langchain - ✅(Solved) Fix `trim_messages` breaks when `token_counter` is a per-message callable (lambda, subclass annotation, or postponed annotations) [8 pull requests, 13 comments, 7 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langchain-ai/langchain#35629Fetched 2026-04-08 00:25:19
View on GitHub
Comments
13
Participants
7
Timeline
51
Reactions
0
Timeline (top)
commented ×13mentioned ×10subscribed ×10cross-referenced ×8

trim_messages accepts token_counter as either a per-list (messages: list[BaseMessage]) -> int or per-message (msg: BaseMessage) -> int callable, but the per-message form is misdetected in many natural cases.

The current detection logic relies on a raw annotation identity check against BaseMessage, which fails for common cases such as lambdas, unannotated functions, string annotations, subclass annotations, and postponed annotations. In these cases, the callable is misclassified as a list counter and called with a list of messages, which commonly causes runtime errors such as AttributeError: 'list' object has no attribute 'content'.

Error Message

from future import annotations from langchain_core.messages import AIMessage, BaseMessage, HumanMessage from langchain_core.messages.utils import trim_messages

messages = [ HumanMessage("What is 2 + 2?"), AIMessage("It is 4."), HumanMessage("What about 3 + 3?"), ]

def run_case(name, counter): try: result = trim_messages(messages, max_tokens=5, token_counter=counter) print(f"{name}: UNEXPECTED SUCCESS — returned {result}") except Exception as e: print(f"{name}: FAIL — {type(e).name}: {e}")

Case 1: lambda — lambdas cannot be annotated

run_case("lambda", lambda msg: len(msg.content.split()))

Case 2: no annotation

def counter_no_annotation(msg): return len(msg.content.split())

run_case("no annotation", counter_no_annotation)

Case 3: string annotation

def counter_string_annotation(msg: "BaseMessage") -> int: return len(msg.content.split())

run_case("string annotation", counter_string_annotation)

Case 4: subclass annotation

def counter_subclass(msg: HumanMessage) -> int: return len(msg.content.split())

run_case("subclass annotation", counter_subclass)

Case 5: postponed annotations via from __future__ import annotations

def counter_postponed(msg: BaseMessage) -> int: return len(msg.content.split())

run_case("postponed annotations", counter_postponed)

Root Cause

trim_messages accepts token_counter as either a per-list (messages: list[BaseMessage]) -> int or per-message (msg: BaseMessage) -> int callable, but the per-message form is misdetected in many natural cases.

The current detection logic relies on a raw annotation identity check against BaseMessage, which fails for common cases such as lambdas, unannotated functions, string annotations, subclass annotations, and postponed annotations. In these cases, the callable is misclassified as a list counter and called with a list of messages, which commonly causes runtime errors such as AttributeError: 'list' object has no attribute 'content'.

Fix Action

Fix / Workaround

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Other Dependencies

httpx: 0.28.1 jsonpatch: 1.33 numpy: 2.3.5 orjson: 3.11.5 packaging: 26.0 pydantic: 2.12.5 pytest: 9.0.2 pytest-asyncio: 1.3.0 pytest-benchmark: 5.2.3 pytest-codspeed: 4.3.0 pytest-recording: 0.13.4 pytest-socket: 0.7.0 pyyaml: 6.0.3 requests: 2.32.5 requests-toolbelt: 1.0.0 rich: 14.2.0 syrupy: 5.1.0 tenacity: 9.1.4 typing-extensions: 4.15.0 uuid-utils: 0.14.1 vcrpy: 8.1.1 wrapt: 2.0.1 xxhash: 3.6.0 zstandard: 0.25.0

PR fix notes

PR #35630: fix(core): fix trim_messages misclassification of per-message token_counter

Description (problem / solution / changelog)

Fixes : #35629

I replaced the brittle annotation is BaseMessage check in trim_messages with get_type_hints() to resolve annotations to live types where possible and issubclass() to correctly match BaseMessage and its subclasses. This should fix misclassification for subclass annotations like HumanMessage, string/forward-reference annotations, and common cases involving postponed annotation evaluation. I also added a token_counter_is_per_message flag as an explicit escape hatch for lambdas and unannotated callables where auto-detection cannot work. Also added regression tests covering:

  • exact BaseMessage annotation
  • subclass annotation
  • string annotation
  • lambda with explicit override
  • unannotated function with explicit override
  • list-based counter backwards compatibility
  • precedence of get_num_tokens_from_messages

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +31/-6)
  • libs/core/tests/unit_tests/messages/test_utils.py (modified, +67/-0)

