langwatch 0.0.1

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 (132) hide show
  1. package/.eslintrc.cjs +37 -0
  2. package/README.md +3 -0
  3. package/dist/chunk-GOA2HL4A.mjs +269 -0
  4. package/dist/chunk-GOA2HL4A.mjs.map +1 -0
  5. package/dist/index.d.mts +82 -0
  6. package/dist/index.d.ts +82 -0
  7. package/dist/index.js +940 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/index.mjs +666 -0
  10. package/dist/index.mjs.map +1 -0
  11. package/dist/utils-s3gGR6vj.d.mts +209 -0
  12. package/dist/utils-s3gGR6vj.d.ts +209 -0
  13. package/dist/utils.d.mts +3 -0
  14. package/dist/utils.d.ts +3 -0
  15. package/dist/utils.js +263 -0
  16. package/dist/utils.js.map +1 -0
  17. package/dist/utils.mjs +7 -0
  18. package/dist/utils.mjs.map +1 -0
  19. package/example/.env.example +12 -0
  20. package/example/.eslintrc.json +26 -0
  21. package/example/LICENSE +13 -0
  22. package/example/README.md +10 -0
  23. package/example/app/(chat)/chat/[id]/page.tsx +60 -0
  24. package/example/app/(chat)/layout.tsx +14 -0
  25. package/example/app/(chat)/page.tsx +22 -0
  26. package/example/app/actions.ts +156 -0
  27. package/example/app/globals.css +76 -0
  28. package/example/app/layout.tsx +64 -0
  29. package/example/app/login/actions.ts +71 -0
  30. package/example/app/login/page.tsx +18 -0
  31. package/example/app/new/page.tsx +5 -0
  32. package/example/app/opengraph-image.png +0 -0
  33. package/example/app/share/[id]/page.tsx +58 -0
  34. package/example/app/signup/actions.ts +111 -0
  35. package/example/app/signup/page.tsx +18 -0
  36. package/example/app/twitter-image.png +0 -0
  37. package/example/auth.config.ts +42 -0
  38. package/example/auth.ts +45 -0
  39. package/example/components/button-scroll-to-bottom.tsx +36 -0
  40. package/example/components/chat-history.tsx +49 -0
  41. package/example/components/chat-list.tsx +52 -0
  42. package/example/components/chat-message-actions.tsx +40 -0
  43. package/example/components/chat-message.tsx +80 -0
  44. package/example/components/chat-panel.tsx +139 -0
  45. package/example/components/chat-share-dialog.tsx +95 -0
  46. package/example/components/chat.tsx +84 -0
  47. package/example/components/clear-history.tsx +75 -0
  48. package/example/components/empty-screen.tsx +38 -0
  49. package/example/components/external-link.tsx +29 -0
  50. package/example/components/footer.tsx +19 -0
  51. package/example/components/header.tsx +80 -0
  52. package/example/components/login-button.tsx +42 -0
  53. package/example/components/login-form.tsx +97 -0
  54. package/example/components/markdown.tsx +9 -0
  55. package/example/components/prompt-form.tsx +115 -0
  56. package/example/components/providers.tsx +17 -0
  57. package/example/components/sidebar-actions.tsx +125 -0
  58. package/example/components/sidebar-desktop.tsx +19 -0
  59. package/example/components/sidebar-footer.tsx +16 -0
  60. package/example/components/sidebar-item.tsx +124 -0
  61. package/example/components/sidebar-items.tsx +42 -0
  62. package/example/components/sidebar-list.tsx +38 -0
  63. package/example/components/sidebar-mobile.tsx +31 -0
  64. package/example/components/sidebar-toggle.tsx +24 -0
  65. package/example/components/sidebar.tsx +21 -0
  66. package/example/components/signup-form.tsx +95 -0
  67. package/example/components/stocks/events-skeleton.tsx +31 -0
  68. package/example/components/stocks/events.tsx +30 -0
  69. package/example/components/stocks/index.tsx +36 -0
  70. package/example/components/stocks/message.tsx +134 -0
  71. package/example/components/stocks/spinner.tsx +16 -0
  72. package/example/components/stocks/stock-purchase.tsx +146 -0
  73. package/example/components/stocks/stock-skeleton.tsx +22 -0
  74. package/example/components/stocks/stock.tsx +210 -0
  75. package/example/components/stocks/stocks-skeleton.tsx +9 -0
  76. package/example/components/stocks/stocks.tsx +67 -0
  77. package/example/components/tailwind-indicator.tsx +14 -0
  78. package/example/components/theme-toggle.tsx +31 -0
  79. package/example/components/ui/alert-dialog.tsx +141 -0
  80. package/example/components/ui/badge.tsx +36 -0
  81. package/example/components/ui/button.tsx +57 -0
  82. package/example/components/ui/codeblock.tsx +148 -0
  83. package/example/components/ui/dialog.tsx +122 -0
  84. package/example/components/ui/dropdown-menu.tsx +205 -0
  85. package/example/components/ui/icons.tsx +507 -0
  86. package/example/components/ui/input.tsx +25 -0
  87. package/example/components/ui/label.tsx +26 -0
  88. package/example/components/ui/select.tsx +164 -0
  89. package/example/components/ui/separator.tsx +31 -0
  90. package/example/components/ui/sheet.tsx +140 -0
  91. package/example/components/ui/sonner.tsx +31 -0
  92. package/example/components/ui/switch.tsx +29 -0
  93. package/example/components/ui/textarea.tsx +24 -0
  94. package/example/components/ui/tooltip.tsx +30 -0
  95. package/example/components/user-menu.tsx +53 -0
  96. package/example/components.json +17 -0
  97. package/example/lib/chat/actions.tsx +606 -0
  98. package/example/lib/hooks/use-copy-to-clipboard.tsx +33 -0
  99. package/example/lib/hooks/use-enter-submit.tsx +23 -0
  100. package/example/lib/hooks/use-local-storage.ts +24 -0
  101. package/example/lib/hooks/use-scroll-anchor.tsx +86 -0
  102. package/example/lib/hooks/use-sidebar.tsx +60 -0
  103. package/example/lib/hooks/use-streamable-text.ts +25 -0
  104. package/example/lib/types.ts +41 -0
  105. package/example/lib/utils.ts +89 -0
  106. package/example/middleware.ts +8 -0
  107. package/example/next-env.d.ts +5 -0
  108. package/example/next.config.js +13 -0
  109. package/example/package-lock.json +9249 -0
  110. package/example/package.json +77 -0
  111. package/example/pnpm-lock.yaml +5712 -0
  112. package/example/postcss.config.js +6 -0
  113. package/example/prettier.config.cjs +34 -0
  114. package/example/public/apple-touch-icon.png +0 -0
  115. package/example/public/favicon-16x16.png +0 -0
  116. package/example/public/favicon.ico +0 -0
  117. package/example/public/next.svg +1 -0
  118. package/example/public/thirteen.svg +1 -0
  119. package/example/public/vercel.svg +1 -0
  120. package/example/tailwind.config.ts +81 -0
  121. package/example/tsconfig.json +35 -0
  122. package/package.json +45 -0
  123. package/src/helpers.ts +64 -0
  124. package/src/index.test.ts +255 -0
  125. package/src/index.ts +397 -0
  126. package/src/server/types/.gitkeep +0 -0
  127. package/src/types.ts +69 -0
  128. package/src/utils.ts +134 -0
  129. package/ts-to-zod.config.js +18 -0
  130. package/tsconfig.json +32 -0
  131. package/tsup.config.ts +10 -0
  132. package/vitest.config.ts +8 -0
