@mvriu5/payload-ai 0.5.9 → 0.5.10
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 +62 -6
- package/dist/ai/{proposals.d.ts → proposalSigning.d.ts} +1 -1
- package/dist/ai/{proposals.js → proposalSigning.js} +6 -11
- package/dist/ai/providerOptions.d.ts +17 -1
- package/dist/ai/providerOptions.js +35 -7
- package/dist/ai/providerRuntime.d.ts +2 -2
- package/dist/ai/providerRuntime.js +50 -16
- package/dist/ai/sensitiveData.js +2 -6
- package/dist/components/AIInput.d.ts +2 -1
- package/dist/components/AIInput.js +210 -39
- package/dist/components/AIInput.module.css +15 -1
- package/dist/components/APIKeyField.d.ts +3 -0
- package/dist/components/{AIApiKeyField.js → APIKeyField.js} +3 -4
- package/dist/components/ActionToast.d.ts +30 -0
- package/dist/components/{AIActionProposalList.js → ActionToast.js} +10 -8
- package/dist/components/AuditLogList.d.ts +32 -0
- package/dist/components/{RecentChangesList.js → AuditLogList.js} +13 -12
- package/dist/components/{RecentChangesList.module.css → AuditLogList.module.css} +18 -1
- package/dist/components/DiffDialog.d.ts +10 -3
- package/dist/components/DiffDialog.js +164 -78
- package/dist/components/DiffDialog.module.css +86 -2
- package/dist/components/Icons.d.ts +5 -0
- package/dist/components/Icons.js +109 -3
- package/dist/components/MentionPopover.d.ts +19 -0
- package/dist/components/{CollectionMentionPopover.js → MentionPopover.js} +11 -4
- package/dist/components/{CollectionMentionPopover.module.css → MentionPopover.module.css} +0 -2
- package/dist/components/hooks/useAISettings.d.ts +6 -4
- package/dist/components/hooks/useAISettings.js +18 -3
- package/dist/components/hooks/useDocumentMentionSuggestions.d.ts +3 -3
- package/dist/components/hooks/useDocumentMentionSuggestions.js +2 -2
- package/dist/exports/client.d.ts +4 -2
- package/dist/exports/client.js +4 -2
- package/dist/handlers/applyActionHandler.d.ts +8 -0
- package/dist/handlers/applyActionHandler.js +563 -0
- package/dist/handlers/auditLogHandler.d.ts +6 -0
- package/dist/{endpoints/aiRecentChangesEndpointHandler.js → handlers/auditLogHandler.js} +12 -8
- package/dist/handlers/chatHandler.d.ts +42 -0
- package/dist/handlers/chatHandler.js +634 -0
- package/dist/handlers/mentionSuggestionHandler.d.ts +7 -0
- package/dist/handlers/mentionSuggestionHandler.js +97 -0
- package/dist/handlers/proposalDiffHandler.d.ts +7 -0
- package/dist/handlers/proposalDiffHandler.js +208 -0
- package/dist/index.d.ts +6 -6
- package/dist/index.js +50 -18
- package/dist/payload/collectionPermissions.d.ts +14 -13
- package/dist/payload/collectionPermissions.js +3 -2
- package/dist/payload/normalizeData.d.ts +8 -0
- package/dist/payload/normalizeData.js +25 -3
- package/dist/payload/schemaContext.d.ts +43 -16
- package/dist/payload/schemaContext.js +139 -18
- package/dist/payload/shared.d.ts +33 -0
- package/dist/payload/shared.js +114 -0
- package/package.json +7 -2
- package/dist/components/AIActionProposalList.d.ts +0 -26
- package/dist/components/AIApiKeyField.d.ts +0 -2
- package/dist/components/CollectionMentionPopover.d.ts +0 -16
- package/dist/components/RecentChangesList.d.ts +0 -18
- package/dist/components/hooks/utils.d.ts +0 -1
- package/dist/components/hooks/utils.js +0 -3
- package/dist/endpoints/aiApplyActionEndpointHandler.d.ts +0 -8
- package/dist/endpoints/aiApplyActionEndpointHandler.js +0 -365
- package/dist/endpoints/aiChatEndpointHandler.d.ts +0 -35
- package/dist/endpoints/aiChatEndpointHandler.js +0 -382
- package/dist/endpoints/aiMentionSuggestionsEndpointHandler.d.ts +0 -7
- package/dist/endpoints/aiMentionSuggestionsEndpointHandler.js +0 -63
- package/dist/endpoints/aiProposalDiffEndpointHandler.d.ts +0 -7
- package/dist/endpoints/aiProposalDiffEndpointHandler.js +0 -138
- package/dist/endpoints/aiRecentChangesEndpointHandler.d.ts +0 -6
- /package/dist/components/{AIActionProposalList.module.css → ActionToast.module.css} +0 -0
|
@@ -1,365 +0,0 @@
|
|
|
1
|
-
import { verifyAIActionProposal } from "../ai/proposals.js";
|
|
2
|
-
import { containsSensitiveData, redactSensitiveData } from "../ai/sensitiveData.js";
|
|
3
|
-
import { getCollectionFields, isAuthCollection, normalizeAuthData, normalizeDataForFields } from "../payload/normalizeData.js";
|
|
4
|
-
import { isCollectionActionAllowed } from "../payload/collectionPermissions.js";
|
|
5
|
-
const getProposalMeta = (proposal)=>{
|
|
6
|
-
if (!proposal) return {};
|
|
7
|
-
return {
|
|
8
|
-
action: proposal.action,
|
|
9
|
-
collection: "collection" in proposal ? proposal.collection : undefined,
|
|
10
|
-
id: "id" in proposal ? proposal.id : undefined,
|
|
11
|
-
slug: "slug" in proposal ? proposal.slug : undefined
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
const getAppliedDocReference = (doc)=>{
|
|
15
|
-
return doc?.id === undefined ? undefined : {
|
|
16
|
-
id: doc.id
|
|
17
|
-
};
|
|
18
|
-
};
|
|
19
|
-
const isAllowedCollection = (req, collection, collections, action = "read")=>{
|
|
20
|
-
return isCollectionActionAllowed({
|
|
21
|
-
action,
|
|
22
|
-
permissions: collections,
|
|
23
|
-
req,
|
|
24
|
-
slug: collection
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
const isKnownGlobal = (req, slug)=>{
|
|
28
|
-
return req.payload.config.globals?.some((item)=>item.slug === slug) || false;
|
|
29
|
-
};
|
|
30
|
-
const isRecord = (value)=>{
|
|
31
|
-
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
32
|
-
};
|
|
33
|
-
const mergeData = (current, next)=>{
|
|
34
|
-
return Object.fromEntries(Object.entries({
|
|
35
|
-
...current,
|
|
36
|
-
...next
|
|
37
|
-
}).map(([key, value])=>{
|
|
38
|
-
const currentValue = current[key];
|
|
39
|
-
if (isRecord(currentValue) && isRecord(value)) {
|
|
40
|
-
return [
|
|
41
|
-
key,
|
|
42
|
-
mergeData(currentValue, value)
|
|
43
|
-
];
|
|
44
|
-
}
|
|
45
|
-
return [
|
|
46
|
-
key,
|
|
47
|
-
value
|
|
48
|
-
];
|
|
49
|
-
}));
|
|
50
|
-
};
|
|
51
|
-
const getJSONLineKey = (line)=>{
|
|
52
|
-
const match = /^(\s*)"([^"]+)":/.exec(line);
|
|
53
|
-
return match ? `${match[1]}${match[2]}` : null;
|
|
54
|
-
};
|
|
55
|
-
const countDiffChanges = ({ after, before })=>{
|
|
56
|
-
const beforeLines = JSON.stringify(before, null, 2).split("\n");
|
|
57
|
-
const afterLines = JSON.stringify(after, null, 2).split("\n");
|
|
58
|
-
const dp = Array.from({
|
|
59
|
-
length: beforeLines.length + 1
|
|
60
|
-
}, ()=>Array(afterLines.length + 1).fill(0));
|
|
61
|
-
let additions = 0;
|
|
62
|
-
let removals = 0;
|
|
63
|
-
for(let i = beforeLines.length - 1; i >= 0; i -= 1){
|
|
64
|
-
for(let j = afterLines.length - 1; j >= 0; j -= 1){
|
|
65
|
-
dp[i][j] = beforeLines[i] === afterLines[j] ? dp[i + 1][j + 1] + 1 : Math.max(dp[i + 1][j], dp[i][j + 1]);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
let beforeIndex = 0;
|
|
69
|
-
let afterIndex = 0;
|
|
70
|
-
while(beforeIndex < beforeLines.length && afterIndex < afterLines.length){
|
|
71
|
-
if (beforeLines[beforeIndex] === afterLines[afterIndex]) {
|
|
72
|
-
beforeIndex += 1;
|
|
73
|
-
afterIndex += 1;
|
|
74
|
-
continue;
|
|
75
|
-
}
|
|
76
|
-
const beforeKey = getJSONLineKey(beforeLines[beforeIndex]);
|
|
77
|
-
const afterKey = getJSONLineKey(afterLines[afterIndex]);
|
|
78
|
-
if (beforeKey && beforeKey === afterKey) {
|
|
79
|
-
removals += 1;
|
|
80
|
-
additions += 1;
|
|
81
|
-
beforeIndex += 1;
|
|
82
|
-
afterIndex += 1;
|
|
83
|
-
continue;
|
|
84
|
-
}
|
|
85
|
-
if (dp[beforeIndex + 1][afterIndex] >= dp[beforeIndex][afterIndex + 1]) {
|
|
86
|
-
removals += 1;
|
|
87
|
-
beforeIndex += 1;
|
|
88
|
-
} else {
|
|
89
|
-
additions += 1;
|
|
90
|
-
afterIndex += 1;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
removals += beforeLines.length - beforeIndex;
|
|
94
|
-
additions += afterLines.length - afterIndex;
|
|
95
|
-
return {
|
|
96
|
-
additions,
|
|
97
|
-
removals
|
|
98
|
-
};
|
|
99
|
-
};
|
|
100
|
-
const getTargetURL = ({ documentID, proposal, req })=>{
|
|
101
|
-
const adminRoute = req.payload.config.routes.admin || "/admin";
|
|
102
|
-
if (proposal.action === "updateGlobal") {
|
|
103
|
-
return `${adminRoute}/globals/${proposal.slug}`;
|
|
104
|
-
}
|
|
105
|
-
if (proposal.action === "delete") {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
const id = proposal.action === "create" ? documentID : proposal.id;
|
|
109
|
-
if (!id) return null;
|
|
110
|
-
return `${adminRoute}/collections/${proposal.collection}/${id}`;
|
|
111
|
-
};
|
|
112
|
-
const getUserID = (req)=>{
|
|
113
|
-
const user = req.user;
|
|
114
|
-
return user?.id === undefined ? undefined : String(user.id);
|
|
115
|
-
};
|
|
116
|
-
const logAIChange = async ({ changeLogCollection, target, proposal, req })=>{
|
|
117
|
-
if (!changeLogCollection) return null;
|
|
118
|
-
const before = redactSensitiveData(target.before);
|
|
119
|
-
const after = redactSensitiveData(target.after);
|
|
120
|
-
const { additions, removals } = countDiffChanges({
|
|
121
|
-
after,
|
|
122
|
-
before
|
|
123
|
-
});
|
|
124
|
-
const proposalForLog = {
|
|
125
|
-
...proposal
|
|
126
|
-
};
|
|
127
|
-
delete proposalForLog._aiSignature;
|
|
128
|
-
try {
|
|
129
|
-
await req.payload.create({
|
|
130
|
-
collection: changeLogCollection,
|
|
131
|
-
data: {
|
|
132
|
-
action: proposal.action,
|
|
133
|
-
additions,
|
|
134
|
-
after,
|
|
135
|
-
before,
|
|
136
|
-
collection: "collection" in proposal ? proposal.collection : undefined,
|
|
137
|
-
documentID: target.documentID === undefined ? undefined : String(target.documentID),
|
|
138
|
-
proposal: redactSensitiveData(proposalForLog),
|
|
139
|
-
removals,
|
|
140
|
-
slug: "slug" in proposal ? proposal.slug : undefined,
|
|
141
|
-
targetType: proposal.action === "updateGlobal" ? "global" : "collection",
|
|
142
|
-
targetURL: getTargetURL({
|
|
143
|
-
documentID: target.documentID,
|
|
144
|
-
proposal,
|
|
145
|
-
req
|
|
146
|
-
}),
|
|
147
|
-
title: proposal.label,
|
|
148
|
-
userID: getUserID(req)
|
|
149
|
-
},
|
|
150
|
-
overrideAccess: true,
|
|
151
|
-
req
|
|
152
|
-
});
|
|
153
|
-
return {
|
|
154
|
-
action: proposal.action,
|
|
155
|
-
additions,
|
|
156
|
-
after,
|
|
157
|
-
before,
|
|
158
|
-
collection: "collection" in proposal ? proposal.collection : null,
|
|
159
|
-
documentID: target.documentID === undefined ? null : String(target.documentID),
|
|
160
|
-
removals,
|
|
161
|
-
slug: "slug" in proposal ? proposal.slug : null,
|
|
162
|
-
title: proposal.label,
|
|
163
|
-
url: getTargetURL({
|
|
164
|
-
documentID: target.documentID,
|
|
165
|
-
proposal,
|
|
166
|
-
req
|
|
167
|
-
})
|
|
168
|
-
};
|
|
169
|
-
} catch (err) {
|
|
170
|
-
req.payload.logger.error({
|
|
171
|
-
err,
|
|
172
|
-
msg: "AI change log entry could not be written",
|
|
173
|
-
proposal: getProposalMeta(proposal)
|
|
174
|
-
});
|
|
175
|
-
return null;
|
|
176
|
-
}
|
|
177
|
-
};
|
|
178
|
-
const isActionProposal = (proposal)=>{
|
|
179
|
-
if (!isRecord(proposal) || typeof proposal.label !== "string") return false;
|
|
180
|
-
if (proposal.action === "create") {
|
|
181
|
-
return typeof proposal.collection === "string" && isRecord(proposal.data);
|
|
182
|
-
}
|
|
183
|
-
if (proposal.action === "update") {
|
|
184
|
-
return typeof proposal.collection === "string" && typeof proposal.id === "string" && isRecord(proposal.data);
|
|
185
|
-
}
|
|
186
|
-
if (proposal.action === "delete") {
|
|
187
|
-
return typeof proposal.collection === "string" && typeof proposal.id === "string";
|
|
188
|
-
}
|
|
189
|
-
if (proposal.action === "updateGlobal") {
|
|
190
|
-
return typeof proposal.slug === "string" && isRecord(proposal.data);
|
|
191
|
-
}
|
|
192
|
-
return false;
|
|
193
|
-
};
|
|
194
|
-
export const createAIApplyActionEndpointHandler = (options = {})=>async (req)=>{
|
|
195
|
-
if (!req.user) return Response.json({
|
|
196
|
-
error: "Unauthorized"
|
|
197
|
-
}, {
|
|
198
|
-
status: 401
|
|
199
|
-
});
|
|
200
|
-
const body = req.json ? await req.json().catch(()=>null) : null;
|
|
201
|
-
const proposal = body?.proposal;
|
|
202
|
-
if (!proposal) return Response.json({
|
|
203
|
-
error: "Proposal is required"
|
|
204
|
-
}, {
|
|
205
|
-
status: 400
|
|
206
|
-
});
|
|
207
|
-
if (!verifyAIActionProposal(proposal)) return Response.json({
|
|
208
|
-
error: "Proposal signature is invalid or expired."
|
|
209
|
-
}, {
|
|
210
|
-
status: 400
|
|
211
|
-
});
|
|
212
|
-
if (!isActionProposal(proposal)) return Response.json({
|
|
213
|
-
error: "Proposal is invalid."
|
|
214
|
-
}, {
|
|
215
|
-
status: 400
|
|
216
|
-
});
|
|
217
|
-
if ("data" in proposal && containsSensitiveData(proposal.data)) return Response.json({
|
|
218
|
-
error: "Proposal contains sensitive fields and cannot be applied."
|
|
219
|
-
}, {
|
|
220
|
-
status: 400
|
|
221
|
-
});
|
|
222
|
-
let normalized;
|
|
223
|
-
try {
|
|
224
|
-
if (proposal.action === "updateGlobal") {
|
|
225
|
-
if (!isKnownGlobal(req, proposal.slug)) return Response.json({
|
|
226
|
-
error: "Unknown global"
|
|
227
|
-
}, {
|
|
228
|
-
status: 400
|
|
229
|
-
});
|
|
230
|
-
const globalConfig = req.payload.config.globals?.find((global)=>global.slug === proposal.slug);
|
|
231
|
-
normalized = normalizeDataForFields(globalConfig?.fields || [], proposal.data);
|
|
232
|
-
const before = await req.payload.findGlobal({
|
|
233
|
-
depth: 2,
|
|
234
|
-
req,
|
|
235
|
-
slug: proposal.slug
|
|
236
|
-
});
|
|
237
|
-
const doc = await req.payload.updateGlobal({
|
|
238
|
-
data: normalized.data,
|
|
239
|
-
overrideAccess: false,
|
|
240
|
-
req,
|
|
241
|
-
slug: proposal.slug
|
|
242
|
-
});
|
|
243
|
-
const change = await logAIChange({
|
|
244
|
-
changeLogCollection: options.changeLogCollection,
|
|
245
|
-
proposal,
|
|
246
|
-
req,
|
|
247
|
-
target: {
|
|
248
|
-
after: mergeData(before, normalized.data),
|
|
249
|
-
before
|
|
250
|
-
}
|
|
251
|
-
});
|
|
252
|
-
return Response.json({
|
|
253
|
-
change,
|
|
254
|
-
doc: getAppliedDocReference(doc),
|
|
255
|
-
status: "applied"
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
if (!isAllowedCollection(req, proposal.collection, options.collections, proposal.action)) return Response.json({
|
|
259
|
-
error: "Unknown collection"
|
|
260
|
-
}, {
|
|
261
|
-
status: 400
|
|
262
|
-
});
|
|
263
|
-
if (proposal.action === "delete") {
|
|
264
|
-
const doc = await req.payload.delete({
|
|
265
|
-
collection: proposal.collection,
|
|
266
|
-
id: proposal.id,
|
|
267
|
-
overrideAccess: false,
|
|
268
|
-
req
|
|
269
|
-
});
|
|
270
|
-
const change = await logAIChange({
|
|
271
|
-
changeLogCollection: options.changeLogCollection,
|
|
272
|
-
proposal,
|
|
273
|
-
req,
|
|
274
|
-
target: {
|
|
275
|
-
after: {},
|
|
276
|
-
before: doc,
|
|
277
|
-
documentID: proposal.id
|
|
278
|
-
}
|
|
279
|
-
});
|
|
280
|
-
return Response.json({
|
|
281
|
-
change,
|
|
282
|
-
doc: getAppliedDocReference(doc),
|
|
283
|
-
status: "applied"
|
|
284
|
-
});
|
|
285
|
-
}
|
|
286
|
-
const collectionConfig = req.payload.config.collections.find((collection)=>collection.slug === proposal.collection);
|
|
287
|
-
normalized = normalizeAuthData(collectionConfig, normalizeDataForFields(getCollectionFields(collectionConfig), proposal.data));
|
|
288
|
-
if (proposal.action === "create" && isAuthCollection(collectionConfig) && !normalized.data.password) {
|
|
289
|
-
return Response.json({
|
|
290
|
-
error: "Password is required when creating a user."
|
|
291
|
-
}, {
|
|
292
|
-
status: 400
|
|
293
|
-
});
|
|
294
|
-
}
|
|
295
|
-
if (proposal.action === "create" && isAuthCollection(collectionConfig) && !normalized.data.email) {
|
|
296
|
-
return Response.json({
|
|
297
|
-
error: "Email is required when creating a user."
|
|
298
|
-
}, {
|
|
299
|
-
status: 400
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
if (proposal.action === "create") {
|
|
303
|
-
const doc = await req.payload.create({
|
|
304
|
-
collection: proposal.collection,
|
|
305
|
-
data: normalized.data,
|
|
306
|
-
overrideAccess: false,
|
|
307
|
-
req
|
|
308
|
-
});
|
|
309
|
-
const change = await logAIChange({
|
|
310
|
-
changeLogCollection: options.changeLogCollection,
|
|
311
|
-
proposal,
|
|
312
|
-
req,
|
|
313
|
-
target: {
|
|
314
|
-
after: doc,
|
|
315
|
-
before: {},
|
|
316
|
-
documentID: doc.id
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
return Response.json({
|
|
320
|
-
change,
|
|
321
|
-
doc: getAppliedDocReference(doc),
|
|
322
|
-
status: "applied"
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
const before = await req.payload.findByID({
|
|
326
|
-
collection: proposal.collection,
|
|
327
|
-
depth: 2,
|
|
328
|
-
id: proposal.id,
|
|
329
|
-
req
|
|
330
|
-
});
|
|
331
|
-
const doc = await req.payload.update({
|
|
332
|
-
collection: proposal.collection,
|
|
333
|
-
data: normalized.data,
|
|
334
|
-
id: proposal.id,
|
|
335
|
-
overrideAccess: false,
|
|
336
|
-
req
|
|
337
|
-
});
|
|
338
|
-
const change = await logAIChange({
|
|
339
|
-
changeLogCollection: options.changeLogCollection,
|
|
340
|
-
proposal,
|
|
341
|
-
req,
|
|
342
|
-
target: {
|
|
343
|
-
after: mergeData(before, normalized.data),
|
|
344
|
-
before,
|
|
345
|
-
documentID: proposal.id
|
|
346
|
-
}
|
|
347
|
-
});
|
|
348
|
-
return Response.json({
|
|
349
|
-
change,
|
|
350
|
-
doc: getAppliedDocReference(doc),
|
|
351
|
-
status: "applied"
|
|
352
|
-
});
|
|
353
|
-
} catch (err) {
|
|
354
|
-
req.payload.logger.error({
|
|
355
|
-
err,
|
|
356
|
-
msg: "AI apply action failed",
|
|
357
|
-
proposal: getProposalMeta(proposal)
|
|
358
|
-
});
|
|
359
|
-
return Response.json({
|
|
360
|
-
error: "Could not apply proposal."
|
|
361
|
-
}, {
|
|
362
|
-
status: 400
|
|
363
|
-
});
|
|
364
|
-
}
|
|
365
|
-
};
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type { PayloadHandler } from "payload";
|
|
2
|
-
import { type AIActionSignature } from "../ai/proposals.js";
|
|
3
|
-
import { type AIModelConfig } from "../ai/providerOptions.js";
|
|
4
|
-
import { type ResolvedAICollectionPermissionMap } from "../payload/collectionPermissions.js";
|
|
5
|
-
export type AIActionProposal = ({
|
|
6
|
-
action: "create";
|
|
7
|
-
collection: string;
|
|
8
|
-
data: Record<string, unknown>;
|
|
9
|
-
label: string;
|
|
10
|
-
} | {
|
|
11
|
-
action: "delete";
|
|
12
|
-
collection: string;
|
|
13
|
-
id: string;
|
|
14
|
-
label: string;
|
|
15
|
-
} | {
|
|
16
|
-
action: "update";
|
|
17
|
-
collection: string;
|
|
18
|
-
data: Record<string, unknown>;
|
|
19
|
-
id: string;
|
|
20
|
-
label: string;
|
|
21
|
-
} | {
|
|
22
|
-
action: "updateGlobal";
|
|
23
|
-
data: Record<string, unknown>;
|
|
24
|
-
label: string;
|
|
25
|
-
slug: string;
|
|
26
|
-
}) & {
|
|
27
|
-
_aiSignature?: AIActionSignature;
|
|
28
|
-
};
|
|
29
|
-
type AIChatEndpointOptions = {
|
|
30
|
-
allowUserApiKeys?: boolean;
|
|
31
|
-
collections?: ResolvedAICollectionPermissionMap;
|
|
32
|
-
models?: AIModelConfig;
|
|
33
|
-
};
|
|
34
|
-
export declare const createAIChatEndpointHandler: (options?: AIChatEndpointOptions) => PayloadHandler;
|
|
35
|
-
export {};
|