-
-
Notifications
You must be signed in to change notification settings - Fork 4.5k
feat(agents): Show truncated messages info #102947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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, | ||
|
|
@@ -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
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. just wondering why
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
|
|
||
| let promptMessages = shouldRender | ||
| ? getTraceNodeAttribute('gen_ai.request.messages', node, event, attributes) | ||
|
|
@@ -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} | ||
|
|
@@ -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); | ||
|
|
@@ -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}> | ||
|
|
@@ -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"> | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.