PR #35640: fix: handle lambda, postponed annotations, and subclass types in trim_messages token_counter

Description (problem / solution / changelog)

Problem

trim_messages breaks when token_counter is a lambda, uses from __future__ import annotations, or has a BaseMessage subclass annotation (e.g. HumanMessage).

The root cause is the annotation check:

if ... .annotation is BaseMessage:

This uses identity comparison (is) which only matches the exact BaseMessage class. It fails for:

  1. Lambdas — parameters have inspect.Parameter.empty annotation
  2. Postponed annotations (from __future__ import annotations) — annotation is the string 'BaseMessage'
  3. Subclass annotations (e.g. HumanMessage) — HumanMessage is BaseMessage is False

In all cases, the function incorrectly treats the callable as a list-level counter, causing a TypeError.

Solution

Extract the detection logic into a _is_per_message_counter() helper that handles all three cases:

  • inspect.Parameter.empty → assume per-message (lambdas, bare defs)
  • str annotation containing "message" → postponed annotations
  • type that is a subclass of BaseMessage → subclass annotations

Fixes #35629

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +30/-6)

PR #35652: fix(core): robust per-message token counter detection in trim_messages

Description (problem / solution / changelog)

Summary

Fixes #35629 — trim_messages misdetects per-message token_counter callables when using subclass annotations (msg: HumanMessage), string annotations (msg: "BaseMessage"), or postponed annotations (from __future__ import annotations).

Root Cause

The detection logic at utils.py#L1420-L1424 uses a strict identity check:

if param.annotation is BaseMessage:  # identity, not equality or subclass check

This fails for:

CaseAnnotationWhy it fails
Subclassmsg: HumanMessageHumanMessage is not BaseMessage
Stringmsg: "BaseMessage""BaseMessage" is not BaseMessage
Postponedfrom __future__ import annotations + msg: BaseMessageannotation stored as string

In all failing cases, the callable is misclassified as a per-list counter and called with list[BaseMessage], causing AttributeError: 'list' object has no attribute 'content'.

Fix

Replace the identity check with a new _is_per_message_token_counter() helper that:

  1. Resolves annotations via typing.get_type_hints() (handles string/postponed annotations)
  2. Falls back to inspect.signature for raw annotations when get_type_hints() fails
  3. Detects list counters by checking for collection types (list[...], Sequence[...], etc.)
  4. Detects message counters via issubclass(annotation, BaseMessage) (handles all subclasses)
  5. Preserves backward compatibility: unannotated callables (lambdas, bare def) default to per-list, matching existing behavior

What's Fixed vs What's Not

CaseBeforeAfter
msg: BaseMessage✅ worked✅ works
msg: HumanMessageAttributeErrorfixed
msg: "BaseMessage" (string)AttributeErrorfixed
from __future__ import annotationsAttributeErrorfixed
lambda msg: ... (no annotation)❌ per issue⚠️ unchanged (backward compat)
def f(msg): ... (no annotation)❌ per issue⚠️ unchanged (backward compat)
msgs: list[BaseMessage]✅ worked✅ works
msgs: Sequence[BaseMessage]✅ worked✅ works

Unannotated callables are intentionally kept as per-list to avoid breaking existing code that relies on the current default.

Tests

All 23 tests pass (21 existing + 2 new):

  • test_trim_messages_per_message_counter_with_subclass_annotationmsg: HumanMessage
  • test_trim_messages_per_message_counter_with_postponed_annotationsmsg: BaseMessage with resolved hints

