Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion sentry_sdk/integrations/langchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@


try:
from langchain.agents import AgentExecutor
from langchain_core.agents import AgentFinish
from langchain_core.callbacks import (
BaseCallbackHandler,
Expand All @@ -44,6 +43,11 @@
raise DidNotEnable("langchain not installed")


try:
from langchain.agents import AgentExecutor
except ImportError:
AgentExecutor = None

DATA_FIELDS = {
"frequency_penalty": SPANDATA.GEN_AI_REQUEST_FREQUENCY_PENALTY,
"function_call": SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS,
Expand Down
78 changes: 77 additions & 1 deletion tests/integrations/langchain/test_langchain.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from typing import List, Optional, Any, Iterator
from unittest import mock
from unittest.mock import Mock
from unittest.mock import Mock, patch

import pytest

Expand Down Expand Up @@ -662,3 +662,79 @@ def test_tools_integration_in_spans(sentry_init, capture_events):

# Ensure we found at least one span with tools data
assert tools_found, "No spans found with tools data"


def test_langchain_integration_with_langchain_core_only(sentry_init, capture_events):
"""Test that the langchain integration works when langchain.agents.AgentExecutor
is not available or langchain is not installed, but langchain-core is.
"""

from langchain_core.outputs import LLMResult, Generation

with patch("sentry_sdk.integrations.langchain.AgentExecutor", None):
from sentry_sdk.integrations.langchain import (
LangchainIntegration,
SentryLangchainCallback,
)

sentry_init(
integrations=[LangchainIntegration(include_prompts=True)],
traces_sample_rate=1.0,
send_default_pii=True,
)
events = capture_events()

try:
LangchainIntegration.setup_once()
except Exception as e:
pytest.fail(f"setup_once() failed when AgentExecutor is None: {e}")

callback = SentryLangchainCallback(max_span_map_size=100, include_prompts=True)

run_id = "12345678-1234-1234-1234-123456789012"
serialized = {"_type": "openai-chat", "model_name": "gpt-3.5-turbo"}
prompts = ["What is the capital of France?"]

with start_transaction():
callback.on_llm_start(
serialized=serialized,
prompts=prompts,
run_id=run_id,
invocation_params={
"temperature": 0.7,
"max_tokens": 100,
"model": "gpt-3.5-turbo",
},
)

response = LLMResult(
generations=[[Generation(text="The capital of France is Paris.")]],
llm_output={
"token_usage": {
"total_tokens": 25,
"prompt_tokens": 10,
"completion_tokens": 15,
}
},
)
callback.on_llm_end(response=response, run_id=run_id)

assert len(events) > 0
tx = events[0]
assert tx["type"] == "transaction"

llm_spans = [
span for span in tx.get("spans", []) if span.get("op") == "gen_ai.pipeline"
]
assert len(llm_spans) > 0

llm_span = llm_spans[0]
assert llm_span["description"] == "Langchain LLM call"
assert llm_span["data"]["gen_ai.request.model"] == "gpt-3.5-turbo"
assert (
llm_span["data"]["gen_ai.response.text"]
== "The capital of France is Paris."
)
assert llm_span["data"]["gen_ai.usage.total_tokens"] == 25
assert llm_span["data"]["gen_ai.usage.input_tokens"] == 10
assert llm_span["data"]["gen_ai.usage.output_tokens"] == 15
Loading