-
Notifications
You must be signed in to change notification settings - Fork 113
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
Feedback inspector in Assistant builder #9680
Conversation
if (!config.versionCreatedAt) { | ||
return `v${config.version}`; | ||
} | ||
return new Date(config.versionCreatedAt).toLocaleDateString("en-US", { |
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 use a date instead of timeAgo because the iterations might be close in time, and you still want to easily distinguish them.
This is consistent with the date given in the prompt versioning Popover
@@ -565,6 +569,7 @@ export default function AssistantBuilder({ | |||
rightPanelStatus={rightPanelStatus} | |||
openRightPanelTab={openRightPanelTab} | |||
builderState={builderState} | |||
agentConfigurationId={agentConfigurationId} |
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.
passing Id instead of LightAgentConfigurationType because a larger refactoring is needed (wouldn't be consistent with submitAssistantBuilderForm, SharingButton, InstructionScreen, useSlackChannel, ...)
shouldAnimatePreviewDrawer && | ||
rightPanelStatus.tab === "Preview" && | ||
rightPanelStatus.openedAt != null && | ||
className={cn( |
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 keeps the same display except with a white background for the feedback tab
)} | ||
{agentConfigurationId && ( | ||
<TabsTrigger | ||
value="Performance" |
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.
Analytics will be added to this tab later -> Performance is a sensible name
feedback.conversationId && | ||
feedback.messageId && | ||
feedback.isConversationShared | ||
? `${process.env.NEXT_PUBLIC_DUST_CLIENT_FACING_URL}/w/${owner.sId}/assistant/${feedback.conversationId}#${feedback.messageId}` |
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.
We add a messageId anchor, because another PR will make it possible to auto-scroll to the message.
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.
IMHO this should be returned by the endpoint directly since this is very brittle the day we decide to change the endpoint, pretty sure we won't find this occurrence.
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 mean getting the link from the endpoint ?
I don't see how it would be easier to spot in the endpoint vs in this file, given that the endpoint is not the conversation one.
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.
given that the endpoint is not the conversation one.
Not sure to get this one 🤔
@@ -20,7 +20,7 @@ export function PrevNextButtons({ | |||
<Button | |||
label="Previous" | |||
size="md" | |||
variant="highlight" | |||
variant="primary" |
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.
Makes buttons black -> Asked from design team
front/lib/api/assistant/feedback.ts
Outdated
| AgentMessageFeedbackType | ||
| AgentMessageFeedbackWithMetadataType | ||
)[]; | ||
totalFeedbackCount: number; |
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.
The count is needed, because pagination relies on it
}; | ||
|
||
// Get the total feedback count, because needed for pagination | ||
const totalFeedbackCountPromise = AgentMessageFeedback.count({ |
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 hits the highest number of feedbacks
explain analyze SELECT count(*) AS "count" FROM "agent_message_feedbacks" AS "agent_message_feedback" WHERE "agent_message_feedback"."workspaceId" = 44603 AND "agent_message_feedback"."agentConfigurationId" = 'claude-3-sonnet';
Aggregate (cost=40.55..40.56 rows=1 width=8) (actual time=0.281..0.281 rows=1 loops=1)
-> Seq Scan on agent_message_feedbacks agent_message_feedback (cost=0.00..39.62 rows=372 width=0) (actual time=0.012..0.249 rows=628 loops=1)
Filter: (("workspaceId" = 44603) AND (("agentConfigurationId")::text = 'claude-3-sonnet'::text))
Rows Removed by Filter: 640
Planning Time: 0.097 ms
Execution Time: 0.307 ms
} | ||
className="hidden lg:flex" | ||
> | ||
<TabsList className="inline-flex items-center gap-2 border-b border-separator"> |
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.
Removed the h-10 because it was producing a vertical scroll bar. The rest is unchanged.
rightPanelStatus.openedAt != null && | ||
className={cn( | ||
"grow-1 mb-5 h-full overflow-y-auto border-structure-200", | ||
{ |
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.
IMHO it becomes pretty hard to figure the style by looking at this code...
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 agree that it's complex, I tried not to touch the design, imho we already had a good bunch of complexity and this syntax is easier to read
front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx
Outdated
Show resolved
Hide resolved
front/components/assistant_builder/AssistantBuilderPreviewDrawer.tsx
Outdated
Show resolved
Hide resolved
| AgentMessageFeedbackWithMetadataType | ||
)[]; | ||
totalFeedbackCount: number; | ||
}> { | ||
const where: WhereOptions<AgentMessageFeedback> = { | ||
// IMPORTANT: Necessary for global models who share ids across workspaces. |
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 thought that global agent could not get feedback?
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.
They used to (at the time I wrote this comment), and an extra layer of security doesn't hurt I guess ?
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 guess this layer should happened before hitting our DB since this does not require any DB interaction and can be disregard earlier.
@@ -91,35 +92,42 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb | |||
}); | |||
} | |||
|
|||
static async fetch({ | |||
static async getAgentConfigurationFeedbacksByDescVersion({ |
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 goes against the Resource pattern approach. All those functions should actually return a Resource not an object. Then if you need. serialized object you should use a toJSON
. Any reason to not follow this pattern?
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.
Yes,
The main obstacle is that you need to do several includes (on AgentMessage, Message and Conversation) which prevents you from only getting a resource back, and associating a toJSON to only a feedback resource.
I got this hint from @Fraggle https://dust4ai.slack.com/archives/C050SM8NSPK/p1734706622967029?thread_ts=1734705178.946699&cid=C050SM8NSPK
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.
Ok did not get this info. OOC why don't we use class variable to have those on the resource like we do for many other resources?
Example with DataSourceViewResource
here:
readonly editedByUser?: Attributes<UserModel>; |
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.
Agree that the returned object is too complex is that we should try to return resources instead.
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.
Will spend some time with @overmode today to align the pattern.
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.
Please share your conclusions, i'm interested :)
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.
We ended up creating an attribute in the resource class to allow easy access to related objects. My main takeaways are that we should indeed refrain from returning anything else than a resource in a _resource file, that toJSON should be kept simple even if that means adding pose-serialize logic to /lib/api files, and that sequelize is really bad a typing.
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.
🔥
8090417
to
4c61121
Compare
@@ -91,35 +92,42 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb | |||
}); | |||
} | |||
|
|||
static async fetch({ | |||
static async getAgentConfigurationFeedbacksByDescVersion({ |
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.
Agree that the returned object is too complex is that we should try to return resources instead.
front/lib/swr/assistants.ts
Outdated
const { data, error, mutate, size, setSize, isLoading, isValidating } = | ||
useSWRInfiniteWithDefaults( | ||
(pageIndex: number, previousPageData) => { | ||
console.log("previousPageData", previousPageData); |
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.
✂️
3aa78fe
to
5cd4c98
Compare
}); | ||
|
||
// Intersection observer to detect when the user has scrolled to the bottom of the list. | ||
const bottomRef = useRef<HTMLDivElement>(null); |
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.
Any reason to use the existing hook useLastMessageGroupObserver
(ok naming is not generic, but the code is!)
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 would need to refactor the version to not accept message but a generic entity (because I'm observing over feedbacks, not messages), and accept the id as a parameter (to avoid conflicts).
2nd point is fine but 1st one is painful, you don't want to have a 'any' type even though that's ~the idea.
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.
One more type, we could leverage duck typing to ensure that we accept all entities that have at least id
set 🙃.
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.
As seen irl the go-to type is unknown
agentConfigurationFeedbacks[index - 1].agentConfigurationVersion; | ||
return ( | ||
<div key={feedback.id} className="animate-fadeIn"> | ||
{isNewVersion && ( |
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.
Hard to understand how isNewVersion
influences isLatestVersion
, can we align naming?
@@ -91,35 +92,42 @@ export class AgentMessageFeedbackResource extends BaseResource<AgentMessageFeedb | |||
}); | |||
} | |||
|
|||
static async fetch({ | |||
static async getAgentConfigurationFeedbacksByDescVersion({ |
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.
🔥
// If we have reached the last page and there are no more | ||
// messages or the previous page has no messages, return null. | ||
if (previousPageData && previousPageData.feedbacks.length < limit) { | ||
setHasMore(false); |
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.
Why do we expose hasMore? IIRC, returning null here will stop the fetch like it's being done in the message.
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.
it is used to avoid calling setSize for ever, we also have a variation of it in messages https://github.com/dust-tt/dust/blob/lucas/feedbacks-inspector/front/components/assistant/conversation/ConversationViewer.tsx#L203
isAgentConfigurationFeedbacksLoading, | ||
isValidating, | ||
agentConfigurationFeedbacks, | ||
hasMore: feedbacksNotExhausted, |
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.
nit
Pretty confusing naming, we are loosing the boolean meaning.
<AgentConfigurationVersionHeader | ||
agentConfiguration={agentConfigurationHistory[0]} | ||
agentConfigurationVersion={agentConfigurationHistory[0].version} | ||
isLatestVersion={true} |
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.
nit
isLatestVersion={true} | |
isLatestVersion |
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.
explicitly setting to true is used widely across the codebase (59 files), I have no easy way to look for the other method to compare, but seems like I'm keeping this one. Cool syntax trick though 👍
…, more loaded at once
…er.tsx Co-authored-by: Flavien David <[email protected]>
44edbfe
to
e693865
Compare
Description
Screen.Recording.2025-01-08.at.12.45.20.mov
Risk
Break assistant builder
Deploy Plan
Deploy Front