Skip to content

Commit 2785101

Browse files
committed
Merge branch 'master' into ivana/toxgen/sanic
2 parents a060fbf + 7d7c8ea commit 2785101

File tree

13 files changed

+254
-163
lines changed

13 files changed

+254
-163
lines changed

.github/workflows/test-integrations-cloud.yml

Lines changed: 0 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -22,85 +22,6 @@ env:
2222
CACHED_BUILD_PATHS: |
2323
${{ github.workspace }}/dist-serverless
2424
jobs:
25-
test-cloud-latest:
26-
name: Cloud (latest)
27-
timeout-minutes: 30
28-
runs-on: ${{ matrix.os }}
29-
strategy:
30-
fail-fast: false
31-
matrix:
32-
python-version: ["3.8","3.12","3.13"]
33-
# python3.6 reached EOL and is no longer being supported on
34-
# new versions of hosted runners on Github Actions
35-
# ubuntu-20.04 is the last version that supported python3.6
36-
# see https://github.com/actions/setup-python/issues/544#issuecomment-1332535877
37-
os: [ubuntu-22.04]
38-
services:
39-
docker:
40-
image: docker:dind # Required for Docker network management
41-
options: --privileged # Required for Docker-in-Docker operations
42-
# Use Docker container only for Python 3.6
43-
container: ${{ matrix.python-version == '3.6' && 'python:3.6' || null }}
44-
steps:
45-
- uses: actions/[email protected]
46-
- uses: actions/setup-python@v5
47-
if: ${{ matrix.python-version != '3.6' }}
48-
with:
49-
python-version: ${{ matrix.python-version }}
50-
allow-prereleases: true
51-
- name: Setup Test Env
52-
run: |
53-
pip install "coverage[toml]" tox
54-
- name: Erase coverage
55-
run: |
56-
coverage erase
57-
- name: Test aws_lambda latest
58-
run: |
59-
set -x # print commands that are executed
60-
./scripts/runtox.sh "py${{ matrix.python-version }}-aws_lambda-latest"
61-
- name: Test boto3 latest
62-
run: |
63-
set -x # print commands that are executed
64-
./scripts/runtox.sh "py${{ matrix.python-version }}-boto3-latest"
65-
- name: Test chalice latest
66-
run: |
67-
set -x # print commands that are executed
68-
./scripts/runtox.sh "py${{ matrix.python-version }}-chalice-latest"
69-
- name: Test cloud_resource_context latest
70-
run: |
71-
set -x # print commands that are executed
72-
./scripts/runtox.sh "py${{ matrix.python-version }}-cloud_resource_context-latest"
73-
- name: Test gcp latest
74-
run: |
75-
set -x # print commands that are executed
76-
./scripts/runtox.sh "py${{ matrix.python-version }}-gcp-latest"
77-
- name: Generate coverage XML (Python 3.6)
78-
if: ${{ !cancelled() && matrix.python-version == '3.6' }}
79-
run: |
80-
export COVERAGE_RCFILE=.coveragerc36
81-
coverage combine .coverage-sentry-*
82-
coverage xml --ignore-errors
83-
- name: Generate coverage XML
84-
if: ${{ !cancelled() && matrix.python-version != '3.6' }}
85-
run: |
86-
coverage combine .coverage-sentry-*
87-
coverage xml
88-
- name: Upload coverage to Codecov
89-
if: ${{ !cancelled() }}
90-
uses: codecov/[email protected]
91-
with:
92-
token: ${{ secrets.CODECOV_TOKEN }}
93-
files: coverage.xml
94-
# make sure no plugins alter our coverage reports
95-
plugins: noop
96-
verbose: true
97-
- name: Upload test results to Codecov
98-
if: ${{ !cancelled() }}
99-
uses: codecov/test-results-action@v1
100-
with:
101-
token: ${{ secrets.CODECOV_TOKEN }}
102-
files: .junitxml
103-
verbose: true
10425
test-cloud-pinned:
10526
name: Cloud (pinned)
10627
timeout-minutes: 30

scripts/populate_tox/config.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@
6666
"py3.7": ["importlib-metadata<5.0"],
6767
},
6868
},
69+
"chalice": {
70+
"package": "chalice",
71+
"deps": {
72+
"*": ["pytest-chalice"],
73+
},
74+
},
6975
"clickhouse_driver": {
7076
"package": "clickhouse-driver",
7177
},

scripts/populate_tox/populate_tox.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@
6767
"potel",
6868
# Integrations that can be migrated -- we should eventually remove all
6969
# of these from the IGNORE list
70-
"chalice",
7170
"gcp",
7271
"httpx",
7372
"pure_eval",

scripts/populate_tox/tox.jinja

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,6 @@ envlist =
4242
# AWS Lambda
4343
{py3.8,py3.9,py3.11,py3.13}-aws_lambda
4444