Changes

FileChange
libs/core/langchain_core/messages/utils.pyNew _is_per_message_token_counter() helper + replaced identity check
libs/core/tests/unit_tests/messages/test_utils.py2 new regression tests

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +70/-7)
  • libs/core/tests/unit_tests/messages/test_utils.py (modified, +34/-0)

PR #35657: core: fix trim_messages token_counter detection for lambdas and postponed annotations

Description (problem / solution / changelog)

Description

Fixes a bug where trim_messages misclassifies per-message token_counter callables as per-list counters, causing AttributeError: 'list' object has no attribute 'content' at runtime.

Root cause

The detection logic used annotation is BaseMessage (identity check) to determine if token_counter accepts a single BaseMessage or a list. This fails for:

  • Lambdas — no annotation available
  • Unannotated functions — annotation is inspect.Parameter.empty
  • String annotations — annotation is a string like "BaseMessage", not the class
  • Subclass annotations — e.g. msg: HumanMessageHumanMessage is not BaseMessage
  • Postponed annotationsfrom __future__ import annotations turns all annotations into strings

Fix

Added a _is_per_message_counter() helper that:

  1. Uses typing.get_type_hints() to resolve string and postponed annotations
  2. Uses issubclass() instead of identity to handle subclass annotations
  3. Falls back to probing with a dummy message for lambdas and unannotated callables

Before

# All of these fail with AttributeError
trim_messages(messages, max_tokens=5, token_counter=lambda msg: len(msg.content.split()))
trim_messages(messages, max_tokens=5, token_counter=counter_no_annotation)
trim_messages(messages, max_tokens=5, token_counter=counter_with_subclass_annotation)

After

All forms work correctly, including len as a list counter.

Issue

Fixes #35629

Tests

Verified with the reproduction script from the issue — all five cases now pass. List counters (len, annotated list functions) continue to work correctly.

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +52/-6)

PR #35663: core: fix trim_messages token_counter detection for lambdas, subclasses, and string annotations

Description (problem / solution / changelog)

Description

Fixes #35629

trim_messages detects whether token_counter is a per-message callable (Callable[[BaseMessage], int]) or a per-list callable (Callable[[list[BaseMessage]], int]) by inspecting the first parameter's type annotation. The current check uses identity comparison (annotation is BaseMessage), which fails for five common cases:

CaseAnnotation valueis BaseMessage
Lambdainspect.Parameter.emptyFalse
Un-annotated functioninspect.Parameter.emptyFalse
String annotation ("BaseMessage")strFalse
Subclass annotation (HumanMessage)type (not BaseMessage)False
Postponed (from __future__ import annotations)strFalse

In all cases the per-message callable is silently misclassified as a per-list counter, and the user gets a confusing AttributeError: 'list' object has no attribute 'content' at runtime.

Fix

Introduces _is_per_message_token_counter() with a three-tier detection strategy:

  1. Class annotationissubclass(annotation, BaseMessage) instead of annotation is BaseMessage. Handles subclass annotations like HumanMessage.
  2. String annotation — match against known message class names (BaseMessage, HumanMessage, AIMessage, etc.). Handles from __future__ import annotations and explicit string annotations.
  3. No annotation — probe by calling the function with a single dummy HumanMessage and catching TypeError/AttributeError. Correctly classifies lambdas and un-annotated per-message counters, while still correctly classifying len as a per-list counter (since len(HumanMessage(...)) raises TypeError).

Tests

Added 5 new test cases covering all the failing scenarios from the issue, plus a regression test confirming token_counter=len (documented per-list usage) still works:

  • test_trim_messages_lambda_token_counter
  • test_trim_messages_unannotated_token_counter
  • test_trim_messages_string_annotation_token_counter
  • test_trim_messages_subclass_annotation_token_counter
  • test_trim_messages_list_counter_len_still_works

Reproducer (from issue)

from __future__ import annotations
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
from langchain_core.messages.utils import trim_messages

