Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

@patcher9
Copy link
Contributor

@patcher9 patcher9 commented Nov 12, 2025

Important

  1. We strictly follow a issue-first approach, please first open an issue relating to this Pull Request.
  2. PR name follows conventional commit format: feat: ... or fix: ....

Issue number: resolves #933

Change description:

Checklist

If your change doesn't seem to apply, please leave them unchecked.

  • PR name follows conventional commit format: feat: ... or fix: ....
  • I have reviewed the contributing guidelines
  • Have you checked to ensure there aren't other open Pull Requests for the same update/change?
  • I have performed a self-review of this change
  • Changes have been tested
  • Changes are documented

Acknowledgment

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.

Summary by Sourcery

Add support for LangChain astream streaming by tracking individual tokens via on_llm_new_token, assembling full streamed responses in on_llm_end, and capturing usage metrics. Enhance error handling by cleaning up streaming buffers and classifying both LLM and chain errors with detailed attributes. Bump Python SDK version to 1.36.1.

New Features:

  • Introduce on_llm_new_token callback to accumulate tokens during streaming operations.
  • Assemble and record complete streamed responses and token usage in on_llm_end.
  • Add on_chain_error callback to capture and annotate chain errors.

Enhancements:

  • Clean up streaming token buffers on LLM and chain errors.
  • Enhance error classification and attach framework error attributes to spans.

Build:

  • Bump Python SDK version from 1.36.0 to 1.36.1.

@patcher9 patcher9 requested a review from a team as a code owner November 12, 2025 07:06
@sourcery-ai
Copy link
Contributor

sourcery-ai bot commented Nov 12, 2025

Reviewer's Guide

This PR implements support for langchain's astream streaming by introducing a token accumulation mechanism and flushing complete responses into spans, adds a new chain-level error callback with enhanced error classification and cleanup logic, and bumps the SDK version to 1.36.1.

Sequence diagram for streaming token accumulation and response flushing in LangChain astream

sequenceDiagram
    participant LangChain
    participant CallbackHandler
    participant Span
    LangChain->>CallbackHandler: on_llm_new_token(token, run_id)
    CallbackHandler->>CallbackHandler: Accumulate token in streaming_chunks[run_id]
    LangChain->>CallbackHandler: on_llm_end(response, run_id)
    CallbackHandler->>CallbackHandler: Join tokens in streaming_chunks[run_id]
    CallbackHandler->>Span: set_attribute(GEN_AI_CONTENT_COMPLETION, complete_response)
    CallbackHandler->>Span: set_attribute(GEN_AI_USAGE_OUTPUT_TOKENS, output_tokens)
    CallbackHandler->>CallbackHandler: Clean up streaming_chunks[run_id]
    CallbackHandler->>Span: _process_llm_response(span, response, run_id)
Loading

Sequence diagram for chain-level error handling and cleanup

sequenceDiagram
    participant LangChain
    participant CallbackHandler
    participant Span
    LangChain->>CallbackHandler: on_chain_error(error, run_id)
    CallbackHandler->>CallbackHandler: Clean up streaming_chunks[run_id]
    CallbackHandler->>Span: set_attribute(GEN_AI_FRAMEWORK_ERROR_CLASS, error_class)
    CallbackHandler->>Span: set_attribute(GEN_AI_FRAMEWORK_ERROR_TYPE, type(error).__name__)
    CallbackHandler->>Span: set_attribute(GEN_AI_FRAMEWORK_ERROR_MESSAGE, str(error))
    CallbackHandler->>Span: set_status(StatusCode.ERROR, str(error))
    CallbackHandler->>Span: record_exception(error)
    CallbackHandler->>CallbackHandler: _end_span(run_id)
Loading

Class diagram for updated CallbackHandler streaming and error handling

classDiagram
    class CallbackHandler {
        spans: Dict[UUID, SpanHolder]
        streaming_chunks: Dict[UUID, List[str]]
        session_name: str
        tags_enabled: bool
        events_enabled: bool
        on_llm_new_token(token: str, chunk: Optional[Any], run_id: UUID, parent_run_id: Optional[UUID], **kwargs)
        on_llm_end(response: Any, run_id: UUID, parent_run_id: Optional[UUID], **kwargs)
        on_llm_error(error: Exception, run_id: UUID, parent_run_id: Optional[UUID], **kwargs)
        on_chain_error(error: Exception, run_id: UUID, parent_run_id: Optional[UUID], **kwargs)
    }
    CallbackHandler "1" o-- "*" SpanHolder
    CallbackHandler "1" o-- "*" streaming_chunks
Loading

File-Level Changes

Change Details Files
Add streaming support with token accumulation and flush into spans
  • Initialize streaming_chunks dict in constructor
  • Implement on_llm_new_token to accumulate tokens
  • Enhance on_llm_end to assemble chunks, set content & token count, and clear buffer
  • Clean up streaming_chunks in on_llm_error
sdk/python/src/openlit/instrumentation/langchain/callback_handler.py
Introduce chain-level error callback with enhanced classification
  • Add on_chain_error to classify and record chain errors
  • Clean up streaming_chunks in on_chain_error
  • Set span error attributes, status, record exception, and end span
sdk/python/src/openlit/instrumentation/langchain/callback_handler.py
Bump SDK version to 1.36.1
  • Update version in pyproject.toml
sdk/python/pyproject.toml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey there - I've reviewed your changes - here's some feedback:

  • You’re duplicating streaming_chunks cleanup in on_llm_end, on_llm_error, and on_chain_error—extract that into a shared helper to reduce repetition.
  • If callbacks can run concurrently, unsynchronized access to streaming_chunks may race—consider guard (e.g. a lock) or a thread-safe structure.
  • Accumulating all tokens unbounded could exhaust memory for long streams—think about capping buffer size or flushing partial results periodically.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- You’re duplicating streaming_chunks cleanup in on_llm_end, on_llm_error, and on_chain_error—extract that into a shared helper to reduce repetition.
- If callbacks can run concurrently, unsynchronized access to streaming_chunks may race—consider guard (e.g. a lock) or a thread-safe structure.
- Accumulating all tokens unbounded could exhaust memory for long streams—think about capping buffer size or flushing partial results periodically.

## Individual Comments

### Comment 1
<location> `sdk/python/src/openlit/instrumentation/langchain/callback_handler.py:663-665` </location>
<code_context>
+
+            self._end_span(run_id)
+
+        except Exception:
+            # Graceful error handling
+            pass
+
     def on_chat_model_start(
</code_context>

<issue_to_address>
**suggestion (bug_risk):** Swallowing all exceptions may obscure underlying issues.

Instead of passing silently, log or record the exception to aid diagnostics unless you have a specific reason to suppress all errors.

```suggestion
        except Exception as exc:
            # Log the exception for diagnostics
            import logging
            logging.exception("Exception occurred while ending span for run_id %s", run_id)
```
</issue_to_address>

### Comment 2
<location> `sdk/python/src/openlit/instrumentation/langchain/callback_handler.py:801` </location>
<code_context>
+                self.streaming_chunks[run_id] = []
+
+            # Accumulate the token
+            if token:
+                self.streaming_chunks[run_id].append(token)
+
</code_context>

<issue_to_address>
**question:** Empty string tokens are ignored; clarify if this is intentional.

If empty tokens are valid from the source, skipping them could cause data loss. Please confirm this is the intended behavior.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@patcher9 patcher9 merged commit 3367072 into main Nov 12, 2025
13 of 15 checks passed
@patcher9 patcher9 deleted the langchain-fix branch November 12, 2025 07:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: Not working with langchain astream

2 participants