Skip to content

[Bug]: Preserve ChatNVIDIA provider tool calls through the LangChain codec round-trip #806

Description

@bbednarski9

Affected area

  • Python binding
  • Middleware or guardrails
  • Framework integrations

Current behavior

The maintained LangChain middleware supplies LangChainCodec to managed execution. Relay decodes and re-encodes requests before the provider callback runs, including when no request interceptor changes the request.

For assistant messages containing tool calls, the round-trip preserves normalized AIMessage.tool_calls but previously rebuilt the message without AIMessage.additional_kwargs["tool_calls"].

ChatNVIDIA serializes prior assistant tool calls from that provider-form field. Without it, the next provider request contains a tool result without the preceding assistant tool call and is rejected. DeepAgents exposes this naturally during a normal model → tool → model loop, but the affected implementation is the shared LangChain codec.

Expected behavior

A no-op LangChain codec round-trip must preserve the provider tool-call representation required by ChatNVIDIA alongside normalized LangChain tool calls.

When an annotated Relay request interceptor changes normalized tool calls, the provider representation must be regenerated from the modified calls rather than retaining stale values.

Reproduction

  1. Create an AIMessage containing equivalent normalized tool_calls and OpenAI-compatible additional_kwargs["tool_calls"].
  2. Serialize it into an LLMRequest, then call LangChainCodec.decode() followed by encode() without edits.
  3. Deserialize the rebuilt message.
  4. Before the fix, rebuilt.tool_calls was populated but rebuilt.additional_kwargs was empty; ChatNVIDIA’s serializer then emitted an assistant message without tool_calls.

Fix and regression coverage

The LangChain codec now preserves the original provider tool-call payload when normalized calls are unchanged, and regenerates a canonical provider payload after an interceptor edits them.

Regression coverage includes:

  • Codec no-op round-trip preservation of normalized and provider-form tool calls.
  • ChatNVIDIA serializer output retaining assistant tool calls and tool-only content: null.
  • Managed LangChain middleware intercept changing tool-call arguments and receiving the matching regenerated provider payload.
  • A real Inference Hub ChatNVIDIA model → tool → model smoke test through Relay middleware.

Environment

  • NeMo Relay main at 2ee3e4d277b3f29437c053887cfacc95ca58fd5b
  • Python 3.12
  • DeepAgents 0.7.4
  • langchain-nvidia-ai-endpoints 1.4.1
  • macOS

Impact

This prevents managed LangChain and DeepAgents agents using ChatNVIDIA from completing multi-turn tool-call runs. Avoiding Relay’s managed LangChain middleware is a temporary workaround, but removes Relay-managed observability, middleware, and pricing for those model calls.

Related: #805 tracks the separate enhancement to model DeepAgents orchestrator and local-subagent topology as nested Relay Agent scopes.

Metadata

Metadata

Assignees

Labels

Bugissue describes bug; PR fixes bug

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions