@convex-dev/agent 0.0.1-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +55 -0
  3. package/dist/commonjs/client/index.d.ts +198 -0
  4. package/dist/commonjs/client/index.d.ts.map +1 -0
  5. package/dist/commonjs/client/index.js +365 -0
  6. package/dist/commonjs/client/index.js.map +1 -0
  7. package/dist/commonjs/client/types.d.ts +21 -0
  8. package/dist/commonjs/client/types.d.ts.map +1 -0
  9. package/dist/commonjs/client/types.js +2 -0
  10. package/dist/commonjs/client/types.js.map +1 -0
  11. package/dist/commonjs/component/_generated/api.d.ts +12 -0
  12. package/dist/commonjs/component/_generated/api.d.ts.map +1 -0
  13. package/dist/commonjs/component/_generated/api.js +22 -0
  14. package/dist/commonjs/component/_generated/api.js.map +1 -0
  15. package/dist/commonjs/component/_generated/server.d.ts +64 -0
  16. package/dist/commonjs/component/_generated/server.d.ts.map +1 -0
  17. package/dist/commonjs/component/_generated/server.js +74 -0
  18. package/dist/commonjs/component/_generated/server.js.map +1 -0
  19. package/dist/commonjs/component/convex.config.d.ts +3 -0
  20. package/dist/commonjs/component/convex.config.d.ts.map +1 -0
  21. package/dist/commonjs/component/convex.config.js +3 -0
  22. package/dist/commonjs/component/convex.config.js.map +1 -0
  23. package/dist/commonjs/component/lib.d.ts +2 -0
  24. package/dist/commonjs/component/lib.d.ts.map +1 -0
  25. package/dist/commonjs/component/lib.js +2 -0
  26. package/dist/commonjs/component/lib.js.map +1 -0
  27. package/dist/commonjs/component/messages.d.ts +1913 -0
  28. package/dist/commonjs/component/messages.d.ts.map +1 -0
  29. package/dist/commonjs/component/messages.js +787 -0
  30. package/dist/commonjs/component/messages.js.map +1 -0
  31. package/dist/commonjs/component/schema.d.ts +5496 -0
  32. package/dist/commonjs/component/schema.d.ts.map +1 -0
  33. package/dist/commonjs/component/schema.js +97 -0
  34. package/dist/commonjs/component/schema.js.map +1 -0
  35. package/dist/commonjs/component/vector/tables.d.ts +40 -0
  36. package/dist/commonjs/component/vector/tables.d.ts.map +1 -0
  37. package/dist/commonjs/component/vector/tables.js +46 -0
  38. package/dist/commonjs/component/vector/tables.js.map +1 -0
  39. package/dist/commonjs/mapping.d.ts +26 -0
  40. package/dist/commonjs/mapping.d.ts.map +1 -0
  41. package/dist/commonjs/mapping.js +101 -0
  42. package/dist/commonjs/mapping.js.map +1 -0
  43. package/dist/commonjs/package.json +3 -0
  44. package/dist/commonjs/react/index.d.ts +2 -0
  45. package/dist/commonjs/react/index.d.ts.map +1 -0
  46. package/dist/commonjs/react/index.js +8 -0
  47. package/dist/commonjs/react/index.js.map +1 -0
  48. package/dist/commonjs/shared.d.ts +9 -0
  49. package/dist/commonjs/shared.d.ts.map +1 -0
  50. package/dist/commonjs/shared.js +29 -0
  51. package/dist/commonjs/shared.js.map +1 -0
  52. package/dist/commonjs/validators.d.ts +6177 -0
  53. package/dist/commonjs/validators.d.ts.map +1 -0
  54. package/dist/commonjs/validators.js +171 -0
  55. package/dist/commonjs/validators.js.map +1 -0
  56. package/dist/esm/client/index.d.ts +198 -0
  57. package/dist/esm/client/index.d.ts.map +1 -0
  58. package/dist/esm/client/index.js +365 -0
  59. package/dist/esm/client/index.js.map +1 -0
  60. package/dist/esm/client/types.d.ts +21 -0
  61. package/dist/esm/client/types.d.ts.map +1 -0
  62. package/dist/esm/client/types.js +2 -0
  63. package/dist/esm/client/types.js.map +1 -0
  64. package/dist/esm/component/_generated/api.d.ts +12 -0
  65. package/dist/esm/component/_generated/api.d.ts.map +1 -0
  66. package/dist/esm/component/_generated/api.js +22 -0
  67. package/dist/esm/component/_generated/api.js.map +1 -0
  68. package/dist/esm/component/_generated/server.d.ts +64 -0
  69. package/dist/esm/component/_generated/server.d.ts.map +1 -0
  70. package/dist/esm/component/_generated/server.js +74 -0
  71. package/dist/esm/component/_generated/server.js.map +1 -0
  72. package/dist/esm/component/convex.config.d.ts +3 -0
  73. package/dist/esm/component/convex.config.d.ts.map +1 -0
  74. package/dist/esm/component/convex.config.js +3 -0
  75. package/dist/esm/component/convex.config.js.map +1 -0
  76. package/dist/esm/component/lib.d.ts +2 -0
  77. package/dist/esm/component/lib.d.ts.map +1 -0
  78. package/dist/esm/component/lib.js +2 -0
  79. package/dist/esm/component/lib.js.map +1 -0
  80. package/dist/esm/component/messages.d.ts +1913 -0
  81. package/dist/esm/component/messages.d.ts.map +1 -0
  82. package/dist/esm/component/messages.js +787 -0
  83. package/dist/esm/component/messages.js.map +1 -0
  84. package/dist/esm/component/schema.d.ts +5496 -0
  85. package/dist/esm/component/schema.d.ts.map +1 -0
  86. package/dist/esm/component/schema.js +97 -0
  87. package/dist/esm/component/schema.js.map +1 -0
  88. package/dist/esm/component/vector/tables.d.ts +40 -0
  89. package/dist/esm/component/vector/tables.d.ts.map +1 -0
  90. package/dist/esm/component/vector/tables.js +46 -0
  91. package/dist/esm/component/vector/tables.js.map +1 -0
  92. package/dist/esm/mapping.d.ts +26 -0
  93. package/dist/esm/mapping.d.ts.map +1 -0
  94. package/dist/esm/mapping.js +101 -0
  95. package/dist/esm/mapping.js.map +1 -0
  96. package/dist/esm/package.json +3 -0
  97. package/dist/esm/react/index.d.ts +2 -0
  98. package/dist/esm/react/index.d.ts.map +1 -0
  99. package/dist/esm/react/index.js +8 -0
  100. package/dist/esm/react/index.js.map +1 -0
  101. package/dist/esm/shared.d.ts +9 -0
  102. package/dist/esm/shared.d.ts.map +1 -0
  103. package/dist/esm/shared.js +29 -0
  104. package/dist/esm/shared.js.map +1 -0
  105. package/dist/esm/validators.d.ts +6177 -0
  106. package/dist/esm/validators.d.ts.map +1 -0
  107. package/dist/esm/validators.js +171 -0
  108. package/dist/esm/validators.js.map +1 -0
  109. package/package.json +91 -0
  110. package/react/package.json +5 -0
  111. package/src/client/index.ts +659 -0
  112. package/src/client/types.ts +54 -0
  113. package/src/component/_generated/api.d.ts +1497 -0
  114. package/src/component/_generated/api.js +23 -0
  115. package/src/component/_generated/dataModel.d.ts +60 -0
  116. package/src/component/_generated/server.d.ts +149 -0
  117. package/src/component/_generated/server.js +90 -0
  118. package/src/component/convex.config.ts +3 -0
  119. package/src/component/lib.test.ts +13 -0
  120. package/src/component/lib.ts +2 -0
  121. package/src/component/messages.ts +959 -0
  122. package/src/component/schema.ts +101 -0
  123. package/src/component/setup.test.ts +5 -0
  124. package/src/component/vector/tables.ts +92 -0
  125. package/src/mapping.ts +160 -0
  126. package/src/react/index.ts +8 -0
  127. package/src/shared.ts +35 -0
  128. package/src/validators.test.ts +101 -0
  129. package/src/validators.ts +258 -0
