Skip to content

Commit 23171b0

Browse files
authored
Merge pull request #213 from get-convex/seth/userid-in-uimessage-188
Add userId field to UIMessage type
2 parents 426eab0 + ab6a8b0 commit 23171b0

File tree

2 files changed

+133
-1
lines changed

2 files changed

+133
-1
lines changed

src/UIMessages.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export type UIMessage<
4242
stepOrder: number;
4343
status: UIStatus;
4444
agentName?: string;
45+
userId?: string;
4546
text: string;
4647
_creationTime: number;
4748
};
@@ -75,7 +76,8 @@ export function fromUIMessages<METADATA = unknown>(
7576
"providerOptions",
7677
"metadata",
7778
]),
78-
...omit(uiMessage, ["parts", "role", "key", "text"]),
79+
...omit(uiMessage, ["parts", "role", "key", "text", "userId"]),
80+
userId: uiMessage.userId ?? meta.userId,
7981
status: uiMessage.status === "streaming" ? "pending" : "success",
8082
streaming: uiMessage.status === "streaming",
8183
// to override
@@ -288,6 +290,7 @@ function createSystemUIMessage<
288290
text,
289291
role: "system",
290292
agentName: message.agentName,
293+
userId: message.userId,
291294
parts: [{ type: "text", text, ...partCommon } satisfies TextUIPart],
292295
metadata: message.metadata,
293296
};
@@ -347,6 +350,7 @@ function createUserUIMessage<
347350
key: `${message.threadId}-${message.order}-${message.stepOrder}`,
348351
text,
349352
role: "user",
353+
userId: message.userId,
350354
parts,
351355
metadata: message.metadata,
352356
};
@@ -370,6 +374,7 @@ function createAssistantUIMessage<
370374
stepOrder: firstMessage.stepOrder,
371375
key: `${firstMessage.threadId}-${firstMessage.order}-${firstMessage.stepOrder}`,
372376
agentName: firstMessage.agentName,
377+
userId: firstMessage.userId,
373378
};
374379

375380
// Get status from last message

src/toUIMessages.test.ts

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,4 +728,131 @@ describe("toUIMessages", () => {
728728
expect(textParts).toHaveLength(1);
729729
expect(textParts[0].text).toBe("The result is 42.");
730730
});
731+
732+
describe("userId preservation", () => {
733+
it("preserves userId in user messages", () => {
734+
const messages = [
735+
baseMessageDoc({
736+
userId: "user123",
737+
message: {
738+
role: "user",
739+
content: "Hello!",
740+
},
741+
text: "Hello!",
742+
}),
743+
];
744+
const uiMessages = toUIMessages(messages);
745+
expect(uiMessages).toHaveLength(1);
746+
expect(uiMessages[0].role).toBe("user");
747+
expect(uiMessages[0].userId).toBe("user123");
748+
});
749+
750+
it("preserves userId in system messages", () => {
751+
const messages = [
752+
baseMessageDoc({
753+
userId: "user456",
754+
message: {
755+
role: "system",
756+
content: "System prompt",
757+
},
758+
text: "System prompt",
759+
}),
760+
];
761+
const uiMessages = toUIMessages(messages);
762+
expect(uiMessages).toHaveLength(1);
763+
expect(uiMessages[0].role).toBe("system");
764+
expect(uiMessages[0].userId).toBe("user456");
765+
});
766+
767+
it("preserves userId in assistant messages", () => {
768+
const messages = [
769+
baseMessageDoc({
770+
userId: "user789",
771+
message: {
772+
role: "assistant",
773+
content: "Hi there!",
774+
},
775+
text: "Hi there!",
776+
}),
777+
];
778+
const uiMessages = toUIMessages(messages);
779+
expect(uiMessages).toHaveLength(1);
780+
expect(uiMessages[0].role).toBe("assistant");
781+
expect(uiMessages[0].userId).toBe("user789");
782+
});
783+
784+
it("preserves userId from first message in grouped assistant messages", () => {
785+
const messages = [
786+
baseMessageDoc({
787+
_id: "msg1",
788+
userId: "userA",
789+
order: 1,
790+
stepOrder: 1,
791+
tool: true,
792+
message: {
793+
role: "assistant",
794+
content: [
795+
{
796+
type: "tool-call",
797+
toolName: "myTool",
798+
toolCallId: "call1",
799+
args: {},
800+
},
801+
],
802+
},
803+
text: "",
804+
}),
805+
baseMessageDoc({
806+
_id: "msg2",
807+
userId: "userA",
808+
order: 1,
809+
stepOrder: 2,
810+
tool: true,
811+
message: {
812+
role: "tool",
813+
content: [
814+
{
815+
type: "tool-result",
816+
toolCallId: "call1",
817+
toolName: "myTool",
818+
output: { type: "text", value: "result" },
819+
},
820+
],
821+
},
822+
text: "",
823+
}),
824+
baseMessageDoc({
825+
_id: "msg3",
826+
userId: "userA",
827+
order: 1,
828+
stepOrder: 3,
829+
message: {
830+
role: "assistant",
831+
content: "Done!",
832+
},
833+
text: "Done!",
834+
}),
835+
];
836+
const uiMessages = toUIMessages(messages);
837+
expect(uiMessages).toHaveLength(1);
838+
expect(uiMessages[0].role).toBe("assistant");
839+
expect(uiMessages[0].userId).toBe("userA");
840+
});
841+
842+
it("handles undefined userId gracefully", () => {
843+
const messages = [
844+
baseMessageDoc({
845+
// No userId provided
846+
message: {
847+
role: "user",
848+
content: "Hello!",
849+
},
850+
text: "Hello!",
851+
}),
852+
];
853+
const uiMessages = toUIMessages(messages);
854+
expect(uiMessages).toHaveLength(1);
855+
expect(uiMessages[0].userId).toBeUndefined();
856+
});
857+
});
731858
});

0 commit comments

Comments
 (0)