Skip to content
Draft
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
40 changes: 15 additions & 25 deletions static/app/views/insights/agents/components/aiSpanList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,7 @@ import {
} from 'sentry/views/insights/agents/utils/query';
import type {AITraceSpanNode} from 'sentry/views/insights/agents/utils/types';
import {SpanFields} from 'sentry/views/insights/types';
import {
isEAPSpanNode,
isTransactionNode,
} from 'sentry/views/performance/newTraceDetails/traceGuards';
import {isTransactionNode} from 'sentry/views/performance/newTraceDetails/traceGuards';
import type {EapSpanNode} from 'sentry/views/performance/newTraceDetails/traceModels/traceTreeNode/eapSpanNode';
import type {TransactionNode} from 'sentry/views/performance/newTraceDetails/traceModels/traceTreeNode/transactionNode';

Expand Down Expand Up @@ -275,26 +272,18 @@ function getNodeInfo(node: AITraceSpanNode, colors: readonly string[]) {
return nodeInfo;
}

const getNodeAttribute = (key: string) => {
if (isEAPSpanNode(node)) {
return node.value.additional_attributes?.[key];
}

return node.value?.data?.[key];
};

const op = node.op ?? 'default';
const truncatedOp = op.startsWith('gen_ai.') ? op.slice(7) : op;
nodeInfo.title = truncatedOp;