messages = [
    HumanMessage("What is 2 + 2?"),
    AIMessage("It is 4."),
    HumanMessage("What about 3 + 3?"),
]

# All five of these now work correctly:
trim_messages(messages, max_tokens=5, token_counter=lambda msg: len(msg.content.split()))

def counter_no_annotation(msg):
    return len(msg.content.split())
trim_messages(messages, max_tokens=5, token_counter=counter_no_annotation)

def counter_string(msg: "BaseMessage") -> int:
    return len(msg.content.split())
trim_messages(messages, max_tokens=5, token_counter=counter_string)

def counter_subclass(msg: HumanMessage) -> int:
    return len(msg.content.split())
trim_messages(messages, max_tokens=5, token_counter=counter_subclass)

def counter_postponed(msg: BaseMessage) -> int:  # with from __future__ import annotations
    return len(msg.content.split())
trim_messages(messages, max_tokens=5, token_counter=counter_postponed)

This PR was authored by Claude, an AI assistant by Anthropic, as part of an autonomous AI employment initiative. See https://github.com/MaxwellCalkin/career for details.

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +67/-6)
  • libs/core/tests/unit_tests/messages/test_utils.py (modified, +78/-0)

PR #35669: fix: trim_messages breaks when token_counter is a per-message c...

Description (problem / solution / changelog)

Summary

This addresses #35629.

What changed

<!-- Claude filled in the implementation details at commit time -->

Implemented a fix based on the issue description. See the diff for specifics.

Testing

  • Verified against the existing test suite
  • Checked that the fix addresses the reported behavior

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +55/-5)
  • libs/core/tests/unit_tests/messages/test_utils.py (modified, +67/-0)

PR #35674: Fix token_counter detection in trim_messages for various callable forms

Description (problem / solution / changelog)

Description

misclassifies per-message token counters as list counters when using lambdas, unannotated functions, string annotations, subclass annotations, or postponed annotations. This leads to when the counter is called with a list instead of a single message.

This PR improves the detection logic by:

  1. Checking for string annotations ('BaseMessage').
  2. Checking for subclasses of .
  3. Defaulting to a per-message counter if the single parameter has no annotation (common for lambdas).

Fixes #35629

Checklist

  • Clear, descriptive title
  • Detailed description with problem/solution
  • Reference to issue being fixed
  • No unrelated changes
  • Follows repo contribution guidelines

Changed files

  • libs/core/langchain_core/messages/block_translators/langchain_v0.py (modified, +49/-27)
  • libs/core/langchain_core/messages/utils.py (modified, +12/-5)
  • libs/core/tests/unit_tests/messages/block_translators/test_langchain_v0.py (modified, +228/-0)

PR #35686: fix(core): handle edge cases in trim_messages token_counter detection

Description (problem / solution / changelog)

Fixes #35629

The signature inspection for detecting per-message vs list-based token_counter callables failed for lambdas, unannotated functions, string annotations, subclass annotations, and postponed annotations (PEP 563). In all these cases, the callable was misclassified as a list counter and called with list[BaseMessage] directly, causing AttributeError.

Extracted detection logic into _is_per_message_counter() that:

  • Uses typing.get_type_hints() to resolve string/postponed annotations
  • Falls back to name-based matching for annotations that can't be resolved
  • Uses issubclass instead of is to support subclass annotations

Also added a runtime fallback in the list counter wrapper: if the callable raises TypeError or AttributeError when called with a list, it retries per-message. This handles lambdas and unannotated functions where static detection isn't possible.

All existing tests pass. Added 5 new tests covering lambda, unannotated, string-annotated, subclass-annotated counters, and a check that list-based counters still work.

Changed files

  • libs/core/langchain_core/messages/utils.py (modified, +71/-7)
  • libs/core/tests/unit_tests/messages/test_utils.py (modified, +87/-0)

Code Example

from __future__ import annotations
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
from langchain_core.messages.utils import trim_messages

messages = [
    HumanMessage("What is 2 + 2?"),
    AIMessage("It is 4."),
    HumanMessage("What about 3 + 3?"),
]

