Skip to content
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

refactor(prompts): Normalize playground instance messages #6218

Open
wants to merge 3 commits into
base: prompts
Choose a base branch
from

Conversation

cephalization
Copy link
Contributor

@cephalization cephalization commented Jan 31, 2025

This PR contains two major changes, and should be viewed by-commit.

Normalize playground instance messages


There is now a split in instance types:

  • PlaygroundInstance
  • PlaygroundNormalizedInstance

The main difference is that chat templates within a normalized instance only contain messageIds instead of message objects.

The PlaygroundStore now only deals in PlaygroundNormalizedInstance, and handles conversion from PlaygroundInstance to PlaygroundNormalizedInstance during initialization.

Convert code mirror editors on playground to be uncontrolled


  • TemplateEditor
  • VariableEditor
  • PlaygroundTool (editor)

All of this is in service of fixing a react-codemirror bug that breaks rendering when updates take too long, which was occurring because messages were stored deeply within an instance causing a cascade of re-renders on every keystroke.

@cephalization cephalization marked this pull request as ready for review January 31, 2025 21:54
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Jan 31, 2025
Comment on lines +67 to +71
useEffect(() => {
if (readOnly) {
setValue(defaultValue);
}
}, [readOnly, defaultValue]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Confused why this useEffect is needed. Isn't value defaulting to defaultValue anyways?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

it is defaulting to it, but never changes from it. This gives codemirror a stable "value" which it was already treating as a default value. Confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The useEffect makes sure to update the value with the new defaultValue if we are in readOnly mode. This lets codemirror blast away when new changes come in like normal, so that the caller doesn't have to mess with keys and remounting

);
const newMessages = arrayMove(messageIds, activeIndex, overIndex);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const newMessages = arrayMove(messageIds, activeIndex, overIndex);
const newMessageIds = arrayMove(messageIds, activeIndex, overIndex);

Copy link
Contributor

@mikeldking mikeldking left a comment

Choose a reason for hiding this comment

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

Def. much better behavior.

@@ -361,6 +352,17 @@ function SortableMessageItem({
ChatMessage["toolCalls"]
>(message.toolCalls);

const updateThisMessage = useCallback(
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const updateThisMessage = useCallback(
const onMessageUpdate = useCallback(

Comment on lines +48 to +54
useEffect(() => {
if (defaultValue == null) {
setInitialValue("");
setVersion((prev) => prev + 1);
}
valueRef.current = defaultValue;
}, [defaultValue]);
Copy link
Contributor

Choose a reason for hiding this comment

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

is this useEffect needed? Seems un-necessary?

valueRef.current = defaultValue;
}, [defaultValue]);
useEffect(() => {
setInitialValue(valueRef.current);
Copy link
Contributor

Choose a reason for hiding this comment

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

A bit confused why this is even entirely needed. Shouldn't we just not have initial values for this stuff?

@@ -919,6 +927,12 @@ const getBaseChatCompletionInput = ({
throw new Error("We only support chat templates for now");
}

const thisInstanceMessages = instance.template.messageIds
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const thisInstanceMessages = instance.template.messageIds
const instanceMessages = instance.template.messageIds

don't think you need this here

if (instance.template.__type === "chat") {
const normalizedTemplate = normalizeChatTemplate(instance.template);
messageMap = {
...messageMap,
Copy link
Contributor

Choose a reason for hiding this comment

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

why does messageMap need to be spread in here? It's largely an un-initialized object on line 190?

let newMessageIds: number[] = [];
let newMessageMap: Record<number, ChatMessage> = {};
if (firstInstance.template.__type === "chat") {
const existingMessageIds = firstInstance.template.messageIds;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
const existingMessageIds = firstInstance.template.messageIds;
const messageIdsToCopy = firstInstance.template.messageIds;

...message,
id: generateMessageId(),
}));
newMessageIds = existingMessages.map((message) => message.id);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
newMessageIds = existingMessages.map((message) => message.id);
newMessageIds = newMessages.map((message) => message.id);

Comment on lines +515 to +517
...get().instanceMessages,
[messageId]: {
...get().instanceMessages[messageId],
Copy link
Contributor

Choose a reason for hiding this comment

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

call get once before line 513 as the store? no need to call multiple times even if it might be technically inexpensive.

Comment on lines +19 to +21
const instance = state.instances.find(
(instance) => instance.id === instanceId
);
Copy link
Contributor

Choose a reason for hiding this comment

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

can reUse selectPlayGroundInstance here.

/**
* If not provided, a default empty message will be added
*/
messages?: ChatMessage | ChatMessage[];
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
messages?: ChatMessage | ChatMessage[];
messages?: ChatMessage[];

can we keep the type uniform?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
size:XL This PR changes 500-999 lines, ignoring generated files.
Projects
Status: 👍 Approved
Development

Successfully merging this pull request may close these issues.

2 participants