-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
feat(llm-observability): spans #27933
Conversation
Size Change: +503 B (+0.04%) Total Size: 1.16 MB ℹ️ View Unchanged
|
…thog into feat/llm-observability-spans
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tree overflow gets janky, otherwise all good
</h3> | ||
</div> | ||
{isLLMTraceEvent(event) ? ( | ||
<MetadataHeader | ||
hasError={event.properties.$ai_is_error} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Naming nit: may be more consistent to do isError={event.properties.$ai_is_error}
) | ||
} | ||
) | ||
LLMMessageDisplay.displayName = 'LLMMessageDisplay' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This wouldn't be needed if the memo used function
:
export const LLMMessageDisplay = React.memo(
function LLMMessageDisplay(...) { }
)
topLevelTrace, | ||
item, | ||
isSelected, | ||
const TraceNode = React.memo( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So actually this is a TraceLeaf
) | ||
TraceNode.displayName = 'TraceNode' | ||
|
||
function RecursiveTreeDisplay({ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And this is a TraceNode
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AH, I was being raving mad, this is actually NodeChildren
and the other one is TreeNode
</span> | ||
), | ||
] | ||
const hasChildren = children.find((child) => !!child) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const hasChildren = children.find((child) => !!child) | |
const hasChildren = children.some((child) => !!child) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right😄 It's what find
is enough here. We just need to know that at least one child exists.some
does. I'm more used to find
.
const idMap = new Map<any, LLMTraceEvent>() | ||
|
||
// Map all events with parents to their parent IDs | ||
events.forEach((event) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I always find for (... of ...)
a bit more readable, but that's a nit which should be a linter rule
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forEach
used to be faster. I'm unsure though it's true now.
}): JSX.Element { | ||
return ( | ||
<aside className="border-border max-h-fit bg-bg-light border rounded overflow-hidden md:w-72"> | ||
<aside className="border-border max-h-full bg-bg-light border rounded overflow-hidden md:w-72"> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it intentional we're back to filling the full height of the scene even if there's just a couple items in the trace? I believed max-h-fit
would still work here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, if we set max-h-fit
, the scroll won't work for larger content.
</NestingGroup> | ||
</aside> | ||
) | ||
} | ||
|
||
function NestingGroup({ level = 0, children }: { level?: number; children: React.ReactNode }): JSX.Element { | ||
const listEl = <ul className={!level ? 'overflow-y-auto p-1 first:*:mt-0' : 'flex-1'}>{children}</ul> | ||
const listEl = ( | ||
<ul className={!level ? 'hide-scrollbar overflow-y-auto p-1 first:*:mt-0 h-full' : 'flex-1'}>{children}</ul> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few snags in scrolling:
- It's a much worse experience without scrollbars, let's avoid
hide-scrollbar
- Horizontal overflow is a little awkward, it's generally hard to make scrolling a list in both axes feel good. Proposing we wrap for readability instead. This will also avoid mismatches width, like here:
- I believe this should be
max-h-full
so avoid filling height with whitespace
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we usually show scrollbars for overflow or not? The scrollbar doesn't look nice on Windows.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const usage = formatLLMUsage(item) | ||
return ( | ||
<NestingGroup level={1}> | ||
{tree.map(({ event, children }) => ( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! I didn't notice it.
'p-2 text-xs border rounded', | ||
!raisedError ? 'bg-[var(--bg-fill-success-tertiary)]' : 'bg-[var(--bg-fill-warning-tertiary)]' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's use red to signal an error:
'p-2 text-xs border rounded', | |
!raisedError ? 'bg-[var(--bg-fill-success-tertiary)]' : 'bg-[var(--bg-fill-warning-tertiary)]' | |
'p-2 text-xs border rounded', | |
!raisedError ? 'bg-[var(--bg-fill-success-tertiary)]' : 'bg-[var(--bg-fill-danger-tertiary)]' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I used the danger color initially, but the contrast ratio is not great and is hard to read. When you look at those spans for a little longer, you actually want it to be plain and readable. I've thought about changing the header color instead of applying a background, as it serves the same indicative purpose, but the content is significantly easier to read.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Awesome
Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Michael Matloka <[email protected]>
Problem
Users want to see a tree of spans and generations with the input and output of each step.
Changes
$ai_trace_name
and return$ai_span
events.Light theme
Dark theme
Does this work well for both Cloud and self-hosted?
Yes
How did you test this code?
Unit tests and manual testing