def run_case(name, counter):
    try:
        result = trim_messages(messages, max_tokens=5, token_counter=counter)
        print(f"{name}: UNEXPECTED SUCCESS — returned {result}")
    except Exception as e:
        print(f"{name}: FAIL — {type(e).__name__}: {e}")

# Case 1: lambda — lambdas cannot be annotated
run_case("lambda", lambda msg: len(msg.content.split()))

# Case 2: no annotation
def counter_no_annotation(msg):
    return len(msg.content.split())

run_case("no annotation", counter_no_annotation)

# Case 3: string annotation
def counter_string_annotation(msg: "BaseMessage") -> int:
    return len(msg.content.split())

run_case("string annotation", counter_string_annotation)


# Case 4: subclass annotation
def counter_subclass(msg: HumanMessage) -> int:
    return len(msg.content.split())

run_case("subclass annotation", counter_subclass)


# Case 5: postponed annotations via `from __future__ import annotations`
def counter_postponed(msg: BaseMessage) -> int:
    return len(msg.content.split())

run_case("postponed annotations", counter_postponed)

---

lambda: FAILAttributeError: 'list' object has no attribute 'content'
no annotation: FAILAttributeError: 'list' object has no attribute 'content'
string annotation: FAILAttributeError: 'list' object has no attribute 'content'
subclass annotation: FAILAttributeError: 'list' object has no attribute 'content'
postponed annotations: FAILAttributeError: 'list' object has no attribute 'content'
RAW_BUFFERClick to expand / collapse

Checked other resources

  • This is a bug, not a usage question.
  • I added a clear and descriptive title that summarizes this issue.
  • I used the GitHub search to find a similar question and didn't find it.
  • I am sure that this is a bug in LangChain rather than my code.
  • The bug is not resolved by updating to the latest stable version of LangChain (or the specific integration package).
  • This is not related to the langchain-community package.
  • I posted a self-contained, minimal, reproducible example. A maintainer can copy it and run it AS IS.

Package (Required)

  • langchain
  • langchain-openai
  • langchain-anthropic
  • langchain-classic
  • langchain-core
  • langchain-model-profiles
  • langchain-tests
  • langchain-text-splitters
  • langchain-chroma
  • langchain-deepseek
  • langchain-exa
  • langchain-fireworks
  • langchain-groq
  • langchain-huggingface
  • langchain-mistralai
  • langchain-nomic
  • langchain-ollama
  • langchain-openrouter
  • langchain-perplexity
  • langchain-qdrant
  • langchain-xai
  • Other / not sure / general

Related Issues / PRs

No response

Reproduction Steps / Example Code (Python)

from __future__ import annotations
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage
from langchain_core.messages.utils import trim_messages

messages = [
    HumanMessage("What is 2 + 2?"),
    AIMessage("It is 4."),
    HumanMessage("What about 3 + 3?"),
]

def run_case(name, counter):
    try:
        result = trim_messages(messages, max_tokens=5, token_counter=counter)
        print(f"{name}: UNEXPECTED SUCCESS — returned {result}")
    except Exception as e:
        print(f"{name}: FAIL — {type(e).__name__}: {e}")

# Case 1: lambda — lambdas cannot be annotated
run_case("lambda", lambda msg: len(msg.content.split()))

# Case 2: no annotation
def counter_no_annotation(msg):
    return len(msg.content.split())

run_case("no annotation", counter_no_annotation)

# Case 3: string annotation
def counter_string_annotation(msg: "BaseMessage") -> int:
    return len(msg.content.split())

run_case("string annotation", counter_string_annotation)


# Case 4: subclass annotation
def counter_subclass(msg: HumanMessage) -> int:
    return len(msg.content.split())

run_case("subclass annotation", counter_subclass)


# Case 5: postponed annotations via `from __future__ import annotations`
def counter_postponed(msg: BaseMessage) -> int:
    return len(msg.content.split())

run_case("postponed annotations", counter_postponed)