@@ -0,0 +1,101 @@
1
+ import { defineSchema, defineTable } from "convex/server";
2
+ import { v } from "convex/values";
3
+ import { vChatStatus, vMessage, vMessageStatus, vStep } from "../validators";
4
+ import { typedV } from "convex-helpers/validators";
5
+ import vectorTables, { vVectorId } from "./vector/tables";
6
+
7
+ export const schema = defineSchema({
8
+ chats: defineTable({
9
+ userId: v.optional(v.string()), // Unset for anonymous
10
+ order: v.optional(v.number()), // within a domain
11
+ // TODO: is this bubbling up in continue?
12
+ defaultSystemPrompt: v.optional(v.string()),
13
+ title: v.optional(v.string()),
14
+ summary: v.optional(v.string()),
15
+ status: vChatStatus,
16
+ // If this is a chat continuation, we can use this to find context from
17
+ // the parent chat(s). There are multiple if the chat is a merging of
18
+ // multiple chats.
19
+ parentChatIds: v.optional(v.array(v.id("chats"))),
20
+ }).index("status_userId_order", ["status", "userId", "order"]),
21
+ // TODO: text search on title/ summary
22
+ messages: defineTable({
23
+ id: v.optional(v.string()), // external id, e.g. from Vercel AI SDK
24
+ userId: v.optional(v.string()), // useful for future indexes (text search)
25
+ chatId: v.id("chats"),
26
+ threadId: v.optional(v.id("messages")),
27
+ stepId: v.optional(v.id("steps")),
28
+ agentName: v.optional(v.string()),
29
+ message: v.optional(vMessage),
30
+ model: v.optional(v.string()),
31
+ text: v.optional(v.string()),
32
+ embeddingId: v.optional(vVectorId),
33
+ // TODO: add sub-messages back in? or be able to skip them?
34
+ tool: v.boolean(),
35
+ // Repeats until a non-tool message.
36
+ // Set when the message is finished
37
+ order: v.optional(v.number()),
38
+ stepOrder: v.optional(v.number()),
39
+ fileId: v.optional(v.id("files")),
40
+ status: vMessageStatus,
41
+ })
42
+ // Allows finding successful visible messages in order
43
+ // Also surface pending messages separately to e.g. stream
44
+ .index("chatId_status_tool_order_stepOrder", [
45
+ "chatId",
46
+ "status",
47
+ "tool",
48
+ "order",
49
+ "stepOrder",
50
+ ])
51
+ // Allows finding all threaded messages in order
52
+ // Allows finding all failed messages to evaluate
53
+ // .index("status_threadId_order_stepOrder", [
54
+ // "status",
55
+ // "threadId",
56
+ // "order",
57
+ // "stepOrder",
58
+ // ])
59
+ // Allows text search on message content
60
+ .searchIndex("text_search", {
61
+ searchField: "text",
62
+ filterFields: ["userId", "chatId"],
63
+ })
64
+ // Allows finding messages by vector embedding id
65
+ .index("embeddingId", ["embeddingId"]),
66
+
67
+ steps: defineTable({
68
+ chatId: v.id("chats"),
69
+ // Could be different from the order if we fail.
70
+ parentMessageId: v.id("messages"),
71
+ order: v.number(), // parent message order
72
+ stepOrder: v.number(), // step order
73
+ step: vStep,
74
+ status: vMessageStatus,
75
+ })
76
+ .index("status_chatId_order_stepOrder", [
77
+ "status",
78
+ "chatId",
79
+ "order",
80
+ "stepOrder",
81
+ ])
82
+ .index("parentMessageId_order_stepOrder", [
83
+ "parentMessageId",
84
+ "order",
85
+ "stepOrder",
86
+ ]),
87
+
88
+ files: defineTable({
89
+ storageId: v.string(),
90
+ hash: v.string(),
91
+ refcount: v.number(),
92
+ })
93
+ .index("hash", ["hash"])
94
+ .index("refcount", ["refcount"]),
95
+ ...vectorTables,
96
+ });
97
+
98
+ export const vv = typedV(schema);
99
+ export { vv as v };
100
+
101
+ export default schema;
@@ -0,0 +1,5 @@
1
+ /// <reference types="vite/client" />
2
+ import { test } from "vitest";
3
+ export const modules = import.meta.glob("./**/*.*s");
4
+
5
+ test("setup", () => {});
@@ -0,0 +1,92 @@
1
+ import { literals } from "convex-helpers/validators";
2
+ import {
3
+ defineTable,
4
+ GenericTableSearchIndexes,
5
+ TableDefinition,
6
+ } from "convex/server";
7
+ import { GenericId, ObjectType, v, VId, VObject, VUnion } from "convex/values";
8
+ import { QueryCtx } from "../_generated/server";
9
+
10
+ // We only generate embeddings for non-tool, non-system messages
11
+ const embeddings = {
12
+ model: v.string(),
13
+ kind: v.union(v.literal("chat"), v.literal("memory")),
14
+ userId: v.optional(v.string()),
15
+ chatId: v.optional(v.string()),
16
+ // not set for private chats
17
+ model_kind_userId: v.optional(v.array(v.string())),
18
+ model_kind_chatId: v.optional(v.array(v.string())),
19
+ vector: v.array(v.number()),
20
+ };
21
+
22
+ function table<D extends number>(dimensions: D): Table<D> {
23
+ return defineTable(embeddings).vectorIndex("vector", {
24
+ vectorField: "vector",
25
+ dimensions,
26
+ filterFields: ["model_kind_userId", "model_kind_chatId"],
27
+ });
28
+ }
29
+
30
+ export const VectorDimensions = [
31
+ 128, 256, 512, 768, 1024, 1536, 2048, 3072, 4096,
32
+ ] as const;
33
+ export type VectorDimension = (typeof VectorDimensions)[number];
34
+ export const VectorTableNames = VectorDimensions.map(
35
+ (d) => `embeddings_${d}`
36
+ ) as `embeddings_${(typeof VectorDimensions)[number]}`[];
37
+ export type VectorTableName = (typeof VectorTableNames)[number];
38
+ export type VectorTableId = GenericId<(typeof VectorTableNames)[number]>;
39
+
40
+ export const vVectorDimension = literals(...VectorDimensions);
41
+ export const vVectorTableName = literals(...VectorTableNames);
42
+ export const vVectorId = v.union(
43
+ ...VectorTableNames.map((name) => v.id(name))
44
+ ) as VUnion<
45
+ GenericId<(typeof VectorTableNames)[number]>,
46
+ VId<(typeof VectorTableNames)[number]>[]
47
+ >;
48
+
49
+ type Table<D extends number> = TableDefinition<
50
+ VObject<ObjectType<typeof embeddings>, typeof embeddings>,
51
+ { id: ["id"] },
52
+ GenericTableSearchIndexes,
53
+ VectorIndex<D>
54
+ >;
55
+
56
+ type VectorIndex<D extends number> = {
57
+ vector: {
58
+ vectorField: "vector";
59
+ dimensions: D;
60
+ filterFields: string;
61
+ };
62
+ };
63
+
64
+ export function getVectorTableName(dimension: VectorDimension) {
65
+ return `embeddings_${dimension}` as VectorTableName;
66
+ }
67
+ export function getVectorIdInfo(ctx: QueryCtx, id: VectorTableId) {
68
+ for (const dimension of VectorDimensions) {
69
+ const tableName = getVectorTableName(dimension);
70
+ if (ctx.db.normalizeId(tableName, id)) {
71
+ return { tableName, dimension };
72
+ }
73
+ }
74
+ throw new Error(`Unknown vector table id: ${id}`);
75
+ }
76
+
77
+ const tables: {
78
+ [K in keyof typeof VectorDimensions &
79
+ number as `embeddings_${(typeof VectorDimensions)[K]}`]: Table<
80
+ (typeof VectorDimensions)[K]
81
+ >;
82
+ } = Object.fromEntries(
83
+ VectorDimensions.map((dimensions) => [
84
+ `embeddings_${dimensions}`,
85
+ table(dimensions),
86
+ ])
87
+ ) as Record<
88
+ `embeddings_${(typeof VectorDimensions)[number]}`,
89
+ Table<(typeof VectorDimensions)[number]>
90
+ >;
91
+
92
+ export default tables;
package/src/mapping.ts ADDED
@@ -0,0 +1,160 @@
1
+ import type {
2
+ AssistantContent,
3
+ CoreAssistantMessage,
4
+ CoreMessage,
5
+ CoreToolMessage,
6
+ DataContent,
7
+ GenerateTextResult,
8
+ StepResult,
9
+ ToolContent,
10
+ ToolSet,
11
+ UserContent,
12
+ } from "ai";
13
+ import { MessageWithFileAndId, Step } from "./validators";
14
+
15
+ export type SerializeUrlsAndUint8Arrays<T> = T extends URL
16
+ ? string
17
+ : T extends Uint8Array | ArrayBufferLike
18
+ ? ArrayBuffer
19
+ : T extends Array<infer Inner>
20
+ ? Array<SerializeUrlsAndUint8Arrays<Inner>>
21
+ : // eslint-disable-next-line @typescript-eslint/no-explicit-any
22
+ T extends Record<string, any>
23
+ ? { [K in keyof T]: SerializeUrlsAndUint8Arrays<T[K]> }
24
+ : T;
25
+
26
+ export type Content = UserContent | AssistantContent | ToolContent;
27
+ export type SerializedContent = SerializeUrlsAndUint8Arrays<Content>;
28
+
29
+ export type SerializedMessage = SerializeUrlsAndUint8Arrays<CoreMessage>;
30
+
31
+ export function serializeMessage(
32
+ messageWithId: CoreMessage & { id?: string }
33
+ ): SerializedMessage {
34
+ const { id: _, ...message } = messageWithId;
35
+ const content = message.content;
36
+ return {
37
+ ...message,
38
+ content: serializeContent(content),
39
+ } as SerializedMessage;
40
+ }
41
+
42
+ export function serializeMessageWithId(
43
+ messageWithId: CoreMessage & { id?: string }
44
+ ): { message: SerializedMessage; id: string | undefined } {
45
+ return { message: serializeMessage(messageWithId), id: messageWithId.id };
46
+ }
47
+
48
+ export function serializeContent(content: Content): SerializedContent {
49
+ if (typeof content === "string") {
50
+ return content;
51
+ }
52
+ const serialized = content.map((part) => {
53
+ switch (part.type) {
54
+ case "image":
55
+ return { ...part, image: serializeDataOrUrl(part.image) };
56
+ case "file":
57
+ return { ...part, file: serializeDataOrUrl(part.data) };
58
+ default:
59
+ return part;
60
+ }
61
+ });
62
+ return serialized as SerializedContent;
63
+ }
64
+
65
+ export function serializeResponse<TOOLS extends ToolSet, OUTPUT>(
66
+ response: GenerateTextResult<TOOLS, OUTPUT>["response"]
67
+ ): { message: SerializedMessage; id?: string }[] {
68
+ const { id, timestamp, modelId, headers, messages, body } = response;
69
+ // TODO: what to do about all the rest?
70
+ // Store body?
71
+ return messages.map((m) => serializeMessageWithId(m));
72
+ }
73
+
74
+ export function serializeStep<TOOLS extends ToolSet>(
75
+ step: StepResult<TOOLS>
76
+ ): Step {
77
+ const content = step.response?.messages.map((message) => {
78
+ return serializeMessageWithId(message);
79
+ });
80
+ const timestamp = step.response?.timestamp.getTime();
81
+ const response = {
82
+ ...step.response,
83
+ messages: content,
84
+ timestamp,
85
+ headers: {},
86
+ };
87
+ return {
88
+ ...step,
89
+ response,
90
+ };
91
+ }
92
+
93
+ export function serializeNewMessagesInStep<TOOLS extends ToolSet>(
94
+ step: StepResult<TOOLS>
95
+ ): MessageWithFileAndId[] {
96
+ const messages: MessageWithFileAndId[] = [];
97
+ if (step.text) {
98
+ messages.push(serializeMessageWithId(step.response.messages.at(-1)!));
99
+ }
100
+ // TODO: get ID from regular messages
101
+ if (step.toolCalls || step.toolResults) {
102
+ messages.push(
103
+ ...step.response.messages
104
+ .slice(
105
+ 0,
106
+ -((step.toolCalls?.length ?? 0) + (step.toolResults?.length ?? 0))
107
+ )
108
+ .map((m) => serializeMessageWithId(m))
109
+ );
110
+ }
111
+ return messages;
112
+ }
113
+
114
+ export function deserializeContent(content: SerializedContent): Content {
115
+ if (typeof content === "string") {
116
+ return content;
117
+ }
118
+ return content.map((part) => {
119
+ switch (part.type) {
120
+ case "image":
121
+ return { ...part, file: deserializeUrl(part.image) };
122
+ case "file":
123
+ return { ...part, file: deserializeUrl(part.data) };
124
+ default:
125
+ return part;
126
+ }
127
+ }) as Content;
128
+ }
129
+
130
+ // TODO: store in file storage if it's big
131
+ function serializeDataOrUrl(
132
+ dataOrUrl: DataContent | URL
133
+ ): ArrayBuffer | string {
134
+ if (typeof dataOrUrl === "string") {
135
+ return dataOrUrl;
136
+ }
137
+ if (dataOrUrl instanceof ArrayBuffer) {
138
+ return dataOrUrl; // Already an ArrayBuffer
139
+ }
140
+ if (dataOrUrl instanceof URL) {
141
+ return dataOrUrl.toString();
142
+ }
143
+ return dataOrUrl.buffer.slice(
144
+ dataOrUrl.byteOffset,
145
+ dataOrUrl.byteOffset + dataOrUrl.byteLength
146
+ ) as ArrayBuffer;
147
+ }
148
+
149
+ function deserializeUrl(urlOrString: string | ArrayBuffer): URL | DataContent {
150
+ if (typeof urlOrString === "string") {
151
+ if (
152
+ urlOrString.startsWith("http://") ||
153
+ urlOrString.startsWith("https://")
154
+ ) {
155
+ return new URL(urlOrString);
156
+ }
157
+ return urlOrString;
158
+ }
159
+ return urlOrString;
160
+ }
@@ -0,0 +1,8 @@
1
+ // This is where React components go.
2
+ if (typeof window === "undefined") {
3
+ throw new Error("this is frontend code, but it's running somewhere else!");
4
+ }
5
+
6
+ export function subtract(a: number, b: number): number {
7
+ return a - b;
8
+ }
package/src/shared.ts ADDED
@@ -0,0 +1,35 @@
1
+ import { CoreMessage } from "ai";
2
+ import { Message } from "./validators";
3
+
4
+ export function isTool(message: Message | CoreMessage) {
5
+ return (
6
+ message.role === "tool" ||
7
+ (message.role === "assistant" &&
8
+ Array.isArray(message.content) &&
9
+ message.content.some((c) => c.type === "tool-call"))
10
+ );
11
+ }
12
+
13
+ export function extractText(message: Message | CoreMessage) {
14
+ switch (message.role) {
15
+ case "user":
16
+ if (typeof message.content === "string") {
17
+ return message.content;
18
+ }
19
+ return message.content
20
+ .filter((c) => c.type === "text")
21
+ .map((c) => c.text)
22
+ .join("");
23
+ case "assistant":
24
+ if (typeof message.content === "string") {
25
+ return message.content;
26
+ }
27
+ return message.content
28
+ .filter((c) => c.type === "text")
29
+ .map((c) => c.text)
30
+ .join("");
31
+ }
32
+ return undefined;
33
+ }
34
+
35
+ export const DEFAULT_MESSAGE_RANGE = { before: 2, after: 1 };
@@ -0,0 +1,101 @@
1
+ import { Infer } from "convex/values";
2
+ import { expectTypeOf, test } from "vitest";
3
+ import {
4
+ vAssistantContent,
5
+ vAssistantMessage,
6
+ vFilePart,
7
+ vImagePart,
8
+ vMessage,
9
+ vReasoningPart,
10
+ vRedactedReasoningPart,
11
+ vSystemMessage,
12
+ vTextPart,
13
+ vToolCallPart,
14
+ vToolContent,
15
+ vToolMessage,
16
+ vUserMessage,
17
+ } from "./validators";
18
+ import { vUserContent } from "./validators";
19
+ import {
20
+ AssistantContent,
21
+ CoreAssistantMessage,
22
+ CoreMessage,
23
+ CoreSystemMessage,
24
+ CoreToolMessage,
25
+ CoreUserMessage,
26
+ FilePart,
27
+ ImagePart,
28
+ TextPart,
29
+ ToolCallPart,
30
+ ToolContent,
31
+ UserContent,
32
+ } from "ai";
33
+ import { SerializeUrlsAndUint8Arrays } from "./mapping";
34
+
35
+ // type assertion
36
+ type OurUserContent = SerializeUrlsAndUint8Arrays<UserContent>;
37
+ expectTypeOf<OurUserContent>().toExtend<Infer<typeof vUserContent>>();
38
+ expectTypeOf<Infer<typeof vUserContent>>().toExtend<OurUserContent>();
39
+
40
+ type OurAssistantContent = SerializeUrlsAndUint8Arrays<AssistantContent>;
41
+ expectTypeOf<OurAssistantContent>().toExtend<Infer<typeof vAssistantContent>>();
42
+ expectTypeOf<Infer<typeof vAssistantContent>>().toExtend<OurAssistantContent>();
43
+
44
+ type OurToolContent = SerializeUrlsAndUint8Arrays<ToolContent>;
45
+ expectTypeOf<OurToolContent>().toExtend<Infer<typeof vToolContent>>();
46
+ expectTypeOf<Infer<typeof vToolContent>>().toExtend<OurToolContent>();
47
+
48
+ expectTypeOf<Infer<typeof vToolCallPart>>().toExtend<ToolCallPart>();
49
+ expectTypeOf<ToolCallPart>().toExtend<Infer<typeof vToolCallPart>>();
50
+
51
+ type OurTextPart = SerializeUrlsAndUint8Arrays<TextPart>;
52
+ expectTypeOf<OurTextPart>().toExtend<Infer<typeof vTextPart>>();
53
+ expectTypeOf<Infer<typeof vTextPart>>().toExtend<OurTextPart>();
54
+
55
+ type OurImagePart = SerializeUrlsAndUint8Arrays<ImagePart>;
56
+ expectTypeOf<OurImagePart>().toExtend<Infer<typeof vImagePart>>();
57
+ expectTypeOf<Infer<typeof vImagePart>>().toExtend<OurImagePart>();
58
+
59
+ type OurFilePart = SerializeUrlsAndUint8Arrays<FilePart>;
60
+ expectTypeOf<OurFilePart>().toExtend<Infer<typeof vFilePart>>();
61
+ expectTypeOf<Infer<typeof vFilePart>>().toExtend<OurFilePart>();
62
+
63
+ // narrow to the type
64
+ type ReasoningPart = AssistantContent[number] & { type: "reasoning" } & object;
65
+ type OurReasoningPart = SerializeUrlsAndUint8Arrays<ReasoningPart>;
66
+ expectTypeOf<OurReasoningPart>().toExtend<Infer<typeof vReasoningPart>>();
67
+ expectTypeOf<Infer<typeof vReasoningPart>>().toExtend<OurReasoningPart>();
68
+
69
+ // narrow to the type
70
+ type RedactedReasoningPart = AssistantContent[number] & {
71
+ type: "redacted-reasoning";
72
+ } & object;
73
+ type OurRedactedReasoningPart =
74
+ SerializeUrlsAndUint8Arrays<RedactedReasoningPart>;
75
+ expectTypeOf<OurRedactedReasoningPart>().toExtend<
76
+ Infer<typeof vRedactedReasoningPart>
77
+ >();
78
+ expectTypeOf<
79
+ Infer<typeof vRedactedReasoningPart>
80
+ >().toExtend<OurRedactedReasoningPart>();
81
+
82
+ // test("noop", () => {
83
+ type OurUserMessage = SerializeUrlsAndUint8Arrays<CoreUserMessage>;
84
+ expectTypeOf<OurUserMessage>().toExtend<Infer<typeof vUserMessage>>();
85
+ expectTypeOf<Infer<typeof vUserMessage>>().toExtend<OurUserMessage>();
86
+
87
+ type OurAssistantMessage = SerializeUrlsAndUint8Arrays<CoreAssistantMessage>;
88
+ expectTypeOf<OurAssistantMessage>().toExtend<Infer<typeof vAssistantMessage>>();
89
+ expectTypeOf<Infer<typeof vAssistantMessage>>().toExtend<OurAssistantMessage>();
90
+
91
+ expectTypeOf<Infer<typeof vToolMessage>>().toExtend<CoreToolMessage>();
92
+ expectTypeOf<CoreToolMessage>().toExtend<Infer<typeof vToolMessage>>();
93
+
94
+ expectTypeOf<Infer<typeof vSystemMessage>>().toExtend<CoreSystemMessage>();
95
+ expectTypeOf<CoreSystemMessage>().toExtend<Infer<typeof vSystemMessage>>();
96
+
97
+ type OurMessage = SerializeUrlsAndUint8Arrays<CoreMessage>;
98
+ expectTypeOf<OurMessage>().toExtend<Infer<typeof vMessage>>();
99
+ expectTypeOf<Infer<typeof vMessage>>().toExtend<OurMessage>();
100
+
101
+ test("noop", () => { });