package/dist/utils.js ADDED
@@ -0,0 +1,263 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJS = (cb, mod) => function __require() {
9
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+
33
+ // node_modules/secure-json-parse/index.js
34
+ var require_secure_json_parse = __commonJS({
35
+ "node_modules/secure-json-parse/index.js"(exports2, module2) {
36
+ "use strict";
37
+ var hasBuffer = typeof Buffer !== "undefined";
38
+ var suspectProtoRx = /"(?:_|\\u005[Ff])(?:_|\\u005[Ff])(?:p|\\u0070)(?:r|\\u0072)(?:o|\\u006[Ff])(?:t|\\u0074)(?:o|\\u006[Ff])(?:_|\\u005[Ff])(?:_|\\u005[Ff])"\s*:/;
39
+ var suspectConstructorRx = /"(?:c|\\u0063)(?:o|\\u006[Ff])(?:n|\\u006[Ee])(?:s|\\u0073)(?:t|\\u0074)(?:r|\\u0072)(?:u|\\u0075)(?:c|\\u0063)(?:t|\\u0074)(?:o|\\u006[Ff])(?:r|\\u0072)"\s*:/;
40
+ function _parse(text, reviver, options) {
41
+ if (options == null) {
42
+ if (reviver !== null && typeof reviver === "object") {
43
+ options = reviver;
44
+ reviver = void 0;
45
+ }
46
+ }
47
+ if (hasBuffer && Buffer.isBuffer(text)) {
48
+ text = text.toString();
49
+ }
50
+ if (text && text.charCodeAt(0) === 65279) {
51
+ text = text.slice(1);
52
+ }
53
+ const obj = JSON.parse(text, reviver);
54
+ if (obj === null || typeof obj !== "object") {
55
+ return obj;
56
+ }
57
+ const protoAction = options && options.protoAction || "error";
58
+ const constructorAction = options && options.constructorAction || "error";
59
+ if (protoAction === "ignore" && constructorAction === "ignore") {
60
+ return obj;
61
+ }
62
+ if (protoAction !== "ignore" && constructorAction !== "ignore") {
63
+ if (suspectProtoRx.test(text) === false && suspectConstructorRx.test(text) === false) {
64
+ return obj;
65
+ }
66
+ } else if (protoAction !== "ignore" && constructorAction === "ignore") {
67
+ if (suspectProtoRx.test(text) === false) {
68
+ return obj;
69
+ }
70
+ } else {
71
+ if (suspectConstructorRx.test(text) === false) {
72
+ return obj;
73
+ }
74
+ }
75
+ return filter(obj, { protoAction, constructorAction, safe: options && options.safe });
76
+ }
77
+ function filter(obj, { protoAction = "error", constructorAction = "error", safe } = {}) {
78
+ let next = [obj];
79
+ while (next.length) {
80
+ const nodes = next;
81
+ next = [];
82
+ for (const node of nodes) {
83
+ if (protoAction !== "ignore" && Object.prototype.hasOwnProperty.call(node, "__proto__")) {
84
+ if (safe === true) {
85
+ return null;
86
+ } else if (protoAction === "error") {
87
+ throw new SyntaxError("Object contains forbidden prototype property");
88
+ }
89
+ delete node.__proto__;
90
+ }
91
+ if (constructorAction !== "ignore" && Object.prototype.hasOwnProperty.call(node, "constructor") && Object.prototype.hasOwnProperty.call(node.constructor, "prototype")) {
92
+ if (safe === true) {
93
+ return null;
94
+ } else if (constructorAction === "error") {
95
+ throw new SyntaxError("Object contains forbidden prototype property");
96
+ }
97
+ delete node.constructor;
98
+ }
99
+ for (const key in node) {
100
+ const value = node[key];
101
+ if (value && typeof value === "object") {
102
+ next.push(value);
103
+ }
104
+ }
105
+ }
106
+ }
107
+ return obj;
108
+ }
109
+ function parse(text, reviver, options) {
110
+ const stackTraceLimit = Error.stackTraceLimit;
111
+ Error.stackTraceLimit = 0;
112
+ try {
113
+ return _parse(text, reviver, options);
114
+ } finally {
115
+ Error.stackTraceLimit = stackTraceLimit;
116
+ }
117
+ }
118
+ function safeParse(text, reviver) {
119
+ const stackTraceLimit = Error.stackTraceLimit;
120
+ Error.stackTraceLimit = 0;
121
+ try {
122
+ return _parse(text, reviver, { safe: true });
123
+ } catch (_e) {
124
+ return null;
125
+ } finally {
126
+ Error.stackTraceLimit = stackTraceLimit;
127
+ }
128
+ }
129
+ module2.exports = parse;
130
+ module2.exports.default = parse;
131
+ module2.exports.parse = parse;
132
+ module2.exports.safeParse = safeParse;
133
+ module2.exports.scan = filter;
134
+ }
135
+ });
136
+
137
+ // src/utils.ts
138
+ var utils_exports = {};
139
+ __export(utils_exports, {
140
+ convertFromVercelAIMessages: () => convertFromVercelAIMessages
141
+ });
142
+ module.exports = __toCommonJS(utils_exports);
143
+
144
+ // node_modules/@ai-sdk/provider-utils/dist/index.mjs
145
+ var import_non_secure = require("nanoid/non-secure");
146
+ var import_secure_json_parse = __toESM(require_secure_json_parse(), 1);
147
+ var generateId = (0, import_non_secure.customAlphabet)(
148
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
149
+ 7
150
+ );
151
+ function convertUint8ArrayToBase64(array) {
152
+ let latin1string = "";
153
+ for (let i = 0; i < array.length; i++) {
154
+ latin1string += String.fromCodePoint(array[i]);
155
+ }
156
+ return globalThis.btoa(latin1string);
157
+ }
158
+
159
+ // src/utils.ts
160
+ var convertImageToUrl = (image, mimeType) => {
161
+ try {
162
+ return image instanceof URL ? image.toString() : typeof image === "string" ? image : `data:${mimeType != null ? mimeType : "image/jpeg"};base64,${convertUint8ArrayToBase64(
163
+ image
164
+ )}`;
165
+ } catch (e) {
166
+ console.error("[LangWatch] error converting vercel ui image to url:", e);
167
+ return "";
168
+ }
169
+ };
170
+ function convertFromVercelAIMessages(messages) {
171
+ var _a;
172
+ const lwMessages = [];
173
+ for (const { role, content } of messages) {
174
+ switch (role) {
175
+ case "system": {
176
+ lwMessages.push({ role: "system", content });
177
+ break;
178
+ }
179
+ case "user": {
180
+ if (Array.isArray(content) && content.length === 1 && ((_a = content[0]) == null ? void 0 : _a.type) === "text") {
181
+ lwMessages.push({ role: "user", content: content[0].text });
182
+ break;
183
+ }
184
+ lwMessages.push({
185
+ role: "user",
186
+ content: Array.isArray(content) ? content.map((part) => {
187
+ switch (part.type) {
188
+ case "text": {
189
+ return { type: "text", text: part.text };
190
+ }
191
+ case "image": {
192
+ return {
193
+ type: "image_url",
194
+ image_url: {
195
+ url: convertImageToUrl(part.image, part.mimeType)
196
+ }
197
+ };
198
+ }
199
+ }
200
+ }) : content
201
+ });
202
+ break;
203
+ }
204
+ case "assistant": {
205
+ let text = "";
206
+ const toolCalls = [];
207
+ if (Array.isArray(content)) {
208
+ for (const part of content) {
209
+ switch (part.type) {
210
+ case "text": {
211
+ text += part.text;
212
+ break;
213
+ }
214
+ case "tool-call": {
215
+ toolCalls.push({
216
+ id: part.toolCallId,
217
+ type: "function",
218
+ function: {
219
+ name: part.toolName,
220
+ arguments: JSON.stringify(part.args)
221
+ }
222
+ });
223
+ break;
224
+ }
225
+ default: {
226
+ const _exhaustiveCheck = part;
227
+ throw new Error(`Unsupported part: ${_exhaustiveCheck}`);
228
+ }
229
+ }
230
+ }
231
+ } else {
232
+ text = content;
233
+ }
234
+ lwMessages.push({
235
+ role: "assistant",
236
+ content: text,
237
+ tool_calls: toolCalls.length > 0 ? toolCalls : void 0
238
+ });
239
+ break;
240
+ }
241
+ case "tool": {
242
+ for (const toolResponse of content) {
243
+ lwMessages.push({
244
+ role: "tool",
245
+ tool_call_id: toolResponse.toolCallId,
246
+ content: JSON.stringify(toolResponse.result)
247
+ });
248
+ }
249
+ break;
250
+ }
251
+ default: {
252
+ const _exhaustiveCheck = role;
253
+ throw new Error(`Unsupported role: ${_exhaustiveCheck}`);
254
+ }
255
+ }
256
+ }
257
+ return lwMessages;
258
+ }
259
+ // Annotate the CommonJS export names for ESM import in node:
260
+ 0 && (module.exports = {
261
+ convertFromVercelAIMessages
262
+ });
263
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../node_modules/secure-json-parse/index.js","../src/utils.ts","../node_modules/@ai-sdk/provider-utils/src/convert-async-generator-to-readable-stream.ts","../node_modules/@ai-sdk/provider-utils/src/extract-response-headers.ts","../node_modules/@ai-sdk/provider-utils/src/generate-id.ts","../node_modules/@ai-sdk/provider-utils/src/get-error-message.ts","../node_modules/@ai-sdk/provider-utils/src/is-abort-error.ts","../node_modules/@ai-sdk/provider-utils/src/load-api-key.ts","../node_modules/@ai-sdk/provider-utils/src/load-setting.ts","../node_modules/@ai-sdk/provider-utils/src/parse-json.ts","../node_modules/@ai-sdk/provider-utils/src/validate-types.ts","../node_modules/@ai-sdk/provider-utils/src/post-to-api.ts","../node_modules/@ai-sdk/provider-utils/src/response-handler.ts","../node_modules/@ai-sdk/provider-utils/src/uint8-utils.ts","../node_modules/@ai-sdk/provider-utils/src/without-trailing-slash.ts"],"sourcesContent":["'use strict'\n\nconst hasBuffer = typeof Buffer !== 'undefined'\nconst suspectProtoRx = /\"(?:_|\\\\u005[Ff])(?:_|\\\\u005[Ff])(?:p|\\\\u0070)(?:r|\\\\u0072)(?:o|\\\\u006[Ff])(?:t|\\\\u0074)(?:o|\\\\u006[Ff])(?:_|\\\\u005[Ff])(?:_|\\\\u005[Ff])\"\\s*:/\nconst suspectConstructorRx = /\"(?:c|\\\\u0063)(?:o|\\\\u006[Ff])(?:n|\\\\u006[Ee])(?:s|\\\\u0073)(?:t|\\\\u0074)(?:r|\\\\u0072)(?:u|\\\\u0075)(?:c|\\\\u0063)(?:t|\\\\u0074)(?:o|\\\\u006[Ff])(?:r|\\\\u0072)\"\\s*:/\n\nfunction _parse (text, reviver, options) {\n // Normalize arguments\n if (options == null) {\n if (reviver !== null && typeof reviver === 'object') {\n options = reviver\n reviver = undefined\n }\n }\n\n if (hasBuffer && Buffer.isBuffer(text)) {\n text = text.toString()\n }\n\n // BOM checker\n if (text && text.charCodeAt(0) === 0xFEFF) {\n text = text.slice(1)\n }\n\n // Parse normally, allowing exceptions\n const obj = JSON.parse(text, reviver)\n\n // Ignore null and non-objects\n if (obj === null || typeof obj !== 'object') {\n return obj\n }\n\n const protoAction = (options && options.protoAction) || 'error'\n const constructorAction = (options && options.constructorAction) || 'error'\n\n // options: 'error' (default) / 'remove' / 'ignore'\n if (protoAction === 'ignore' && constructorAction === 'ignore') {\n return obj\n }\n\n if (protoAction !== 'ignore' && constructorAction !== 'ignore') {\n if (suspectProtoRx.test(text) === false && suspectConstructorRx.test(text) === false) {\n return obj\n }\n } else if (protoAction !== 'ignore' && constructorAction === 'ignore') {\n if (suspectProtoRx.test(text) === false) {\n return obj\n }\n } else {\n if (suspectConstructorRx.test(text) === false) {\n return obj\n }\n }\n\n // Scan result for proto keys\n return filter(obj, { protoAction, constructorAction, safe: options && options.safe })\n}\n\nfunction filter (obj, { protoAction = 'error', constructorAction = 'error', safe } = {}) {\n let next = [obj]\n\n while (next.length) {\n const nodes = next\n next = []\n\n for (const node of nodes) {\n if (protoAction !== 'ignore' && Object.prototype.hasOwnProperty.call(node, '__proto__')) { // Avoid calling node.hasOwnProperty directly\n if (safe === true) {\n return null\n } else if (protoAction === 'error') {\n throw new SyntaxError('Object contains forbidden prototype property')\n }\n\n delete node.__proto__ // eslint-disable-line no-proto\n }\n\n if (constructorAction !== 'ignore' &&\n Object.prototype.hasOwnProperty.call(node, 'constructor') &&\n Object.prototype.hasOwnProperty.call(node.constructor, 'prototype')) { // Avoid calling node.hasOwnProperty directly\n if (safe === true) {\n return null\n } else if (constructorAction === 'error') {\n throw new SyntaxError('Object contains forbidden prototype property')\n }\n\n delete node.constructor\n }\n\n for (const key in node) {\n const value = node[key]\n if (value && typeof value === 'object') {\n next.push(value)\n }\n }\n }\n }\n return obj\n}\n\nfunction parse (text, reviver, options) {\n const stackTraceLimit = Error.stackTraceLimit\n Error.stackTraceLimit = 0\n try {\n return _parse(text, reviver, options)\n } finally {\n Error.stackTraceLimit = stackTraceLimit\n }\n}\n\nfunction safeParse (text, reviver) {\n const stackTraceLimit = Error.stackTraceLimit\n Error.stackTraceLimit = 0\n try {\n return _parse(text, reviver, { safe: true })\n } catch (_e) {\n return null\n } finally {\n Error.stackTraceLimit = stackTraceLimit\n }\n}\n\nmodule.exports = parse\nmodule.exports.default = parse\nmodule.exports.parse = parse\nmodule.exports.safeParse = safeParse\nmodule.exports.scan = filter\n","import { convertUint8ArrayToBase64 } from \"@ai-sdk/provider-utils\";\nimport { type ImagePart, type CoreMessage } from \"ai\";\nimport { type ChatMessage } from \"./types\";\n\nconst convertImageToUrl = (\n image: ImagePart[\"image\"],\n mimeType: string | undefined\n) => {\n try {\n return image instanceof URL\n ? image.toString()\n : typeof image === \"string\"\n ? image\n : `data:${mimeType ?? \"image/jpeg\"};base64,${convertUint8ArrayToBase64(\n image as any\n )}`;\n } catch (e) {\n console.error(\"[LangWatch] error converting vercel ui image to url:\", e);\n return \"\";\n }\n};\n\n// Mostly copied from https://github.com/vercel/ai/blob/main/packages/openai/src/convert-to-openai-chat-messages.ts\nexport function convertFromVercelAIMessages(\n messages: CoreMessage[]\n): ChatMessage[] {\n const lwMessages: ChatMessage[] = [];\n\n for (const { role, content } of messages) {\n switch (role) {\n case \"system\": {\n lwMessages.push({ role: \"system\", content });\n break;\n }\n\n case \"user\": {\n if (\n Array.isArray(content) &&\n content.length === 1 &&\n content[0]?.type === \"text\"\n ) {\n lwMessages.push({ role: \"user\", content: content[0].text });\n break;\n }\n\n lwMessages.push({\n role: \"user\",\n content: Array.isArray(content)\n ? content.map((part) => {\n switch (part.type) {\n case \"text\": {\n return { type: \"text\", text: part.text };\n }\n case \"image\": {\n return {\n type: \"image_url\",\n image_url: {\n url: convertImageToUrl(part.image, part.mimeType),\n },\n };\n }\n }\n })\n : content,\n });\n\n break;\n }\n\n case \"assistant\": {\n let text = \"\";\n const toolCalls: Array<{\n id: string;\n type: \"function\";\n function: { name: string; arguments: string };\n }> = [];\n\n if (Array.isArray(content)) {\n for (const part of content) {\n switch (part.type) {\n case \"text\": {\n text += part.text;\n break;\n }\n case \"tool-call\": {\n toolCalls.push({\n id: part.toolCallId,\n type: \"function\",\n function: {\n name: part.toolName,\n arguments: JSON.stringify(part.args),\n },\n });\n break;\n }\n default: {\n const _exhaustiveCheck = part;\n throw new Error(`Unsupported part: ${_exhaustiveCheck as any}`);\n }\n }\n }\n } else {\n text = content;\n }\n\n lwMessages.push({\n role: \"assistant\",\n content: text,\n tool_calls: toolCalls.length > 0 ? toolCalls : undefined,\n });\n\n break;\n }\n\n case \"tool\": {\n for (const toolResponse of content) {\n lwMessages.push({\n role: \"tool\",\n tool_call_id: toolResponse.toolCallId,\n content: JSON.stringify(toolResponse.result),\n });\n }\n break;\n }\n\n default: {\n const _exhaustiveCheck = role;\n throw new Error(`Unsupported role: ${_exhaustiveCheck as any}`);\n }\n }\n }\n\n return lwMessages;\n}\n","/**\n * Converts an AsyncGenerator to a ReadableStream.\n *\n * @template T - The type of elements produced by the AsyncGenerator.\n * @param {AsyncGenerator<T>} stream - The AsyncGenerator to convert.\n * @returns {ReadableStream<T>} - A ReadableStream that provides the same data as the AsyncGenerator.\n */\nexport function convertAsyncGeneratorToReadableStream<T>(\n stream: AsyncGenerator<T>,\n): ReadableStream<T> {\n return new ReadableStream<T>({\n /**\n * Called when the consumer wants to pull more data from the stream.\n *\n * @param {ReadableStreamDefaultController<T>} controller - The controller to enqueue data into the stream.\n * @returns {Promise<void>}\n */\n async pull(controller) {\n try {\n const { value, done } = await stream.next();\n if (done) {\n controller.close();\n } else {\n controller.enqueue(value);\n }\n } catch (error) {\n controller.error(error);\n }\n },\n /**\n * Called when the consumer cancels the stream.\n */\n cancel() {},\n });\n}\n","/**\nExtracts the headers from a response object and returns them as a key-value object.\n\n@param response - The response object to extract headers from.\n@returns The headers as a key-value object.\n*/\nexport function extractResponseHeaders(\n response: Response,\n): Record<string, string> {\n const headers: Record<string, string> = {};\n response.headers.forEach((value, key) => {\n headers[key] = value;\n });\n return headers;\n}\n","import { customAlphabet } from 'nanoid/non-secure';\n\n/**\n * Generates a 7-character random string to use for IDs. Not secure.\n */\nexport const generateId = customAlphabet(\n '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz',\n 7,\n);\n","export function getErrorMessage(error: unknown | undefined) {\n if (error == null) {\n return 'unknown error';\n }\n\n if (typeof error === 'string') {\n return error;\n }\n\n if (error instanceof Error) {\n return error.message;\n }\n\n return JSON.stringify(error);\n}\n","export function isAbortError(error: unknown): error is DOMException {\n return (\n error instanceof DOMException &&\n (error.name === 'AbortError' || error.name === 'TimeoutError')\n );\n}\n","import { LoadAPIKeyError } from '@ai-sdk/provider';\n\nexport function loadApiKey({\n apiKey,\n environmentVariableName,\n apiKeyParameterName = 'apiKey',\n description,\n}: {\n apiKey: string | undefined;\n environmentVariableName: string;\n apiKeyParameterName?: string;\n description: string;\n}): string {\n if (typeof apiKey === 'string') {\n return apiKey;\n }\n\n if (apiKey != null) {\n throw new LoadAPIKeyError({\n message: `${description} API key must be a string.`,\n });\n }\n\n if (typeof process === 'undefined') {\n throw new LoadAPIKeyError({\n message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter. Environment variables is not supported in this environment.`,\n });\n }\n\n apiKey = process.env[environmentVariableName];\n\n if (apiKey == null) {\n throw new LoadAPIKeyError({\n message: `${description} API key is missing. Pass it using the '${apiKeyParameterName}' parameter or the ${environmentVariableName} environment variable.`,\n });\n }\n\n if (typeof apiKey !== 'string') {\n throw new LoadAPIKeyError({\n message: `${description} API key must be a string. The value of the ${environmentVariableName} environment variable is not a string.`,\n });\n }\n\n return apiKey;\n}\n","import { LoadSettingError } from '@ai-sdk/provider';\n\nexport function loadSetting({\n settingValue,\n environmentVariableName,\n settingName,\n description,\n}: {\n settingValue: string | undefined;\n environmentVariableName: string;\n settingName: string;\n description: string;\n}): string {\n if (typeof settingValue === 'string') {\n return settingValue;\n }\n\n if (settingValue != null) {\n throw new LoadSettingError({\n message: `${description} setting must be a string.`,\n });\n }\n\n if (typeof process === 'undefined') {\n throw new LoadSettingError({\n message: `${description} setting is missing. Pass it using the '${settingName}' parameter. Environment variables is not supported in this environment.`,\n });\n }\n\n settingValue = process.env[environmentVariableName];\n\n if (settingValue == null) {\n throw new LoadSettingError({\n message: `${description} setting is missing. Pass it using the '${settingName}' parameter or the ${environmentVariableName} environment variable.`,\n });\n }\n\n if (typeof settingValue !== 'string') {\n throw new LoadSettingError({\n message: `${description} setting must be a string. The value of the ${environmentVariableName} environment variable is not a string.`,\n });\n }\n\n return settingValue;\n}\n","import { JSONParseError, TypeValidationError } from '@ai-sdk/provider';\nimport SecureJSON from 'secure-json-parse';\nimport { ZodSchema } from 'zod';\nimport { safeValidateTypes, validateTypes } from './validate-types';\n\n/**\n * Parses a JSON string into an unknown object.\n *\n * @param text - The JSON string to parse.\n * @returns {unknown} - The parsed JSON object.\n */\nexport function parseJSON({ text }: { text: string }): unknown;\n/**\n * Parses a JSON string into a strongly-typed object using the provided schema.\n *\n * @template T - The type of the object to parse the JSON into.\n * @param {string} text - The JSON string to parse.\n * @param {Schema<T>} schema - The schema to use for parsing the JSON.\n * @returns {T} - The parsed object.\n */\nexport function parseJSON<T>({\n text,\n schema,\n}: {\n text: string;\n schema: ZodSchema<T>;\n}): T;\nexport function parseJSON<T>({\n text,\n schema,\n}: {\n text: string;\n schema?: ZodSchema<T>;\n}): T {\n try {\n const value = SecureJSON.parse(text);\n\n if (schema == null) {\n return value;\n }\n\n return validateTypes({ value, schema });\n } catch (error) {\n if (\n JSONParseError.isJSONParseError(error) ||\n TypeValidationError.isTypeValidationError(error)\n ) {\n throw error;\n }\n\n throw new JSONParseError({ text, cause: error });\n }\n}\n\nexport type ParseResult<T> =\n | { success: true; value: T }\n | { success: false; error: JSONParseError | TypeValidationError };\n\n/**\n * Safely parses a JSON string and returns the result as an object of type `unknown`.\n *\n * @param text - The JSON string to parse.\n * @returns {object} Either an object with `success: true` and the parsed data, or an object with `success: false` and the error that occurred.\n */\nexport function safeParseJSON({ text }: { text: string }): ParseResult<unknown>;\n/**\n * Safely parses a JSON string into a strongly-typed object, using a provided schema to validate the object.\n *\n * @template T - The type of the object to parse the JSON into.\n * @param {string} text - The JSON string to parse.\n * @param {Schema<T>} schema - The schema to use for parsing the JSON.\n * @returns An object with either a `success` flag and the parsed and typed data, or a `success` flag and an error object.\n */\nexport function safeParseJSON<T>({\n text,\n schema,\n}: {\n text: string;\n schema: ZodSchema<T>;\n}): ParseResult<T>;\nexport function safeParseJSON<T>({\n text,\n schema,\n}: {\n text: string;\n schema?: ZodSchema<T>;\n}):\n | { success: true; value: T }\n | { success: false; error: JSONParseError | TypeValidationError } {\n try {\n const value = SecureJSON.parse(text);\n\n if (schema == null) {\n return {\n success: true,\n value: value as T,\n };\n }\n\n return safeValidateTypes({ value, schema });\n } catch (error) {\n return {\n success: false,\n error: JSONParseError.isJSONParseError(error)\n ? error\n : new JSONParseError({ text, cause: error }),\n };\n }\n}\n\nexport function isParseableJson(input: string): boolean {\n try {\n SecureJSON.parse(input);\n return true;\n } catch {\n return false;\n }\n}\n","import { TypeValidationError } from '@ai-sdk/provider';\nimport { ZodSchema } from 'zod';\n\n/**\n * Validates the types of an unknown object using a schema and\n * return a strongly-typed object.\n *\n * @template T - The type of the object to validate.\n * @param {string} options.value - The object to validate.\n * @param {Schema<T>} options.schema - The schema to use for validating the JSON.\n * @returns {T} - The typed object.\n */\nexport function validateTypes<T>({\n value,\n schema,\n}: {\n value: unknown;\n schema: ZodSchema<T>;\n}): T {\n try {\n return schema.parse(value);\n } catch (error) {\n throw new TypeValidationError({ value, cause: error });\n }\n}\n\n/**\n * Safely validates the types of an unknown object using a schema and\n * return a strongly-typed object.\n *\n * @template T - The type of the object to validate.\n * @param {string} options.value - The JSON object to validate.\n * @param {Schema<T>} options.schema - The schema to use for validating the JSON.\n * @returns An object with either a `success` flag and the parsed and typed data, or a `success` flag and an error object.\n */\nexport function safeValidateTypes<T>({\n value,\n schema,\n}: {\n value: unknown;\n schema: ZodSchema<T>;\n}):\n | { success: true; value: T }\n | { success: false; error: TypeValidationError } {\n try {\n const validationResult = schema.safeParse(value);\n\n if (validationResult.success) {\n return {\n success: true,\n value: validationResult.data,\n };\n }\n\n return {\n success: false,\n error: new TypeValidationError({\n value,\n cause: validationResult.error,\n }),\n };\n } catch (error) {\n return {\n success: false,\n error: TypeValidationError.isTypeValidationError(error)\n ? error\n : new TypeValidationError({ value, cause: error }),\n };\n }\n}\n","import { APICallError } from '@ai-sdk/provider';\nimport { extractResponseHeaders } from './extract-response-headers';\nimport { isAbortError } from './is-abort-error';\nimport { ResponseHandler } from './response-handler';\n\nexport const postJsonToApi = async <T>({\n url,\n headers,\n body,\n failedResponseHandler,\n successfulResponseHandler,\n abortSignal,\n}: {\n url: string;\n headers?: Record<string, string | undefined>;\n body: unknown;\n failedResponseHandler: ResponseHandler<APICallError>;\n successfulResponseHandler: ResponseHandler<T>;\n abortSignal?: AbortSignal;\n}) =>\n postToApi({\n url,\n headers: {\n ...headers,\n 'Content-Type': 'application/json',\n },\n body: {\n content: JSON.stringify(body),\n values: body,\n },\n failedResponseHandler,\n successfulResponseHandler,\n abortSignal,\n });\n\nexport const postToApi = async <T>({\n url,\n headers = {},\n body,\n successfulResponseHandler,\n failedResponseHandler,\n abortSignal,\n}: {\n url: string;\n headers?: Record<string, string | undefined>;\n body: {\n content: string | FormData | Uint8Array;\n values: unknown;\n };\n failedResponseHandler: ResponseHandler<Error>;\n successfulResponseHandler: ResponseHandler<T>;\n abortSignal?: AbortSignal;\n}) => {\n try {\n // remove undefined headers:\n const definedHeaders = Object.fromEntries(\n Object.entries(headers).filter(([_key, value]) => value != null),\n ) as Record<string, string>;\n\n const response = await fetch(url, {\n method: 'POST',\n headers: definedHeaders,\n body: body.content,\n signal: abortSignal,\n });\n\n const responseHeaders = extractResponseHeaders(response);\n\n if (!response.ok) {\n let errorInformation: {\n value: Error;\n responseHeaders?: Record<string, string> | undefined;\n };\n\n try {\n errorInformation = await failedResponseHandler({\n response,\n url,\n requestBodyValues: body.values,\n });\n } catch (error) {\n if (isAbortError(error) || APICallError.isAPICallError(error)) {\n throw error;\n }\n\n throw new APICallError({\n message: 'Failed to process error response',\n cause: error,\n statusCode: response.status,\n url,\n responseHeaders,\n requestBodyValues: body.values,\n });\n }\n\n throw errorInformation.value;\n }\n\n try {\n return await successfulResponseHandler({\n response,\n url,\n requestBodyValues: body.values,\n });\n } catch (error) {\n if (error instanceof Error) {\n if (isAbortError(error) || APICallError.isAPICallError(error)) {\n throw error;\n }\n }\n\n throw new APICallError({\n message: 'Failed to process successful response',\n cause: error,\n statusCode: response.status,\n url,\n responseHeaders,\n requestBodyValues: body.values,\n });\n }\n } catch (error) {\n if (isAbortError(error)) {\n throw error;\n }\n\n // unwrap original error when fetch failed (for easier debugging):\n if (error instanceof TypeError && error.message === 'fetch failed') {\n const cause = (error as any).cause;\n\n if (cause != null) {\n // Failed to connect to server:\n throw new APICallError({\n message: `Cannot connect to API: ${cause.message}`,\n cause,\n url,\n requestBodyValues: body.values,\n isRetryable: true, // retry when network error\n });\n }\n }\n\n throw error;\n }\n};\n","import { APICallError, EmptyResponseBodyError } from '@ai-sdk/provider';\nimport {\n EventSourceParserStream,\n ParsedEvent,\n} from 'eventsource-parser/stream';\nimport { ZodSchema } from 'zod';\nimport { extractResponseHeaders } from './extract-response-headers';\nimport { ParseResult, parseJSON, safeParseJSON } from './parse-json';\n\nexport type ResponseHandler<RETURN_TYPE> = (options: {\n url: string;\n requestBodyValues: unknown;\n response: Response;\n}) => PromiseLike<{\n value: RETURN_TYPE;\n responseHeaders?: Record<string, string>;\n}>;\n\nexport const createJsonErrorResponseHandler =\n <T>({\n errorSchema,\n errorToMessage,\n isRetryable,\n }: {\n errorSchema: ZodSchema<T>;\n errorToMessage: (error: T) => string;\n isRetryable?: (response: Response, error?: T) => boolean;\n }): ResponseHandler<APICallError> =>\n async ({ response, url, requestBodyValues }) => {\n const responseBody = await response.text();\n const responseHeaders = extractResponseHeaders(response);\n\n // Some providers return an empty response body for some errors:\n if (responseBody.trim() === '') {\n return {\n responseHeaders,\n value: new APICallError({\n message: response.statusText,\n url,\n requestBodyValues,\n statusCode: response.status,\n responseHeaders,\n responseBody,\n isRetryable: isRetryable?.(response),\n }),\n };\n }\n\n // resilient parsing in case the response is not JSON or does not match the schema:\n try {\n const parsedError = parseJSON({\n text: responseBody,\n schema: errorSchema,\n });\n\n return {\n responseHeaders,\n value: new APICallError({\n message: errorToMessage(parsedError),\n url,\n requestBodyValues,\n statusCode: response.status,\n responseHeaders,\n responseBody,\n data: parsedError,\n isRetryable: isRetryable?.(response, parsedError),\n }),\n };\n } catch (parseError) {\n return {\n responseHeaders,\n value: new APICallError({\n message: response.statusText,\n url,\n requestBodyValues,\n statusCode: response.status,\n responseHeaders,\n responseBody,\n isRetryable: isRetryable?.(response),\n }),\n };\n }\n };\n\nexport const createEventSourceResponseHandler =\n <T>(\n chunkSchema: ZodSchema<T>,\n ): ResponseHandler<ReadableStream<ParseResult<T>>> =>\n async ({ response }: { response: Response }) => {\n const responseHeaders = extractResponseHeaders(response);\n\n if (response.body == null) {\n throw new EmptyResponseBodyError({});\n }\n\n return {\n responseHeaders,\n value: response.body\n .pipeThrough(new TextDecoderStream())\n .pipeThrough(new EventSourceParserStream())\n .pipeThrough(\n new TransformStream<ParsedEvent, ParseResult<T>>({\n transform({ data }, controller) {\n // ignore the 'DONE' event that e.g. OpenAI sends:\n if (data === '[DONE]') {\n return;\n }\n\n controller.enqueue(\n safeParseJSON({\n text: data,\n schema: chunkSchema,\n }),\n );\n },\n }),\n ),\n };\n };\n\nexport const createJsonResponseHandler =\n <T>(responseSchema: ZodSchema<T>): ResponseHandler<T> =>\n async ({ response, url, requestBodyValues }) => {\n const responseBody = await response.text();\n\n const parsedResult = safeParseJSON({\n text: responseBody,\n schema: responseSchema,\n });\n\n const responseHeaders = extractResponseHeaders(response);\n\n if (!parsedResult.success) {\n throw new APICallError({\n message: 'Invalid JSON response',\n cause: parsedResult.error,\n statusCode: response.status,\n responseHeaders,\n responseBody,\n url,\n requestBodyValues,\n });\n }\n\n return {\n responseHeaders,\n value: parsedResult.value,\n };\n };\n","export function convertBase64ToUint8Array(base64String: string) {\n const base64Url = base64String.replace(/-/g, '+').replace(/_/g, '/');\n const latin1string = globalThis.atob(base64Url);\n return Uint8Array.from(latin1string, byte => byte.codePointAt(0)!);\n}\n\nexport function convertUint8ArrayToBase64(array: Uint8Array): string {\n let latin1string = '';\n\n // Note: regular for loop to support older JavaScript versions that\n // do not support for..of on Uint8Array\n for (let i = 0; i < array.length; i++) {\n latin1string += String.fromCodePoint(array[i]);\n }\n\n return globalThis.btoa(latin1string);\n}\n","export function withoutTrailingSlash(url: string | undefined) {\n return url?.replace(/\\/$/, '');\n}\n"],"mappings":"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","names":["exports","module"]}
package/dist/utils.mjs ADDED
@@ -0,0 +1,7 @@
1
+ import {
2
+ convertFromVercelAIMessages
3
+ } from "./chunk-GOA2HL4A.mjs";
4
+ export {
5
+ convertFromVercelAIMessages
6
+ };
7
+ //# sourceMappingURL=utils.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,12 @@
1
+ # You must first activate a Billing Account here: https://platform.openai.com/account/billing/overview
2
+ # Then get your OpenAI API Key here: https://platform.openai.com/account/api-keys
3
+ OPENAI_API_KEY=XXXXXXXX
4
+
5
+ # Generate a random secret: https://generate-secret.vercel.app/32 or `openssl rand -base64 32`
6
+ AUTH_SECRET=XXXXXXXX
7
+
8
+ # Get your LangWatch API Key here: https://app.langwatch.ai/
9
+ LANGWATCH_API_KEY=XXXXXXXX
10
+
11
+ # Keep the default endpoint unless pointing to a self-hosted version
12
+ LANGWATCH_ENDPOINT=https://app.langwatch.ai
@@ -0,0 +1,26 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/eslintrc",
3
+ "root": true,
4
+ "extends": [
5
+ "next/core-web-vitals",
6
+ "prettier",
7
+ "plugin:tailwindcss/recommended"
8
+ ],
9
+ "plugins": ["tailwindcss"],
10
+ "rules": {
11
+ "tailwindcss/no-custom-classname": "off",
12
+ "tailwindcss/classnames-order": "off"
13
+ },
14
+ "settings": {
15
+ "tailwindcss": {
16
+ "callees": ["cn", "cva"],
17
+ "config": "tailwind.config.js"
18
+ }
19
+ },
20
+ "overrides": [
21
+ {
22
+ "files": ["*.ts", "*.tsx"],
23
+ "parser": "@typescript-eslint/parser"
24
+ }
25
+ ]
26
+ }
@@ -0,0 +1,13 @@
1
+ Copyright 2023 Vercel, Inc.
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
@@ -0,0 +1,10 @@
1
+ # LangWatch TypeScript SDK example project
2
+
3
+ This is an example typescript project using Next.js AI Chatbot using LangWatch SDK for observability.
4
+
5
+ Run it with:
6
+
7
+ ```
8
+ npm install
9
+ npm run dev
10
+ ```
@@ -0,0 +1,60 @@
1
+ import { type Metadata } from 'next'
2
+ import { notFound, redirect } from 'next/navigation'
3
+
4
+ import { auth } from '@/auth'
5
+ import { getChat, getMissingKeys } from '@/app/actions'
6
+ import { Chat } from '@/components/chat'
7
+ import { AI } from '@/lib/chat/actions'
8
+ import { Session } from '@/lib/types'
9
+
10
+ export interface ChatPageProps {
11
+ params: {
12
+ id: string
13
+ }
14
+ }
15
+
16
+ export async function generateMetadata({
17
+ params
18
+ }: ChatPageProps): Promise<Metadata> {
19
+ const session = await auth()
20
+
21
+ if (!session?.user) {
22
+ return {}
23
+ }
24
+
25
+ const chat = await getChat(params.id, session.user.id)
26
+ return {
27
+ title: chat?.title.toString().slice(0, 50) ?? 'Chat'
28
+ }
29
+ }
30
+
31
+ export default async function ChatPage({ params }: ChatPageProps) {
32
+ const session = (await auth()) as Session
33
+ const missingKeys = await getMissingKeys()
34
+
35
+ if (!session?.user) {
36
+ redirect(`/login?next=/chat/${params.id}`)
37
+ }
38
+
39
+ const userId = session.user.id as string
40
+ const chat = await getChat(params.id, userId)
41
+
42
+ if (!chat) {
43
+ redirect('/')
44
+ }
45
+
46
+ if (chat?.userId !== session?.user?.id) {
47
+ notFound()
48
+ }
49
+
50
+ return (
51
+ <AI initialAIState={{ chatId: chat.id, messages: chat.messages }}>
52
+ <Chat
53
+ id={chat.id}
54
+ session={session}
55
+ initialMessages={chat.messages}
56
+ missingKeys={missingKeys}
57
+ />
58
+ </AI>
59
+ )
60
+ }
@@ -0,0 +1,14 @@
1
+ import { SidebarDesktop } from '@/components/sidebar-desktop'
2
+
3
+ interface ChatLayoutProps {
4
+ children: React.ReactNode
5
+ }
6
+
7
+ export default async function ChatLayout({ children }: ChatLayoutProps) {
8
+ return (
9
+ <div className="relative flex h-[calc(100vh_-_theme(spacing.16))] overflow-hidden">
10
+ <SidebarDesktop />
11
+ {children}
12
+ </div>
13
+ )
14
+ }
@@ -0,0 +1,22 @@
1
+ import { nanoid } from '@/lib/utils'
2
+ import { Chat } from '@/components/chat'
3
+ import { AI } from '@/lib/chat/actions'
4
+ import { auth } from '@/auth'
5
+ import { Session } from '@/lib/types'
6
+ import { getMissingKeys } from '@/app/actions'
7
+
8
+ export const metadata = {
9
+ title: 'Next.js AI Chatbot'
10
+ }
11
+
12
+ export default async function IndexPage() {
13
+ const id = nanoid()
14
+ const session = (await auth()) as Session
15
+ const missingKeys = await getMissingKeys()
16
+
17
+ return (
18
+ <AI initialAIState={{ chatId: id, messages: [] }}>
19
+ <Chat id={id} session={session} missingKeys={missingKeys} />
20
+ </AI>
21
+ )
22
+ }
@@ -0,0 +1,156 @@
1
+ 'use server'
2
+
3
+ import { revalidatePath } from 'next/cache'
4
+ import { redirect } from 'next/navigation'
5
+ import { kv } from '@vercel/kv'
6
+
7
+ import { auth } from '@/auth'
8
+ import { type Chat } from '@/lib/types'
9
+
10
+ export async function getChats(userId?: string | null) {
11
+ if (!userId) {
12
+ return []
13
+ }
14
+
15
+ try {
16
+ const pipeline = kv.pipeline()
17
+ const chats: string[] = await kv.zrange(`user:chat:${userId}`, 0, -1, {
18
+ rev: true
19
+ })
20
+
21
+ for (const chat of chats) {
22
+ pipeline.hgetall(chat)
23
+ }
24
+
25
+ const results = await pipeline.exec()
26
+
27
+ return results as Chat[]
28
+ } catch (error) {
29
+ return []
30
+ }
31
+ }
32
+
33
+ export async function getChat(id: string, userId: string) {
34
+ const chat = await kv.hgetall<Chat>(`chat:${id}`)
35
+
36
+ if (!chat || (userId && chat.userId !== userId)) {
37
+ return null
38
+ }
39
+
40
+ return chat
41
+ }
42
+
43
+ export async function removeChat({ id, path }: { id: string; path: string }) {
44
+ const session = await auth()
45
+
46
+ if (!session) {
47
+ return {
48
+ error: 'Unauthorized'
49
+ }
50
+ }
51
+
52
+ //Convert uid to string for consistent comparison with session.user.id
53
+ const uid = String(await kv.hget(`chat:${id}`, 'userId'))
54
+
55
+ if (uid !== session?.user?.id) {
56
+ return {
57
+ error: 'Unauthorized'
58
+ }
59
+ }
60
+
61
+ await kv.del(`chat:${id}`)
62
+ await kv.zrem(`user:chat:${session.user.id}`, `chat:${id}`)
63
+
64
+ revalidatePath('/')
65
+ return revalidatePath(path)
66
+ }
67
+
68
+ export async function clearChats() {
69
+ const session = await auth()
70
+
71
+ if (!session?.user?.id) {
72
+ return {
73
+ error: 'Unauthorized'
74
+ }
75
+ }
76
+
77
+ const chats: string[] = await kv.zrange(`user:chat:${session.user.id}`, 0, -1)
78
+ if (!chats.length) {
79
+ return redirect('/')
80
+ }
81
+ const pipeline = kv.pipeline()
82
+
83
+ for (const chat of chats) {
84
+ pipeline.del(chat)
85
+ pipeline.zrem(`user:chat:${session.user.id}`, chat)
86
+ }
87
+
88
+ await pipeline.exec()
89
+
90
+ revalidatePath('/')
91
+ return redirect('/')
92
+ }
93
+
94
+ export async function getSharedChat(id: string) {
95
+ const chat = await kv.hgetall<Chat>(`chat:${id}`)
96
+
97
+ if (!chat || !chat.sharePath) {
98
+ return null
99
+ }
100
+
101
+ return chat
102
+ }
103
+
104
+ export async function shareChat(id: string) {
105
+ const session = await auth()
106
+
107
+ if (!session?.user?.id) {
108
+ return {
109
+ error: 'Unauthorized'
110
+ }
111
+ }
112
+
113
+ const chat = await kv.hgetall<Chat>(`chat:${id}`)
114
+
115
+ if (!chat || chat.userId !== session.user.id) {
116
+ return {
117
+ error: 'Something went wrong'
118
+ }
119
+ }
120
+
121
+ const payload = {
122
+ ...chat,
123
+ sharePath: `/share/${chat.id}`
124
+ }
125
+
126
+ await kv.hmset(`chat:${chat.id}`, payload)
127
+
128
+ return payload
129
+ }
130
+
131
+ export async function saveChat(chat: Chat) {
132
+ const session = await auth()
133
+
134
+ if (session && session.user) {
135
+ const pipeline = kv.pipeline()
136
+ pipeline.hmset(`chat:${chat.id}`, chat)
137
+ pipeline.zadd(`user:chat:${chat.userId}`, {
138
+ score: Date.now(),
139
+ member: `chat:${chat.id}`
140
+ })
141
+ await pipeline.exec()
142
+ } else {
143
+ return
144
+ }
145
+ }
146
+
147
+ export async function refreshHistory(path: string) {
148
+ redirect(path)
149
+ }
150
+
151
+ export async function getMissingKeys() {
152
+ const keysRequired = ['OPENAI_API_KEY']
153
+ return keysRequired
154
+ .map(key => (process.env[key] ? '' : key))
155
+ .filter(key => key !== '')
156
+ }