45-
# Chalice
46-
{py3.6,py3.9}-chalice-v{1.16}
47-
{py3.8,py3.12,py3.13}-chalice-latest
48-
4945
# Cloud Resource Context
5046
{py3.6,py3.12,py3.13}-cloud_resource_context
5147

@@ -152,11 +148,6 @@ deps =
152148
aws_lambda: requests
153149
aws_lambda: uvicorn
154150
155-
# Chalice
156-
chalice: pytest-chalice==0.0.5
157-
chalice-v1.16: chalice~=1.16.0
158-
chalice-latest: chalice
159-
160151
# HTTPX
161152
httpx-v0.16: pytest-httpx==0.10.0
162153
httpx-v0.18: pytest-httpx==0.12.0

sentry_sdk/integrations/langchain.py

Lines changed: 105 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@
5151
"presence_penalty": SPANDATA.GEN_AI_REQUEST_PRESENCE_PENALTY,
5252
"temperature": SPANDATA.GEN_AI_REQUEST_TEMPERATURE,
5353
"tool_calls": SPANDATA.GEN_AI_RESPONSE_TOOL_CALLS,
54-
"tools": SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS,
5554
"top_k": SPANDATA.GEN_AI_REQUEST_TOP_K,
5655
"top_p": SPANDATA.GEN_AI_REQUEST_TOP_P,
5756
}
@@ -203,8 +202,12 @@ def on_llm_start(
203202
if key in all_params and all_params[key] is not None:
204203
set_data_normalized(span, attribute, all_params[key], unpack=False)
205204

205+
_set_tools_on_span(span, all_params.get("tools"))
206+
206207
if should_send_default_pii() and self.include_prompts:
207-
set_data_normalized(span, SPANDATA.GEN_AI_REQUEST_MESSAGES, prompts)
208+
set_data_normalized(
209+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, prompts, unpack=False
210+
)
208211

209212
def on_chat_model_start(self, serialized, messages, *, run_id, **kwargs):
210213
# type: (SentryLangchainCallback, Dict[str, Any], List[List[BaseMessage]], UUID, Any) -> Any
@@ -246,14 +249,20 @@ def on_chat_model_start(self, serialized, messages, *, run_id, **kwargs):
246249
if key in all_params and all_params[key] is not None:
247250
set_data_normalized(span, attribute, all_params[key], unpack=False)
248251

252+
_set_tools_on_span(span, all_params.get("tools"))
253+
249254
if should_send_default_pii() and self.include_prompts:
255+
normalized_messages = []
256+
for list_ in messages:
257+
for message in list_:
258+
normalized_messages.append(
259+
self._normalize_langchain_message(message)
260+
)
250261
set_data_normalized(
251262
span,
252263
SPANDATA.GEN_AI_REQUEST_MESSAGES,
253-
[
254-
[self._normalize_langchain_message(x) for x in list_]
255-
for list_ in messages
256-
],
264+
normalized_messages,
265+
unpack=False,
257266
)
258267

259268
def on_chat_model_end(self, response, *, run_id, **kwargs):
@@ -351,9 +360,7 @@ def on_agent_finish(self, finish, *, run_id, **kwargs):
351360

352361
if should_send_default_pii() and self.include_prompts:
353362
set_data_normalized(
354-
span,
355-
SPANDATA.GEN_AI_RESPONSE_TEXT,
356-
finish.return_values.items(),
363+
span, SPANDATA.GEN_AI_RESPONSE_TEXT, finish.return_values.items()
357364
)
358365

359366
self._exit_span(span_data, run_id)
@@ -473,13 +480,11 @@ def _get_token_usage(obj):
473480
if usage is not None:
474481
return usage
475482

476-
# check for usage in the object itself
477483
for name in possible_names:
478484
usage = _get_value(obj, name)
479485
if usage is not None:
480486
return usage
481487

482-
# no usage found anywhere
483488
return None
484489

485490

@@ -531,6 +536,87 @@ def _get_request_data(obj, args, kwargs):
531536
return (agent_name, tools)
532537

533538

539+
def _simplify_langchain_tools(tools):
540+
# type: (Any) -> Optional[List[Any]]
541+
"""Parse and simplify tools into a cleaner format."""
542+
if not tools:
543+
return None
544+
545+
if not isinstance(tools, (list, tuple)):
546+
return None
547+
548+
simplified_tools = []
549+
for tool in tools:
550+
try:
551+
if isinstance(tool, dict):
552+
553+
if "function" in tool and isinstance(tool["function"], dict):
554+
func = tool["function"]
555+
simplified_tool = {
556+
"name": func.get("name"),
557+
"description": func.get("description"),
558+
}
559+
if simplified_tool["name"]:
560+
simplified_tools.append(simplified_tool)
561+
elif "name" in tool:
562+
simplified_tool = {
563+
"name": tool.get("name"),
564+
"description": tool.get("description"),
565+
}
566+
simplified_tools.append(simplified_tool)
567+
else:
568+
name = (
569+
tool.get("name")
570+
or tool.get("tool_name")
571+
or tool.get("function_name")
572+
)
573+
if name:
574+
simplified_tools.append(
575+
{
576+
"name": name,
577+
"description": tool.get("description")
578+
or tool.get("desc"),
579+
}
580+
)
581+
elif hasattr(tool, "name"):
582+
simplified_tool = {
583+
"name": getattr(tool, "name", None),
584+
"description": getattr(tool, "description", None)
585+
or getattr(tool, "desc", None),
586+
}
587+
if simplified_tool["name"]:
588+
simplified_tools.append(simplified_tool)
589+
elif hasattr(tool, "__name__"):
590+
simplified_tools.append(
591+
{
592+
"name": tool.__name__,
593+
"description": getattr(tool, "__doc__", None),
594+
}
595+
)
596+
else:
597+
tool_str = str(tool)
598+
if tool_str and tool_str != "":
599+
simplified_tools.append({"name": tool_str, "description": None})
600+
except Exception:
601+
continue
602+
603+
return simplified_tools if simplified_tools else None
604+
605+
606+
def _set_tools_on_span(span, tools):
607+
# type: (Span, Any) -> None
608+
"""Set available tools data on a span if tools are provided."""
609+
if tools is not None:
610+
simplified_tools = _simplify_langchain_tools(tools)
611+
if simplified_tools:
612+
set_data_normalized(
613+
span,
614+
SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS,
615+
simplified_tools,
616+
unpack=False,
617+
)
618+
619+
534620
def _wrap_configure(f):
535621
# type: (Callable[..., Any]) -> Callable[..., Any]
536622

@@ -601,7 +687,7 @@ def new_configure(
601687
]
602688
elif isinstance(local_callbacks, BaseCallbackHandler):
603689
local_callbacks = [local_callbacks, sentry_handler]
604-
else: # local_callbacks is a list
690+
else:
605691
local_callbacks = [*local_callbacks, sentry_handler]
606692

607693
return f(
@@ -638,10 +724,7 @@ def new_invoke(self, *args, **kwargs):
638724
span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent")
639725
span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, False)
640726

641-
if tools:
642-
set_data_normalized(
643-
span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools, unpack=False
644-
)
727+
_set_tools_on_span(span, tools)
645728

646729
# Run the agent
647730
result = f(self, *args, **kwargs)
@@ -653,11 +736,7 @@ def new_invoke(self, *args, **kwargs):
653736
and integration.include_prompts
654737
):
655738
set_data_normalized(
656-
span,
657-
SPANDATA.GEN_AI_REQUEST_MESSAGES,
658-
[
659-
input,
660-
],
739+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, [input], unpack=False
661740
)
662741

