X Tutup
Skip to content

feat(cohere): upgrade integration from ai to gen_ai#5597

Open
shellmayr wants to merge 8 commits intomasterfrom
shellmayr/cohere/1-genai-migration
Open

feat(cohere): upgrade integration from ai to gen_ai#5597
shellmayr wants to merge 8 commits intomasterfrom
shellmayr/cohere/1-genai-migration

Conversation

@shellmayr
Copy link
Member

  • Move everything in cohere from ai.* attributes to gen_ai.* attributes
  • Purposely does not include the changes for v2 after alignment with @alexander-alderman-webb

Closes TET-2023

@linear-code
Copy link

linear-code bot commented Mar 6, 2026

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Semver Impact of This PR

🟡 Minor (new features)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


New Features ✨

  • (cohere) Upgrade integration from ai to gen_ai by shellmayr in #5597

Bug Fixes 🐛

  • (celery) Propagate user-set headers by sentrivana in #5581
  • (utils) Avoid double serialization of strings in safe_serialize by ericapisani in #5587

Documentation 📚

  • (openai-agents) Remove inapplicable comment by alexander-alderman-webb in #5495
  • Add AGENTS.md by sentrivana in #5579
  • Add set_attribute example to changelog by sentrivana in #5578

Internal Changes 🔧

Openai Agents

  • Set streaming header when library uses with_streaming_response() by alexander-alderman-webb in #5583
  • Replace mocks with httpx for streamed responses by alexander-alderman-webb in #5580
  • Replace mocks with httpx in non-MCP tool tests by alexander-alderman-webb in #5602
  • Replace mocks with httpx in MCP tool tests by alexander-alderman-webb in #5605
  • Replace mocks with httpx in handoff tests by alexander-alderman-webb in #5604
  • Replace mocks with httpx in API error test by alexander-alderman-webb in #5601
  • Replace mocks with httpx in non-error single-response tests by alexander-alderman-webb in #5600
  • Remove test for unreachable state by alexander-alderman-webb in #5584
  • Expect namespace tool field for new openai versions by alexander-alderman-webb in #5599

Other

  • Do not run actions on potel-base by sentrivana in #5614

🤖 This preview updates automatically when you update the PR.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Codecov Results 📊

5 passed | Total: 5 | Pass Rate: 100% | Execution Time: 1.12s

All tests are passing successfully.

❌ Patch coverage is 9.09%. Project has 15703 uncovered lines.

Files with missing lines (2)
File Patch % Lines
utils.py 16.08% ⚠️ 214 Missing
cohere.py 11.85% ⚠️ 119 Missing

Generated by Codecov Action

@shellmayr shellmayr marked this pull request as ready for review March 9, 2026 08:56
@shellmayr shellmayr requested a review from a team as a code owner March 9, 2026 08:56
from sentry_sdk.ai.monitoring import record_token_usage
from sentry_sdk.consts import SPANDATA
from sentry_sdk.ai.utils import set_data_normalized
from sentry_sdk.consts import OP, SPANDATA
Copy link

Choose a reason for hiding this comment

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

Unused consts import after direct OP import added

Low Severity

The from sentry_sdk import consts import is now dead code. The old code accessed consts.OP.COHERE_CHAT_COMPLETIONS_CREATE and consts.OP.COHERE_EMBEDDINGS_CREATE, but those were replaced with OP.GEN_AI_CHAT and OP.GEN_AI_EMBEDDINGS using the new direct import from sentry_sdk.consts import OP, SPANDATA on line 6. There are no remaining consts. references in the file.

Fix in Cursor Fix in Web

if integration is None:
return f(*args, **kwargs)

model = kwargs.get("model", "")
Copy link
Contributor

Choose a reason for hiding this comment

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

the documentation currently does not specify the AI Client Span's description when there is no request model.

I'll bring this up in the sync, update the devdocs, and ping you once there's a concrete spec.

https://develop.sentry.dev/sdk/telemetry/traces/modules/ai-agents/

Comment on lines +161 to +173
messages = []
for x in kwargs.get("chat_history", []):
role = getattr(x, "role", "").lower()
if role == "chatbot":
role = "assistant"
messages.append(
{
"role": role,
"content": getattr(x, "message", ""),
}
)
messages.append({"role": "user", "content": message})
messages = normalize_message_roles(messages)
Copy link
Contributor

Choose a reason for hiding this comment

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

Either you should explicitly convert message roles in cohere inputs or rely on solely on normalize_message_roles().

Also, we are developing against a library with specific schemas and types.
Heuristics like normalize_message_roles should be avoided as they effectively add dead code.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Autofix Details

