@mvriu5/payload-ai 1.3.2 → 1.5.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.
- package/README.md +102 -13
- package/dist/ai/providerOptions.d.ts +24 -1
- package/dist/ai/providerOptions.js +81 -0
- package/dist/ai/providerRuntime.d.ts +2 -1
- package/dist/ai/providerRuntime.js +5 -2
- package/dist/ai/tokenUsage.d.ts +38 -0
- package/dist/ai/tokenUsage.js +106 -0
- package/dist/components/Icons.d.ts +1 -0
- package/dist/components/Icons.js +15 -0
- package/dist/components/action-toast/ActionToast.d.ts +5 -1
- package/dist/components/action-toast/ActionToast.js +57 -21
- package/dist/components/ai-input/AIInput.d.ts +4 -1
- package/dist/components/ai-input/AIInput.js +196 -51
- package/dist/components/ai-input/AIInput.module.css +89 -2
- package/dist/components/audit-log-list/AuditLogList.js +9 -2
- package/dist/components/dashboard/Dashboard.js +3 -1
- package/dist/components/generate-field/GenerateField.d.ts +11 -0
- package/dist/components/generate-field/GenerateField.js +109 -0
- package/dist/components/generate-field/GenerateField.module.css +39 -0
- package/dist/components/generate-field/richText.d.ts +29 -0
- package/dist/components/generate-field/richText.js +30 -0
- package/dist/components/hooks/useAIChatStream.d.ts +12 -1
- package/dist/components/hooks/useAIChatStream.js +13 -4
- package/dist/components/hooks/useAISettings.d.ts +6 -4
- package/dist/components/hooks/useAISettings.js +62 -22
- package/dist/components/hooks/usePluginConfig.d.ts +8 -20
- package/dist/components/hooks/usePluginConfig.js +9 -2
- package/dist/components/text-shimmer/TextShimmer.d.ts +9 -0
- package/dist/components/text-shimmer/TextShimmer.js +34 -0
- package/dist/components/text-shimmer/TextShimmer.module.css +19 -0
- package/dist/exports/client.d.ts +4 -0
- package/dist/exports/client.js +4 -0
- package/dist/handlers/chatHandler.d.ts +4 -1
- package/dist/handlers/chatHandler.js +198 -17
- package/dist/handlers/generateFieldHandler.d.ts +14 -0
- package/dist/handlers/generateFieldHandler.js +144 -0
- package/dist/index.d.ts +8 -1
- package/dist/index.js +141 -5
- package/dist/payload/textFieldGeneration.d.ts +26 -0
- package/dist/payload/textFieldGeneration.js +99 -0
- package/package.json +18 -16
package/dist/index.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
-
import { aiProviders, getResolvedAIModelConfig } from "./ai/providerOptions.js";
|
|
1
|
+
import { aiProviders, getResolvedAIModelConfig, resolveAIProviderConfigs, toClientAIProviderProfiles } from "./ai/providerOptions.js";
|
|
2
|
+
import { resolveMaxTokenUsageOptions, tokenUsageCollectionSlug } from "./ai/tokenUsage.js";
|
|
2
3
|
import { createApplyActionHandler } from "./handlers/applyActionHandler.js";
|
|
3
4
|
import { createChatHandler } from "./handlers/chatHandler.js";
|
|
5
|
+
import { createGenerateFieldHandler } from "./handlers/generateFieldHandler.js";
|
|
4
6
|
import { createMentionSuggestionHandler } from "./handlers/mentionSuggestionHandler.js";
|
|
5
7
|
import { createMediaUploadHandler } from "./handlers/mediaUploadHandler.js";
|
|
6
8
|
import { createProposalDiffHandler } from "./handlers/proposalDiffHandler.js";
|
|
7
9
|
import { createAuditLogHandler } from "./handlers/auditLogHandler.js";
|
|
8
10
|
import { resolveCollectionPermissions } from "./payload/collectionPermissions.js";
|
|
9
11
|
import { isInternalCollection } from "./payload/shared.js";
|
|
12
|
+
import { addTextGenerationFields } from "./payload/textFieldGeneration.js";
|
|
10
13
|
const resolveMediaUploadOptions = (media)=>{
|
|
11
14
|
if (!media || media.enabled === false) return null;
|
|
12
15
|
return {
|
|
@@ -137,6 +140,56 @@ const createAIChangesCollection = ()=>({
|
|
|
137
140
|
],
|
|
138
141
|
timestamps: true
|
|
139
142
|
});
|
|
143
|
+
const createAITokenUsageCollection = ()=>({
|
|
144
|
+
slug: tokenUsageCollectionSlug,
|
|
145
|
+
access: {
|
|
146
|
+
create: ()=>false,
|
|
147
|
+
delete: ()=>false,
|
|
148
|
+
read: ()=>false,
|
|
149
|
+
update: ()=>false
|
|
150
|
+
},
|
|
151
|
+
admin: {
|
|
152
|
+
hidden: true
|
|
153
|
+
},
|
|
154
|
+
fields: [
|
|
155
|
+
{
|
|
156
|
+
name: "userID",
|
|
157
|
+
type: "text",
|
|
158
|
+
index: true,
|
|
159
|
+
required: true
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
name: "provider",
|
|
163
|
+
type: "text",
|
|
164
|
+
required: true
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
name: "model",
|
|
168
|
+
type: "text",
|
|
169
|
+
required: true
|
|
170
|
+
},
|
|
171
|
+
{
|
|
172
|
+
name: "inputTokens",
|
|
173
|
+
type: "number"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
name: "outputTokens",
|
|
177
|
+
type: "number"
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
name: "totalTokens",
|
|
181
|
+
type: "number",
|
|
182
|
+
required: true
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
name: "recordedAt",
|
|
186
|
+
type: "date",
|
|
187
|
+
index: true,
|
|
188
|
+
required: true
|
|
189
|
+
}
|
|
190
|
+
],
|
|
191
|
+
timestamps: true
|
|
192
|
+
});
|
|
140
193
|
const addAccountFields = ({ allowUserApiKeys, config })=>{
|
|
141
194
|
const adminUserSlug = config.admin?.user;
|
|
142
195
|
if (!adminUserSlug || !config.collections) return;
|
|
@@ -163,22 +216,87 @@ const addAccountFields = ({ allowUserApiKeys, config })=>{
|
|
|
163
216
|
});
|
|
164
217
|
}
|
|
165
218
|
};
|
|
219
|
+
const aiField = {
|
|
220
|
+
name: "payloadAi",
|
|
221
|
+
type: "ui",
|
|
222
|
+
admin: {
|
|
223
|
+
components: {
|
|
224
|
+
Field: "@mvriu5/payload-ai/client#AIInput"
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
};
|
|
228
|
+
const getEntityLabel = (label, fallback)=>{
|
|
229
|
+
if (typeof label === "string") return label;
|
|
230
|
+
if (label && typeof label === "object") {
|
|
231
|
+
const translatedLabel = Object.values(label).find((value)=>typeof value === "string");
|
|
232
|
+
if (typeof translatedLabel === "string") return translatedLabel;
|
|
233
|
+
}
|
|
234
|
+
return fallback;
|
|
235
|
+
};
|
|
236
|
+
const addAIFieldsToDocumentsAndGlobals = ({ addGenerateFields, addAIInput, config })=>{
|
|
237
|
+
const pageContexts = new Map();
|
|
238
|
+
for (const collection of config.collections || []){
|
|
239
|
+
if (isInternalCollection(collection.slug)) continue;
|
|
240
|
+
if (collection.slug === "payload-ai-auditlog") continue;
|
|
241
|
+
if (addGenerateFields) {
|
|
242
|
+
const pageContext = addTextGenerationFields({
|
|
243
|
+
fields: collection.fields || [],
|
|
244
|
+
label: getEntityLabel(collection.labels?.singular, collection.slug),
|
|
245
|
+
slug: collection.slug,
|
|
246
|
+
type: "collection"
|
|
247
|
+
});
|
|
248
|
+
pageContexts.set(`collection:${collection.slug}`, pageContext);
|
|
249
|
+
}
|
|
250
|
+
if (addAIInput) collection.fields = [
|
|
251
|
+
aiField,
|
|
252
|
+
...collection.fields || []
|
|
253
|
+
];
|
|
254
|
+
}
|
|
255
|
+
for (const global of config.globals || []){
|
|
256
|
+
if (addGenerateFields) {
|
|
257
|
+
const pageContext = addTextGenerationFields({
|
|
258
|
+
fields: global.fields || [],
|
|
259
|
+
label: getEntityLabel(global.label, global.slug),
|
|
260
|
+
slug: global.slug,
|
|
261
|
+
type: "global"
|
|
262
|
+
});
|
|
263
|
+
pageContexts.set(`global:${global.slug}`, pageContext);
|
|
264
|
+
}
|
|
265
|
+
if (addAIInput) global.fields = [
|
|
266
|
+
aiField,
|
|
267
|
+
...global.fields || []
|
|
268
|
+
];
|
|
269
|
+
}
|
|
270
|
+
return pageContexts;
|
|
271
|
+
};
|
|
166
272
|
export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
167
273
|
const incomingOnInit = config.onInit;
|
|
168
274
|
const collectionPermissions = resolveCollectionPermissions(pluginOptions.collections);
|
|
169
|
-
const
|
|
275
|
+
const providerConfigs = resolveAIProviderConfigs(pluginOptions.providers);
|
|
276
|
+
const managedProviders = providerConfigs.length > 0;
|
|
277
|
+
const allowUserApiKeys = !managedProviders && pluginOptions.allowUserApiKeys !== false;
|
|
170
278
|
const modelConfig = getResolvedAIModelConfig(pluginOptions.models);
|
|
279
|
+
const maxTokenUsage = resolveMaxTokenUsageOptions(pluginOptions.maxTokenUsage);
|
|
171
280
|
const mediaUploadOptions = resolveMediaUploadOptions(pluginOptions.media);
|
|
172
281
|
const maxOutputTokens = typeof pluginOptions.maxOutputTokens === "number" && Number.isFinite(pluginOptions.maxOutputTokens) && pluginOptions.maxOutputTokens > 0 ? Math.floor(pluginOptions.maxOutputTokens) : undefined;
|
|
173
282
|
if (!config.collections) config.collections = [];
|
|
174
283
|
if (!config.collections.some((collection)=>collection.slug === "payload-ai-auditlog")) {
|
|
175
284
|
config.collections.push(createAIChangesCollection());
|
|
176
285
|
}
|
|
177
|
-
|
|
286
|
+
if (maxTokenUsage && !config.collections.some((collection)=>collection.slug === tokenUsageCollectionSlug)) {
|
|
287
|
+
config.collections.push(createAITokenUsageCollection());
|
|
288
|
+
}
|
|
289
|
+
if (!managedProviders) addAccountFields({
|
|
178
290
|
allowUserApiKeys,
|
|
179
291
|
config
|
|
180
292
|
});
|
|
181
293
|
if (pluginOptions.disabled) return config;
|
|
294
|
+
const generateFields = pluginOptions.generateFields !== false;
|
|
295
|
+
const textGenerationPageContexts = addAIFieldsToDocumentsAndGlobals({
|
|
296
|
+
addGenerateFields: generateFields,
|
|
297
|
+
addAIInput: pluginOptions.aiInput !== false,
|
|
298
|
+
config
|
|
299
|
+
});
|
|
182
300
|
const mentionCollectionSlugs = config.collections.flatMap((collection)=>{
|
|
183
301
|
if (isInternalCollection(collection.slug)) return [];
|
|
184
302
|
if (collectionPermissions && !collectionPermissions[collection.slug]?.read) return [];
|
|
@@ -194,13 +312,15 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
194
312
|
...config.admin.custom?.payloadAiPlugin || {},
|
|
195
313
|
collectionSlugs: mentionCollectionSlugs,
|
|
196
314
|
allowUserApiKeys,
|
|
315
|
+
managedProviders,
|
|
197
316
|
...mediaUploadOptions ? {
|
|
198
317
|
media: {
|
|
199
318
|
...mediaUploadOptions,
|
|
200
319
|
enabled: true
|
|
201
320
|
}
|
|
202
321
|
} : {},
|
|
203
|
-
models: modelConfig
|
|
322
|
+
models: modelConfig,
|
|
323
|
+
providers: toClientAIProviderProfiles(providerConfigs)
|
|
204
324
|
}
|
|
205
325
|
};
|
|
206
326
|
if (!config.admin.components) config.admin.components = {};
|
|
@@ -211,7 +331,9 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
211
331
|
allowUserApiKeys,
|
|
212
332
|
collections: collectionPermissions,
|
|
213
333
|
maxOutputTokens,
|
|
214
|
-
|
|
334
|
+
maxTokenUsage,
|
|
335
|
+
models: modelConfig,
|
|
336
|
+
providers: providerConfigs
|
|
215
337
|
}),
|
|
216
338
|
method: "post",
|
|
217
339
|
path: "/ai-chat"
|
|
@@ -245,6 +367,20 @@ export const payloadAiPlugin = (pluginOptions)=>(config)=>{
|
|
|
245
367
|
method: "post",
|
|
246
368
|
path: "/ai-mention-suggestion"
|
|
247
369
|
});
|
|
370
|
+
if (generateFields) {
|
|
371
|
+
config.endpoints.push({
|
|
372
|
+
handler: createGenerateFieldHandler({
|
|
373
|
+
allowUserApiKeys,
|
|
374
|
+
maxOutputTokens,
|
|
375
|
+
maxTokenUsage,
|
|
376
|
+
models: modelConfig,
|
|
377
|
+
pageContexts: textGenerationPageContexts,
|
|
378
|
+
providers: providerConfigs
|
|
379
|
+
}),
|
|
380
|
+
method: "post",
|
|
381
|
+
path: "/ai-generate-field"
|
|
382
|
+
});
|
|
383
|
+
}
|
|
248
384
|
if (mediaUploadOptions) {
|
|
249
385
|
config.endpoints.push({
|
|
250
386
|
handler: createMediaUploadHandler(mediaUploadOptions),
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Field } from "payload";
|
|
2
|
+
type GeneratableField = Extract<Field, {
|
|
3
|
+
type: "json" | "richText" | "text" | "textarea";
|
|
4
|
+
}>;
|
|
5
|
+
export type TextGenerationFieldContext = {
|
|
6
|
+
description?: string;
|
|
7
|
+
fieldType: GeneratableField["type"];
|
|
8
|
+
hasMany: boolean;
|
|
9
|
+
key: string;
|
|
10
|
+
label: string;
|
|
11
|
+
maxLength?: number;
|
|
12
|
+
name: string;
|
|
13
|
+
};
|
|
14
|
+
export type TextGenerationPageContext = {
|
|
15
|
+
fields: TextGenerationFieldContext[];
|
|
16
|
+
label: string;
|
|
17
|
+
slug: string;
|
|
18
|
+
type: "collection" | "global";
|
|
19
|
+
};
|
|
20
|
+
export declare const addTextGenerationFields: ({ fields, label, slug, type, }: {
|
|
21
|
+
fields: Field[];
|
|
22
|
+
label: string;
|
|
23
|
+
slug: string;
|
|
24
|
+
type: TextGenerationPageContext["type"];
|
|
25
|
+
}) => TextGenerationPageContext;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
const generateFieldComponent = "@mvriu5/payload-ai/client#GenerateField";
|
|
2
|
+
const getLabel = (field)=>{
|
|
3
|
+
if (typeof field.label === "string") return field.label;
|
|
4
|
+
if (field.label && typeof field.label === "object") {
|
|
5
|
+
const label = Object.values(field.label).find((value)=>typeof value === "string");
|
|
6
|
+
if (typeof label === "string") return label;
|
|
7
|
+
}
|
|
8
|
+
return field.name;
|
|
9
|
+
};
|
|
10
|
+
const getDescription = (field)=>{
|
|
11
|
+
const description = field.admin?.description;
|
|
12
|
+
return typeof description === "string" ? description : undefined;
|
|
13
|
+
};
|
|
14
|
+
const addGenerateComponent = (field, key)=>{
|
|
15
|
+
field.admin = field.admin || {};
|
|
16
|
+
field.admin.components = field.admin.components || {};
|
|
17
|
+
const current = field.admin.components.afterInput || [];
|
|
18
|
+
const alreadyAdded = current.some((component)=>{
|
|
19
|
+
if (typeof component === "string") return component === generateFieldComponent;
|
|
20
|
+
return component && typeof component === "object" && "path" in component && component.path === generateFieldComponent;
|
|
21
|
+
});
|
|
22
|
+
if (alreadyAdded) return;
|
|
23
|
+
field.admin.components.afterInput = [
|
|
24
|
+
...current,
|
|
25
|
+
{
|
|
26
|
+
clientProps: {
|
|
27
|
+
generationFieldKey: key,
|
|
28
|
+
generationFieldType: field.type
|
|
29
|
+
},
|
|
30
|
+
path: generateFieldComponent
|
|
31
|
+
}
|
|
32
|
+
];
|
|
33
|
+
};
|
|
34
|
+
const visitFields = ({ fields, parentKey, result })=>{
|
|
35
|
+
for (const field of fields){
|
|
36
|
+
if (field.type === "tabs") {
|
|
37
|
+
for (const tab of field.tabs){
|
|
38
|
+
visitFields({
|
|
39
|
+
fields: tab.fields,
|
|
40
|
+
parentKey: "name" in tab ? `${parentKey}.${tab.name}` : parentKey,
|
|
41
|
+
result
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
if (field.type === "blocks") {
|
|
47
|
+
for (const block of field.blocks){
|
|
48
|
+
if (typeof block !== "object") continue;
|
|
49
|
+
visitFields({
|
|
50
|
+
fields: block.fields,
|
|
51
|
+
parentKey: `${parentKey}.${field.name}.${block.slug}`,
|
|
52
|
+
result
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if ("fields" in field && Array.isArray(field.fields)) {
|
|
58
|
+
const nextParent = "name" in field && field.name ? `${parentKey}.${field.name}` : parentKey;
|
|
59
|
+
visitFields({
|
|
60
|
+
fields: field.fields,
|
|
61
|
+
parentKey: nextParent,
|
|
62
|
+
result
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
if (![
|
|
66
|
+
"json",
|
|
67
|
+
"richText",
|
|
68
|
+
"text",
|
|
69
|
+
"textarea"
|
|
70
|
+
].includes(field.type) || !("name" in field) || !field.name) continue;
|
|
71
|
+
const key = `${parentKey}.${field.name}`;
|
|
72
|
+
const generatableField = field;
|
|
73
|
+
if (generatableField.admin?.hidden) continue;
|
|
74
|
+
addGenerateComponent(generatableField, key);
|
|
75
|
+
result.push({
|
|
76
|
+
description: getDescription(generatableField),
|
|
77
|
+
fieldType: generatableField.type,
|
|
78
|
+
hasMany: "hasMany" in generatableField ? Boolean(generatableField.hasMany) : false,
|
|
79
|
+
key,
|
|
80
|
+
label: getLabel(generatableField),
|
|
81
|
+
maxLength: "maxLength" in generatableField ? generatableField.maxLength : undefined,
|
|
82
|
+
name: generatableField.name
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
export const addTextGenerationFields = ({ fields, label, slug, type })=>{
|
|
87
|
+
const result = [];
|
|
88
|
+
visitFields({
|
|
89
|
+
fields,
|
|
90
|
+
parentKey: slug,
|
|
91
|
+
result
|
|
92
|
+
});
|
|
93
|
+
return {
|
|
94
|
+
fields: result,
|
|
95
|
+
label,
|
|
96
|
+
slug,
|
|
97
|
+
type
|
|
98
|
+
};
|
|
99
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mvriu5/payload-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.0",
|
|
4
4
|
"description": "AI assistant plugin for Payload CMS with provider selection, CMS mentions, and signed action proposals.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"payload",
|
|
@@ -68,16 +68,17 @@
|
|
|
68
68
|
"devDependencies": {
|
|
69
69
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
70
70
|
"@ai-sdk/google": "^3.0.80",
|
|
71
|
-
"@ai-sdk/mistral": "^
|
|
71
|
+
"@ai-sdk/mistral": "^4.0.13",
|
|
72
72
|
"@ai-sdk/openai": "^3.0.67",
|
|
73
|
-
"@
|
|
74
|
-
"@
|
|
75
|
-
"@payloadcms/
|
|
76
|
-
"@payloadcms/
|
|
77
|
-
"@payloadcms/
|
|
73
|
+
"@floating-ui/react": "0.27.20",
|
|
74
|
+
"@openrouter/ai-sdk-provider": "^3.0.0",
|
|
75
|
+
"@payloadcms/db-postgres": "3.86.0",
|
|
76
|
+
"@payloadcms/next": "3.86.0",
|
|
77
|
+
"@payloadcms/richtext-lexical": "3.86.0",
|
|
78
|
+
"@payloadcms/ui": "3.86.0",
|
|
78
79
|
"@playwright/test": "^1.56.1",
|
|
79
80
|
"@swc/cli": "0.8.1",
|
|
80
|
-
"@types/node": "
|
|
81
|
+
"@types/node": "26.1.1",
|
|
81
82
|
"@types/react": "19.2.17",
|
|
82
83
|
"@types/react-dom": "19.2.3",
|
|
83
84
|
"copyfiles": "2.4.1",
|
|
@@ -86,22 +87,23 @@
|
|
|
86
87
|
"graphql": "^17.0.1",
|
|
87
88
|
"jsdom": "^29.1.1",
|
|
88
89
|
"knip": "^6.18.0",
|
|
89
|
-
"next": "16.2.
|
|
90
|
-
"payload": "3.
|
|
90
|
+
"next": "16.2.11",
|
|
91
|
+
"payload": "3.86.0",
|
|
91
92
|
"prettier": "^3.8.4",
|
|
92
93
|
"react": "19.2.7",
|
|
93
94
|
"react-dom": "19.2.7",
|
|
94
95
|
"rimraf": "6.1.3",
|
|
95
|
-
"sharp": "0.35.
|
|
96
|
-
"typescript": "
|
|
97
|
-
"vitest": "4.1.
|
|
96
|
+
"sharp": "0.35.3",
|
|
97
|
+
"typescript": "6.0.3",
|
|
98
|
+
"vitest": "4.1.10"
|
|
98
99
|
},
|
|
99
100
|
"peerDependencies": {
|
|
100
101
|
"@ai-sdk/anthropic": "^3.0.81",
|
|
101
102
|
"@ai-sdk/google": "^3.0.80",
|
|
102
|
-
"@ai-sdk/mistral": "^
|
|
103
|
+
"@ai-sdk/mistral": "^4.0.13",
|
|
103
104
|
"@ai-sdk/openai": "^3.0.67",
|
|
104
|
-
"@openrouter/ai-sdk-provider": "^
|
|
105
|
+
"@openrouter/ai-sdk-provider": "^3.0.0",
|
|
106
|
+
"@payloadcms/ui": "^3.84.1",
|
|
105
107
|
"payload": "^3.84.1"
|
|
106
108
|
},
|
|
107
109
|
"peerDependenciesMeta": {
|
|
@@ -147,7 +149,7 @@
|
|
|
147
149
|
]
|
|
148
150
|
},
|
|
149
151
|
"dependencies": {
|
|
150
|
-
"ai": "^
|
|
152
|
+
"ai": "^7.0.31",
|
|
151
153
|
"zod": "^4.4.3"
|
|
152
154
|
}
|
|
153
155
|
}
|