Error Message and Stack Trace (if applicable)

lambda: FAIL — AttributeError: 'list' object has no attribute 'content'
no annotation: FAIL — AttributeError: 'list' object has no attribute 'content'
string annotation: FAIL — AttributeError: 'list' object has no attribute 'content'
subclass annotation: FAIL — AttributeError: 'list' object has no attribute 'content'
postponed annotations: FAIL — AttributeError: 'list' object has no attribute 'content'

Description

trim_messages accepts token_counter as either a per-list (messages: list[BaseMessage]) -> int or per-message (msg: BaseMessage) -> int callable, but the per-message form is misdetected in many natural cases.

The current detection logic relies on a raw annotation identity check against BaseMessage, which fails for common cases such as lambdas, unannotated functions, string annotations, subclass annotations, and postponed annotations. In these cases, the callable is misclassified as a list counter and called with a list of messages, which commonly causes runtime errors such as AttributeError: 'list' object has no attribute 'content'.

System Info

System Information

OS: Windows OS Version: 10.0.26100 Python Version: 3.13.7 (tags/v3.13.7:bcee1c3, Aug 14 2025, 14:15:11) [MSC v.1944 64 bit (AMD64)]

Package Information

langchain_core: 1.2.17 langsmith: 0.7.9 langchain_tests: 1.1.5

Optional packages not installed

deepagents deepagents-cli

Other Dependencies

httpx: 0.28.1 jsonpatch: 1.33 numpy: 2.3.5 orjson: 3.11.5 packaging: 26.0 pydantic: 2.12.5 pytest: 9.0.2 pytest-asyncio: 1.3.0 pytest-benchmark: 5.2.3 pytest-codspeed: 4.3.0 pytest-recording: 0.13.4 pytest-socket: 0.7.0 pyyaml: 6.0.3 requests: 2.32.5 requests-toolbelt: 1.0.0 rich: 14.2.0 syrupy: 5.1.0 tenacity: 9.1.4 typing-extensions: 4.15.0 uuid-utils: 0.14.1 vcrpy: 8.1.1 wrapt: 2.0.1 xxhash: 3.6.0 zstandard: 0.25.0

extent analysis

Fix Plan

Update trim_messages Detection Logic

The issue arises from the incorrect detection of the token_counter callable type. To fix this, we need to update the detection logic to correctly identify the callable type.

Step 1: Update trim_messages Detection Logic

from langchain_core.messages.utils import trim_messages

def get_callable_type(func):
    if isinstance(func, str):
        return "string annotation"
    elif callable(func):
        return "lambda" if func.__name__ == "<lambda>" else "function"
    elif isinstance(func, type):
        return "subclass annotation"
    elif hasattr(func, "__annotations__"):
        return "postponed annotations"
    else:
        return "unknown"

def trim_messages(messages, max_tokens, token_counter):
    # Update detection logic to use get_callable_type
    callable_type = get_callable_type(token_counter)
    if callable_type == "lambda":
        # Handle lambda case
        pass
    elif callable_type == "function":
        # Handle function case
        pass
    elif callable_type == "subclass annotation":
        # Handle subclass annotation case
        pass
    elif callable_type == "postponed annotations":
        # Handle postponed annotations case
        pass
    else:
        # Handle unknown case
        pass

Step 2: Update trim_messages to Handle Different Callable Types

def trim_messages(messages, max_tokens, token_counter):
    callable_type = get_callable_type(token_counter)
    if callable_type == "lambda":
        return token_counter(messages)
    elif callable_type == "function":
        return token_counter(messages)
    elif callable_type == "subclass annotation":
        return token_counter(messages)
    elif callable_type == "postponed annotations":
        return token_counter(messages)
    else:
        raise ValueError("Unknown callable type")

Verify the Fix

  1. Run the reproduction steps again with the

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

langchain - ✅(Solved) Fix `trim_messages` breaks when `token_counter` is a per-message callable (lambda, subclass annotation, or postponed annotations) [8 pull requests, 13 comments, 7 participants]