if (getIsAiRunSpan({op}) || getIsAiCreateAgentSpan({op})) {
const agentName =
getNodeAttribute(SpanFields.GEN_AI_AGENT_NAME) ||
getNodeAttribute(SpanFields.GEN_AI_FUNCTION_ID) ||
node.attributes?.[SpanFields.GEN_AI_AGENT_NAME] ||
node.attributes?.[SpanFields.GEN_AI_FUNCTION_ID] ||
'';
const model =
getNodeAttribute(SpanFields.GEN_AI_REQUEST_MODEL) ||
getNodeAttribute(SpanFields.GEN_AI_RESPONSE_MODEL) ||
node.attributes?.[SpanFields.GEN_AI_REQUEST_MODEL] ||
node.attributes?.[SpanFields.GEN_AI_RESPONSE_MODEL] ||
'';
nodeInfo.icon = <IconBot size="md" />;
nodeInfo.title = agentName || truncatedOp;
Expand All @@ -308,8 +297,12 @@ function getNodeInfo(node: AITraceSpanNode, colors: readonly string[]) {
}
nodeInfo.color = colors[0];
} else if (getIsAiGenerationSpan({op})) {
const tokens = getNodeAttribute(SpanFields.GEN_AI_USAGE_TOTAL_TOKENS);
const cost = getNodeAttribute(SpanFields.GEN_AI_USAGE_TOTAL_COST);
const tokens = node.attributes?.[SpanFields.GEN_AI_USAGE_TOTAL_TOKENS] as
| number
| undefined;
const cost = node.attributes?.[SpanFields.GEN_AI_USAGE_TOTAL_COST] as
| number
| undefined;
nodeInfo.icon = <IconSpeechBubble size="md" />;
nodeInfo.subtitle = tokens ? (
<Fragment>
Expand All @@ -328,7 +321,7 @@ function getNodeInfo(node: AITraceSpanNode, colors: readonly string[]) {
}
nodeInfo.color = colors[2];
} else if (getIsExecuteToolSpan({op})) {
const toolName = getNodeAttribute(SpanFields.GEN_AI_TOOL_NAME);
const toolName = node.attributes?.[SpanFields.GEN_AI_TOOL_NAME] as string | undefined;
nodeInfo.icon = <IconTool size="md" />;
nodeInfo.title = toolName || truncatedOp;
nodeInfo.subtitle = toolName ? truncatedOp : '';
Expand All @@ -355,12 +348,9 @@ function hasError(node: AITraceSpanNode) {
return true;
}

if (isEAPSpanNode(node)) {
const status = node.value.additional_attributes?.[SpanFields.SPAN_STATUS];
if (typeof status === 'string') {
return status.includes('error');
}
return false;
const status = node.attributes?.[SpanFields.SPAN_STATUS] as string | undefined;
if (typeof status === 'string') {
return status.includes('error');
}

return false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type {OurLogsResponseItem} from 'sentry/views/explore/logs/types';
import type {TraceRootEventQueryResults} from 'sentry/views/performance/newTraceDetails/traceApi/useTraceRootEvent';
import {
isEAPTraceNode,
isEAPTransaction,
isRootEvent,
isTraceNode,
isTraceSplitResult,
Expand Down Expand Up @@ -74,11 +73,6 @@ export const getRepresentativeTraceEvent = (
break;
}

if (isEAPTransaction(event)) {
// If we find a root EAP transaction, we can stop looking and use it for the title.
break;
}
// Otherwise we keep looking for a root eap transaction. If we don't find one, we use other roots, like standalone spans.
continue;
} else if (
// If we haven't found a root transaction, but we found a candidate transaction
Expand Down
8 changes: 0 additions & 8 deletions static/app/views/performance/newTraceDetails/traceGuards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,6 @@ export function isEAPSpan(value: TraceTree.NodeValue): value is TraceTree.EAPSpa
return !!(value && 'is_transaction' in value);
}

export function isEAPTransaction(value: TraceTree.NodeValue): value is TraceTree.EAPSpan {
return isEAPSpan(value) && value.is_transaction;
}

export function isEAPTransactionNode(node: BaseNode): node is EapSpanNode {
return isEAPTransaction(node.value);
}

export function isEAPSpanNode(node: BaseNode): node is EapSpanNode {
return isEAPSpan(node.value);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import type {Organization} from 'sentry/types/organization';
import type {TraceMetaQueryResults} from 'sentry/views/performance/newTraceDetails/traceApi/useTraceMeta';
import type {TraceTreeNodeDetailsProps} from 'sentry/views/performance/newTraceDetails/traceDrawer/tabs/traceTreeNodeDetails';
import {
isEAPTransactionNode,
isEAPSpanNode,
isTransactionNode,
} from 'sentry/views/performance/newTraceDetails/traceGuards';
import type {TraceTree} from 'sentry/views/performance/newTraceDetails/traceModels/traceTree';
Expand Down Expand Up @@ -471,7 +471,7 @@ export abstract class BaseNode<T extends TraceTree.NodeValue = TraceTree.NodeVal
}

findParentEapTransaction(): EapSpanNode | null {
return this.findParent<EapSpanNode>(p => isEAPTransactionNode(p));
return this.findParent<EapSpanNode>(p => isEAPSpanNode(p) && p.value.is_transaction);
}

expand(expanding: boolean, tree: TraceTree): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import {EAPSpanNodeDetails} from 'sentry/views/performance/newTraceDetails/trace
import type {TraceTreeNodeDetailsProps} from 'sentry/views/performance/newTraceDetails/traceDrawer/tabs/traceTreeNodeDetails';
import {
isBrowserRequestNode,
isEAPSpan,
isEAPSpanNode,
isEAPTransaction,
} from 'sentry/views/performance/newTraceDetails/traceGuards';
import type {TraceTree} from 'sentry/views/performance/newTraceDetails/traceModels/traceTree';
import {TraceEAPSpanRow} from 'sentry/views/performance/newTraceDetails/traceRow/traceEAPSpanRow';
Expand All @@ -35,7 +33,7 @@ export class EapSpanNode extends BaseNode<TraceTree.EAPSpan> {
// For eap transactions, on load we only display the embedded transactions children.
// Mimics the behavior of non-eap traces, enabling a less noisy/summarized view of the trace
const parentNode = value.is_transaction
? (parent?.findParent(p => isEAPTransaction(p.value)) ?? parent)
? (parent?.findParent(p => isEAPSpanNode(p) && p.value.is_transaction) ?? parent)
: parent;

super(parentNode, value, extra);
Expand Down Expand Up @@ -141,10 +139,12 @@ export class EapSpanNode extends BaseNode<TraceTree.EAPSpan> {
}

get directVisibleChildren(): Array<BaseNode<TraceTree.NodeValue>> {
if (isEAPTransaction(this.value) && !this.expanded) {
if (this.value.is_transaction && !this.expanded) {
// For collapsed eap-transactions we still render the embedded eap-transactions as visible children.
// Mimics the behavior of non-eap traces, enabling a less noisy/summarized view of the trace
return this.children.filter(child => isEAPTransaction(child.value));
return this.children.filter(
child => isEAPSpanNode(child) && child.value.is_transaction
);
}

return super.directVisibleChildren;
Expand Down Expand Up @@ -181,14 +181,14 @@ export class EapSpanNode extends BaseNode<TraceTree.EAPSpan> {
// the eap-spans (by their parent_span_id) that were previously hidden. Note that this only impacts the
// direct eap-transaction children of the targetted eap-transaction node.
if (this.value.is_transaction) {
const eapTransactions = this.children.filter(c =>
isEAPTransaction(c.value)
const eapTransactions = this.children.filter(
c => isEAPSpanNode(c) && c.value.is_transaction
) as EapSpanNode[];

for (const txn of eapTransactions) {
// Find the eap-span that is the parent of the transaction
const newParent = this.findChild(n => {
if (isEAPSpan(n.value)) {
if (isEAPSpanNode(n)) {
return n.value.event_id === txn.value.parent_span_id;
}
return false;
Expand Down
Loading