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
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ import {Fragment, useEffect, useEffectEvent, useLayoutEffect, useState} from 're
import styled from '@emotion/styled';
import * as Sentry from '@sentry/react';

import {Alert} from '@sentry/scraps/alert';
import {Container} from '@sentry/scraps/layout';
import {ExternalLink} from '@sentry/scraps/link';

import {Button} from 'sentry/components/core/button';
import {t} from 'sentry/locale';
import {t, tct, tn} from 'sentry/locale';
import {space} from 'sentry/styles/space';
import type {EventTransaction} from 'sentry/types/event';
import {defined} from 'sentry/utils';
import usePrevious from 'sentry/utils/usePrevious';
import type {TraceItemResponseAttribute} from 'sentry/views/explore/hooks/useTraceItemDetails';
import type {
TraceItemDetailsMeta,
TraceItemResponseAttribute,
} from 'sentry/views/explore/hooks/useTraceItemDetails';
import {
getIsAiNode,
getTraceNodeAttribute,
Expand Down Expand Up @@ -170,13 +177,17 @@ function useInvalidRoleDetection(roles: string[]) {
export function AIInputSection({
node,
attributes,
attributesMeta,
event,
}: {
node: TraceTreeNode<TraceTree.EAPSpan | TraceTree.Span | TraceTree.Transaction>;
attributes?: TraceItemResponseAttribute[];
attributesMeta?: TraceItemDetailsMeta;
event?: EventTransaction;
}) {
const shouldRender = getIsAiNode(node) && hasAIInputAttribute(node, attributes, event);
const messagesMeta = attributesMeta?.['gen_ai.request.messages']?.meta as any;
const originalMessagesLength: number | undefined = messagesMeta?.['']?.len;
Comment on lines +189 to +190
Copy link
Collaborator

Choose a reason for hiding this comment

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

just wondering why as any is necessary? Can’t we make the types conform to what we’re trying to do at runtime?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I am still investigate the current usage to see how to fix the types here. In e.g. logs the value key is used. This could be an SDK / BE or FE bug.


let promptMessages = shouldRender
? getTraceNodeAttribute('gen_ai.request.messages', node, event, attributes)
Expand Down Expand Up @@ -227,7 +238,12 @@ export function AIInputSection({
{messages}
</TraceDrawerComponents.MultilineText>
) : null}
{Array.isArray(messages) ? <MessagesArrayRenderer messages={messages} /> : null}
{Array.isArray(messages) ? (
<MessagesArrayRenderer
messages={messages}
originalLength={originalMessagesLength}
/>
) : null}
{toolArgs ? (
<TraceDrawerComponents.MultilineJSON value={toolArgs} maxDefaultDepth={1} />
) : null}
Expand All @@ -248,8 +264,16 @@ const MAX_MESSAGES_TO_SHOW = MAX_MESSAGES_AT_START + MAX_MESSAGES_AT_END;
* As the whole message history takes up too much space we only show the first two (as those often contain the system and initial user prompt)
* and the last messages with the option to expand
*/
function MessagesArrayRenderer({messages}: {messages: AIMessage[]}) {
function MessagesArrayRenderer({
messages,
originalLength,
}: {
messages: AIMessage[];
originalLength?: number;
}) {
const [isExpanded, setIsExpanded] = useState(messages.length <= MAX_MESSAGES_TO_SHOW);
const truncatedMessages = originalLength ? originalLength - messages.length : 0;
const isTruncated = truncatedMessages > 0;

// Reset the expanded state when the messages length changes
const previousMessagesLength = usePrevious(messages.length);
Expand All @@ -259,6 +283,22 @@ function MessagesArrayRenderer({messages}: {messages: AIMessage[]}) {
}
}, [messages.length, previousMessagesLength]);

const truncationAlert = isTruncated ? (
<Container paddingBottom="lg">
<Alert type="muted">
{tct(
'Due to [link:size limitations], the oldest [count] got dropped from the history.',
{
count: tn('message', '%s messages', truncatedMessages),
link: (
<ExternalLink href="https://develop.sentry.dev/sdk/expected-features/data-handling/#variable-size" />
),
}
)}
</Alert>
</Container>
) : null;

const renderMessage = (message: AIMessage, index: number) => {
return (
<Fragment key={index}>
Expand All @@ -278,11 +318,17 @@ function MessagesArrayRenderer({messages}: {messages: AIMessage[]}) {
};

if (isExpanded) {
return messages.map(renderMessage);
return (
<Fragment>
{truncationAlert}
{messages.map(renderMessage)}
</Fragment>
);
}

return (
<Fragment>
{truncationAlert}
{messages.slice(0, MAX_MESSAGES_AT_START).map(renderMessage)}
<ButtonDivider>
<Button onClick={() => setIsExpanded(true)} size="xs">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,7 @@ function EAPSpanNodeDetailsContent({
traceItemData: TraceItemDetailsResponse;
}) {
const attributes = traceItemData.attributes;
const attributesMeta = traceItemData.meta;
const links = traceItemData.links;
const isTransaction = isEAPTransactionNode(node) && !!eventTransaction;

Expand Down Expand Up @@ -487,7 +488,11 @@ function EAPSpanNodeDetailsContent({
hideNodeActions={hideNodeActions}
/>
<AIIOAlert node={node} attributes={attributes} />
<AIInputSection node={node} attributes={attributes} />
<AIInputSection
node={node}
attributes={attributes}
attributesMeta={attributesMeta}
/>
<AIOutputSection node={node} attributes={attributes} />
<MCPInputSection node={node} attributes={attributes} />
<MCPOutputSection node={node} attributes={attributes} />
Expand Down
Loading