Skip to content

fix(core): handle float type in merge_dicts, merge_obj, and _dict_int_op#36053

Closed
nevanwang (nevanwang) wants to merge 2 commits intolangchain-ai:masterfrom
nevanwang:fix/core-merge-dicts-float-support
Closed

fix(core): handle float type in merge_dicts, merge_obj, and _dict_int_op#36053
nevanwang (nevanwang) wants to merge 2 commits intolangchain-ai:masterfrom
nevanwang:fix/core-merge-dicts-float-support

Conversation

@nevanwang
Copy link

Description

merge_dicts() and merge_obj() in libs/core/langchain_core/utils/_merge.py, as well as _dict_int_op() in libs/core/langchain_core/utils/usage.py, handle int types but not float. When these functions encounter float values, they fall through to error branches and raise TypeError or ValueError.

from langchain_core.utils._merge import merge_dicts

merge_dicts({"score": 0.5}, {"score": 0.3})  # ❌ TypeError

This affects streaming scenarios where LLM providers return float fields in generation_info, additional_kwargs, or UsageMetadata (e.g., logprob, score, safety scores, cost fields, etc.). During chunk aggregation via ChatGenerationChunk.__add__()merge_dicts(), or UsageMetadata.__add__()_dict_int_op(), these float fields cause the stream to crash.

Changes

libs/core/langchain_core/utils/_merge.py

  • merge_dicts(): Changed isinstance(merged[right_k], int) to isinstance(merged[right_k], (int, float)) so that float values are summed (or preserved for special keys like index, created, timestamp) instead of raising TypeError.
  • merge_obj(): Added isinstance(left, (int, float)) check after the equality check, so unequal numeric values are summed instead of raising ValueError. The ordering is important — equal values (including True == True, 42 == 42, 3.14 == 3.14) are handled by the equality branch first, and only unequal numeric values reach the addition branch.

libs/core/langchain_core/utils/usage.py

  • _dict_int_op(): Changed isinstance(..., int) to isinstance(..., (int, float)) so that float values in UsageMetadata (e.g., cost fields, timing data) are correctly handled during aggregation.
  • Updated type annotations (Callable[[int, int], int]Callable[[float, float], float]), docstrings, and error messages to reflect float support.

libs/core/tests/unit_tests/utils/test_utils.py

  • Added regression tests for float values in test_merge_dicts (summing, preserved special keys like index/created/timestamp).
  • Added regression tests for numeric addition in test_merge_obj (int and float).
  • Updated test_merge_obj_unmergeable_values to use set instead of different integers (since different integers are now correctly summed).

libs/core/tests/unit_tests/utils/test_usage.py

  • Added test_dict_int_op_float_add — tests pure float addition.
  • Added test_dict_int_op_mixed_int_float — tests mixed int/float addition.
  • Added test_dict_int_op_nested_float — tests nested dictionaries with float values.
  • Updated error message assertion to match new "int, and float" wording.

Design Note

As Jairooh correctly pointed out, isinstance(x, int) returns True for bool in Python. In merge_obj(), this is safely handled because bool equality (True == True) is caught by the left == right branch before reaching the numeric addition branch. For merge_dicts(), the same ordering applies. This is a key design choice — the competing PR #36048 placed the numeric check before the equality check, causing 42 + 42 = 84 and True + True = 2 failures.

Regarding floating-point precision concerns: the current approach mirrors the existing int addition semantics. For use cases where last-value or max semantics are preferred over summation, that would be a separate feature/configuration beyond this bug fix.

Issue

Fixes #36011
Fixes #36015

Related

- merge_dicts(): expand isinstance check from int to (int, float)
- merge_obj(): add numeric addition for int/float after equality check
- _dict_int_op(): expand isinstance check to support float values
- Update docstrings and error messages to reflect float support
- Add regression tests for float values in all three functions

Fixes langchain-ai#36011
Fixes langchain-ai#36015
@github-actions github-actions bot added core `langchain-core` package issues & PRs fix For PRs that implement a fix size: S 50-199 LOC labels Mar 18, 2026
@codspeed-hq
Copy link

codspeed-hq bot commented Mar 18, 2026

Merging this PR will improve performance by 31.71%

⚠️ Unknown Walltime execution environment detected

Using the Walltime instrument on standard Hosted Runners will lead to inconsistent data.

For the most accurate results, we recommend using CodSpeed Macro Runners: bare-metal machines fine-tuned for performance measurement consistency.

⚡ 13 improved benchmarks
⏩ 23 skipped benchmarks1

Performance Changes

Mode Benchmark BASE HEAD Efficiency
WallTime test_import_time[LangChainTracer] 480.7 ms 387.4 ms +24.08%
WallTime test_import_time[InMemoryRateLimiter] 181.2 ms 141.8 ms +27.77%
WallTime test_import_time[HumanMessage] 277.3 ms 214.2 ms +29.41%
WallTime test_async_callbacks_in_sync 25.2 ms 19.7 ms +28.06%
WallTime test_import_time[Runnable] 522.8 ms 403.1 ms +29.7%
WallTime test_import_time[ChatPromptTemplate] 677.3 ms 531 ms +27.56%
WallTime test_import_time[tool] 582.2 ms 459.2 ms +26.78%
WallTime test_import_time[PydanticOutputParser] 565.5 ms 463.1 ms +22.11%
WallTime test_import_time[Document] 200.2 ms 154.8 ms +29.32%
WallTime test_import_time[InMemoryVectorStore] 643.7 ms 509.7 ms +26.28%
WallTime test_import_time[RunnableLambda] 522.3 ms 402 ms +29.92%
WallTime test_import_time[CallbackManager] 336.1 ms 258.3 ms +30.11%
WallTime test_import_time[BaseChatModel] 573.4 ms 435.4 ms +31.71%

Comparing nevanwang:fix/core-merge-dicts-float-support (3d20b09) with master (07fa576)2

Open in CodSpeed

Footnotes

  1. 23 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

  2. No successful run was found on master (a81203b) during the generation of this report, so 07fa576 was used instead as the comparison base. There might be some changes unrelated to this pull request in this report.

@github-actions
Copy link

This PR has been automatically closed because you are not assigned to the linked issue.

External contributors must be assigned to an issue before opening a PR for it. Please:

  1. Comment on the linked issue to request assignment from a maintainer
  2. Once assigned, edit your PR description and the PR will be reopened automatically

@github-actions github-actions bot closed this Mar 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core `langchain-core` package issues & PRs external fix For PRs that implement a fix missing-issue-link new-contributor size: S 50-199 LOC

Projects

None yet

1 participant