663742
output = result.get("output")
@@ -666,7 +745,7 @@ def new_invoke(self, *args, **kwargs):
666745
and should_send_default_pii()
667746
and integration.include_prompts
668747
):
669-
span.set_data(SPANDATA.GEN_AI_RESPONSE_TEXT, output)
748+
set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, output)
670749

671750
return result
672751

@@ -698,10 +777,7 @@ def new_stream(self, *args, **kwargs):
698777
span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "invoke_agent")
699778
span.set_data(SPANDATA.GEN_AI_RESPONSE_STREAMING, True)
700779

701-
if tools:
702-
set_data_normalized(
703-
span, SPANDATA.GEN_AI_REQUEST_AVAILABLE_TOOLS, tools, unpack=False
704-
)
780+
_set_tools_on_span(span, tools)
705781

706782
input = args[0].get("input") if len(args) >= 1 else None
707783
if (
@@ -710,11 +786,7 @@ def new_stream(self, *args, **kwargs):
710786
and integration.include_prompts
711787
):
712788
set_data_normalized(
713-
span,
714-
SPANDATA.GEN_AI_REQUEST_MESSAGES,
715-
[
716-
input,
717-
],
789+
span, SPANDATA.GEN_AI_REQUEST_MESSAGES, [input], unpack=False
718790
)
719791

720792
# Run the agent
@@ -737,7 +809,7 @@ def new_iterator():
737809
and should_send_default_pii()
738810
and integration.include_prompts
739811
):
740-
span.set_data(SPANDATA.GEN_AI_RESPONSE_TEXT, output)
812+
set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, output)
741813

742814
span.__exit__(None, None, None)
743815

@@ -756,7 +828,7 @@ async def new_iterator_async():
756828
and should_send_default_pii()
757829
and integration.include_prompts
758830
):
759-
span.set_data(SPANDATA.GEN_AI_RESPONSE_TEXT, output)
831+
set_data_normalized(span, SPANDATA.GEN_AI_RESPONSE_TEXT, output)
760832

761833
span.__exit__(None, None, None)
762834

0 commit comments

Comments
 (0)