Bugbot Autofix prepared fixes for both issues found in the latest run.

  • ✅ Fixed: System/operation attributes missing on error spans
    • Moved GEN_AI_SYSTEM and GEN_AI_OPERATION_NAME set_data calls before the try block so they are always present on spans, even when exceptions occur.
  • ✅ Fixed: Cohere-specific role added to global mapping utility
    • Removed 'chatbot' from the global GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING and handled the chatbot->assistant role conversion locally in the Cohere integration.

Create PR

Or push these changes by commenting:

@cursor push 5089f11b7f
Preview (5089f11b7f)
diff --git a/sentry_sdk/ai/utils.py b/sentry_sdk/ai/utils.py
--- a/sentry_sdk/ai/utils.py
+++ b/sentry_sdk/ai/utils.py
@@ -30,7 +30,7 @@
 GEN_AI_MESSAGE_ROLE_REVERSE_MAPPING = {
     GEN_AI_ALLOWED_MESSAGE_ROLES.SYSTEM: ["system"],
     GEN_AI_ALLOWED_MESSAGE_ROLES.USER: ["user", "human"],
-    GEN_AI_ALLOWED_MESSAGE_ROLES.ASSISTANT: ["assistant", "ai", "chatbot"],
+    GEN_AI_ALLOWED_MESSAGE_ROLES.ASSISTANT: ["assistant", "ai"],
     GEN_AI_ALLOWED_MESSAGE_ROLES.TOOL: ["tool", "tool_call"],
 }
 

diff --git a/sentry_sdk/integrations/cohere.py b/sentry_sdk/integrations/cohere.py
--- a/sentry_sdk/integrations/cohere.py
+++ b/sentry_sdk/integrations/cohere.py
@@ -141,6 +141,8 @@
             origin=CohereIntegration.origin,
         )
         span.__enter__()
+        span.set_data(SPANDATA.GEN_AI_SYSTEM, "cohere")
+        span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat")
         try:
             res = f(*args, **kwargs)
         except Exception as e:
@@ -151,15 +153,16 @@
             reraise(*exc_info)
 
         with capture_internal_exceptions():
-            span.set_data(SPANDATA.GEN_AI_SYSTEM, "cohere")
-            span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat")
 
             if should_send_default_pii() and integration.include_prompts:
                 messages = []
                 for x in kwargs.get("chat_history", []):
+                    role = getattr(x, "role", "")
+                    if role == "chatbot":
+                        role = "assistant"
                     messages.append(
                         {
-                            "role": getattr(x, "role", ""),
+                            "role": role,
                             "content": getattr(x, "message", ""),
                         }
                     )
This Bugbot Autofix run was free. To enable autofix for future PRs, go to the Cursor dashboard.


with capture_internal_exceptions():
span.set_data(SPANDATA.GEN_AI_SYSTEM, "cohere")
span.set_data(SPANDATA.GEN_AI_OPERATION_NAME, "chat")
Copy link

Choose a reason for hiding this comment

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

System/operation attributes missing on error spans

Medium Severity

GEN_AI_SYSTEM and GEN_AI_OPERATION_NAME are set after the try/except block inside capture_internal_exceptions(). When f(*args, **kwargs) throws, the except block exits the span and reraises, so these attributes are never set on error spans. Other integrations like Google GenAI set these attributes before the try block, ensuring they appear even on failed spans. This means Cohere error spans won't be identifiable by system or operation name.

Fix in Cursor Fix in Web

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

"is_search_required": SPANDATA.AI_SEARCH_REQUIRED,
"finish_reason": SPANDATA.AI_FINISH_REASON,
"generation_id": SPANDATA.GEN_AI_RESPONSE_ID,
"finish_reason": SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS,
Copy link

Choose a reason for hiding this comment

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

Single finish_reason stored for plural finish_reasons attribute

Medium Severity

Cohere's finish_reason response attribute is a single string (e.g. "COMPLETE"), but it's mapped to SPANDATA.GEN_AI_RESPONSE_FINISH_REASONS (plural), which semantically expects a list. The Google GenAI integration consistently stores this attribute as a list of strings via extract_finish_reasons(). The value needs to be wrapped in a list (e.g., [getattr(res, attr)]) to match the plural attribute's expected schema and maintain cross-integration consistency.

Additional Locations (1)

Fix in Cursor Fix in Web

origin=CohereIntegration.origin,
) as span:
set_data_normalized(span, SPANDATA.GEN_AI_SYSTEM, "cohere")
set_data_normalized(span, SPANDATA.GEN_AI_OPERATION_NAME, "embeddings")
Copy link

Choose a reason for hiding this comment

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

Embed uses set_data_normalized instead of span.set_data

Low Severity

The embed function uses set_data_normalized for GEN_AI_SYSTEM and GEN_AI_OPERATION_NAME, while the chat function at lines 162-163 uses span.set_data directly for the same attributes with identical simple string values. The PR reviewer explicitly suggested using span.set_data here, and the chat function was updated accordingly, but the embed function wasn't.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

X Tutup