strapi-plugin-ai-sdk 0.6.9 → 0.7.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 +151 -2
- package/dist/_chunks/{App-C_BH5Ir4.js → App-BGIUzHMh.js} +298 -2
- package/dist/_chunks/{App-DKyCb0BY.mjs → App-v0CobEGM.mjs} +298 -2
- package/dist/_chunks/{index-DCEjJ0as.js → index-BNk29VRc.js} +1 -1
- package/dist/_chunks/{index-BV9DET_M.mjs → index-CFO5UshL.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/TaskConfirmCard.d.ts +11 -0
- package/dist/server/index.js +526 -76
- package/dist/server/index.mjs +526 -76
- package/dist/server/src/content-types/index.d.ts +62 -0
- package/dist/server/src/content-types/task/index.d.ts +63 -0
- package/dist/server/src/controllers/index.d.ts +8 -0
- package/dist/server/src/controllers/task.d.ts +11 -0
- package/dist/server/src/index.d.ts +70 -3
- package/dist/server/src/lib/tool-registry.d.ts +2 -0
- package/dist/server/src/tool-logic/index.d.ts +2 -0
- package/dist/server/src/tool-logic/manage-task.d.ts +43 -0
- package/dist/server/src/tools/definitions/manage-task.d.ts +2 -0
- package/package.json +1 -1
package/dist/server/index.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import * as path from "node:path";
|
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
12
|
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
13
13
|
function toSnakeCase(str) {
|
|
14
|
-
return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
14
|
+
return str.replace(/:/g, "__").replace(/-/g, "_").replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
15
15
|
}
|
|
16
16
|
function createMcpServer(strapi) {
|
|
17
17
|
const plugin = strapi.plugin("ai-sdk");
|
|
@@ -437,7 +437,7 @@ async function sendEmail(strapi, params) {
|
|
|
437
437
|
subject: params.subject
|
|
438
438
|
};
|
|
439
439
|
}
|
|
440
|
-
const CONTENT_TYPE$
|
|
440
|
+
const CONTENT_TYPE$7 = "plugin::ai-sdk.memory";
|
|
441
441
|
const saveMemorySchema = z.object({
|
|
442
442
|
content: z.string().describe('A short, factual statement to remember about the user (e.g. "User prefers dark mode", "Company name is Acme Corp")'),
|
|
443
443
|
category: z.string().optional().describe('Category for the memory (e.g. "preference", "project", "personal", "general"). Defaults to "general".')
|
|
@@ -448,7 +448,7 @@ async function saveMemory(strapi, params, context) {
|
|
|
448
448
|
return { success: false, message: "Cannot save memory: user context not available." };
|
|
449
449
|
}
|
|
450
450
|
try {
|
|
451
|
-
await strapi.documents(CONTENT_TYPE$
|
|
451
|
+
await strapi.documents(CONTENT_TYPE$7).create({
|
|
452
452
|
data: {
|
|
453
453
|
content: params.content,
|
|
454
454
|
category: params.category || "general",
|
|
@@ -461,7 +461,7 @@ async function saveMemory(strapi, params, context) {
|
|
|
461
461
|
return { success: false, message: `Failed to save memory: ${detail}` };
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
|
-
const CONTENT_TYPE$
|
|
464
|
+
const CONTENT_TYPE$6 = "plugin::ai-sdk.memory";
|
|
465
465
|
const recallMemoriesSchema = z.object({
|
|
466
466
|
query: z.string().optional().describe("Optional search term to filter memories by content"),
|
|
467
467
|
category: z.string().optional().describe('Optional category to filter by (e.g. "preference", "project", "personal")')
|
|
@@ -479,7 +479,7 @@ async function recallMemories(strapi, params, context) {
|
|
|
479
479
|
if (params.query) {
|
|
480
480
|
filters.content = { $containsi: params.query };
|
|
481
481
|
}
|
|
482
|
-
const memories = await strapi.documents(CONTENT_TYPE$
|
|
482
|
+
const memories = await strapi.documents(CONTENT_TYPE$6).findMany({
|
|
483
483
|
filters,
|
|
484
484
|
fields: ["content", "category"],
|
|
485
485
|
sort: { createdAt: "desc" }
|
|
@@ -602,7 +602,7 @@ async function uploadMedia(strapi, params) {
|
|
|
602
602
|
usage: `To link this file to a content type field, use writeContent with: { "fieldName": ${uploadedFile.id} }`
|
|
603
603
|
};
|
|
604
604
|
}
|
|
605
|
-
const CONTENT_TYPE$
|
|
605
|
+
const CONTENT_TYPE$5 = "plugin::ai-sdk.public-memory";
|
|
606
606
|
const recallPublicMemoriesSchema = z.object({
|
|
607
607
|
query: z.string().optional().describe("Optional search term to filter public memories by content"),
|
|
608
608
|
category: z.string().optional().describe('Optional category to filter by (e.g. "faq", "product", "policy")')
|
|
@@ -613,7 +613,7 @@ async function recallPublicMemories(strapi, params) {
|
|
|
613
613
|
const filters = {};
|
|
614
614
|
if (params.category) filters.category = params.category;
|
|
615
615
|
if (params.query) filters.content = { $containsi: params.query };
|
|
616
|
-
const memories = await strapi.documents(CONTENT_TYPE$
|
|
616
|
+
const memories = await strapi.documents(CONTENT_TYPE$5).findMany({
|
|
617
617
|
filters,
|
|
618
618
|
fields: ["content", "category"],
|
|
619
619
|
sort: { createdAt: "desc" }
|
|
@@ -847,6 +847,211 @@ async function aggregateContent(strapi, params) {
|
|
|
847
847
|
throw new Error(`Unknown operation: ${operation}`);
|
|
848
848
|
}
|
|
849
849
|
}
|
|
850
|
+
const CONTENT_TYPE$4 = "plugin::ai-sdk.task";
|
|
851
|
+
const manageTaskSchema = z.object({
|
|
852
|
+
action: z.enum(["create", "update", "complete", "list", "summary"]).describe(
|
|
853
|
+
"Action to perform: create a new task, update an existing task, complete (mark done), list open tasks, or get a summary."
|
|
854
|
+
),
|
|
855
|
+
documentId: z.string().optional().describe("Document ID of the task to update or complete. If not known, provide title instead — the system will search for a matching task."),
|
|
856
|
+
title: z.string().optional().describe("Task title — short, clear action. For update/complete: used to find the task if documentId is not provided."),
|
|
857
|
+
description: z.string().optional().describe("Brief context or why this matters."),
|
|
858
|
+
content: z.string().optional().describe("Detailed notes, steps, or links (markdown)."),
|
|
859
|
+
priority: z.enum(["low", "medium", "high", "urgent"]).optional().describe("Priority level. Default: medium."),
|
|
860
|
+
consequence: z.number().int().min(1).max(5).optional().describe("1-5: What happens if this is NOT done? Do NOT ask the user — omit this and a UI form will collect it."),
|
|
861
|
+
impact: z.number().int().min(1).max(5).optional().describe("1-5: How much does completing this move the needle? Do NOT ask the user — omit this and a UI form will collect it."),
|
|
862
|
+
dueDate: z.string().optional().describe("Due date in YYYY-MM-DD format."),
|
|
863
|
+
done: z.boolean().optional().describe("Set done status explicitly (for update action)."),
|
|
864
|
+
filters: z.record(z.string(), z.unknown()).optional().describe("Additional Strapi filters for list action.")
|
|
865
|
+
});
|
|
866
|
+
const manageTaskDescription = "Manage the user's task list. Create, update, complete, list, or summarize tasks. Tasks are scored by consequence × impact to help prioritize what matters most.";
|
|
867
|
+
async function resolveTask(strapi, adminUserId, documentId, title) {
|
|
868
|
+
if (documentId) {
|
|
869
|
+
const task2 = await strapi.documents(CONTENT_TYPE$4).findOne({ documentId });
|
|
870
|
+
if (task2 && task2.adminUserId === adminUserId) return task2;
|
|
871
|
+
}
|
|
872
|
+
if (title) {
|
|
873
|
+
const tasks = await strapi.documents(CONTENT_TYPE$4).findMany({
|
|
874
|
+
filters: {
|
|
875
|
+
adminUserId,
|
|
876
|
+
title: { $containsi: title }
|
|
877
|
+
}
|
|
878
|
+
});
|
|
879
|
+
if (tasks.length === 1) return tasks[0];
|
|
880
|
+
if (tasks.length > 1) {
|
|
881
|
+
const exact = tasks.find(
|
|
882
|
+
(t) => t.title.toLowerCase() === title.toLowerCase()
|
|
883
|
+
);
|
|
884
|
+
if (exact) return exact;
|
|
885
|
+
return tasks.sort(
|
|
886
|
+
(a, b) => b.updatedAt.localeCompare(a.updatedAt)
|
|
887
|
+
)[0];
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
async function manageTask(strapi, params, context) {
|
|
893
|
+
if (!context?.adminUserId) {
|
|
894
|
+
return { success: false, message: "Cannot manage tasks: user context not available." };
|
|
895
|
+
}
|
|
896
|
+
const adminUserId = context.adminUserId;
|
|
897
|
+
try {
|
|
898
|
+
switch (params.action) {
|
|
899
|
+
case "create": {
|
|
900
|
+
if (!params.title) {
|
|
901
|
+
return { success: false, message: "Title is required to create a task." };
|
|
902
|
+
}
|
|
903
|
+
if (params.consequence == null || params.impact == null) {
|
|
904
|
+
return {
|
|
905
|
+
success: false,
|
|
906
|
+
status: "pending_confirmation",
|
|
907
|
+
message: "A confirmation form has been shown to the user in the chat. They will set consequence and impact scores and confirm. Do NOT re-call this tool — the task will be created when the user confirms.",
|
|
908
|
+
proposed: {
|
|
909
|
+
title: params.title,
|
|
910
|
+
description: params.description,
|
|
911
|
+
content: params.content,
|
|
912
|
+
priority: params.priority ?? "medium",
|
|
913
|
+
dueDate: params.dueDate ?? null
|
|
914
|
+
}
|
|
915
|
+
};
|
|
916
|
+
}
|
|
917
|
+
const duplicate = await resolveTask(strapi, adminUserId, void 0, params.title);
|
|
918
|
+
if (duplicate && !duplicate.done) {
|
|
919
|
+
const data = {};
|
|
920
|
+
if (params.description !== void 0) data.description = params.description;
|
|
921
|
+
if (params.content !== void 0) data.content = params.content;
|
|
922
|
+
if (params.priority !== void 0) data.priority = params.priority;
|
|
923
|
+
if (params.consequence !== void 0) data.consequence = params.consequence;
|
|
924
|
+
if (params.impact !== void 0) data.impact = params.impact;
|
|
925
|
+
if (params.dueDate !== void 0) data.dueDate = params.dueDate;
|
|
926
|
+
const updated = await strapi.documents(CONTENT_TYPE$4).update({
|
|
927
|
+
documentId: duplicate.documentId,
|
|
928
|
+
data
|
|
929
|
+
});
|
|
930
|
+
const score2 = (updated.consequence ?? 3) * (updated.impact ?? 3);
|
|
931
|
+
return {
|
|
932
|
+
success: true,
|
|
933
|
+
message: `A similar task already existed ("${duplicate.title}") — updated it instead of creating a duplicate. (priority: ${updated.priority}, score: ${score2})`,
|
|
934
|
+
data: updated
|
|
935
|
+
};
|
|
936
|
+
}
|
|
937
|
+
const task2 = await strapi.documents(CONTENT_TYPE$4).create({
|
|
938
|
+
data: {
|
|
939
|
+
title: params.title,
|
|
940
|
+
description: params.description,
|
|
941
|
+
content: params.content,
|
|
942
|
+
done: false,
|
|
943
|
+
priority: params.priority ?? "medium",
|
|
944
|
+
consequence: params.consequence ?? 3,
|
|
945
|
+
impact: params.impact ?? 3,
|
|
946
|
+
dueDate: params.dueDate,
|
|
947
|
+
adminUserId
|
|
948
|
+
}
|
|
949
|
+
});
|
|
950
|
+
const score = (task2.consequence ?? 3) * (task2.impact ?? 3);
|
|
951
|
+
return {
|
|
952
|
+
success: true,
|
|
953
|
+
message: `Task created: "${task2.title}" (priority: ${task2.priority}, score: ${score})`,
|
|
954
|
+
data: task2
|
|
955
|
+
};
|
|
956
|
+
}
|
|
957
|
+
case "update": {
|
|
958
|
+
const existing = await resolveTask(strapi, adminUserId, params.documentId, params.title);
|
|
959
|
+
if (!existing) {
|
|
960
|
+
return { success: false, message: "Task not found. Provide a documentId or a title to search by." };
|
|
961
|
+
}
|
|
962
|
+
const data = {};
|
|
963
|
+
for (const key of ["title", "description", "content", "priority", "consequence", "impact", "dueDate", "done"]) {
|
|
964
|
+
if (params[key] !== void 0) data[key] = params[key];
|
|
965
|
+
}
|
|
966
|
+
const updated = await strapi.documents(CONTENT_TYPE$4).update({
|
|
967
|
+
documentId: existing.documentId,
|
|
968
|
+
data
|
|
969
|
+
});
|
|
970
|
+
return { success: true, message: `Task updated: "${updated.title}"`, data: updated };
|
|
971
|
+
}
|
|
972
|
+
case "complete": {
|
|
973
|
+
const toComplete = await resolveTask(strapi, adminUserId, params.documentId, params.title);
|
|
974
|
+
if (!toComplete) {
|
|
975
|
+
return { success: false, message: "Task not found. Provide a documentId or a title to search by." };
|
|
976
|
+
}
|
|
977
|
+
await strapi.documents(CONTENT_TYPE$4).update({
|
|
978
|
+
documentId: toComplete.documentId,
|
|
979
|
+
data: { done: true }
|
|
980
|
+
});
|
|
981
|
+
return { success: true, message: `Task completed: "${toComplete.title}"` };
|
|
982
|
+
}
|
|
983
|
+
case "list": {
|
|
984
|
+
const filters = {
|
|
985
|
+
adminUserId,
|
|
986
|
+
done: false,
|
|
987
|
+
...params.filters
|
|
988
|
+
};
|
|
989
|
+
const tasks = await strapi.documents(CONTENT_TYPE$4).findMany({
|
|
990
|
+
filters
|
|
991
|
+
});
|
|
992
|
+
const sorted = tasks.sort((a, b) => {
|
|
993
|
+
const scoreA = (a.consequence ?? 3) * (a.impact ?? 3);
|
|
994
|
+
const scoreB = (b.consequence ?? 3) * (b.impact ?? 3);
|
|
995
|
+
if (scoreB !== scoreA) return scoreB - scoreA;
|
|
996
|
+
if (a.dueDate && !b.dueDate) return -1;
|
|
997
|
+
if (!a.dueDate && b.dueDate) return 1;
|
|
998
|
+
if (a.dueDate && b.dueDate) return a.dueDate.localeCompare(b.dueDate);
|
|
999
|
+
return 0;
|
|
1000
|
+
});
|
|
1001
|
+
return {
|
|
1002
|
+
success: true,
|
|
1003
|
+
message: `Found ${sorted.length} open task(s).`,
|
|
1004
|
+
data: sorted.map((t) => ({
|
|
1005
|
+
documentId: t.documentId,
|
|
1006
|
+
title: t.title,
|
|
1007
|
+
description: t.description,
|
|
1008
|
+
priority: t.priority,
|
|
1009
|
+
consequence: t.consequence,
|
|
1010
|
+
impact: t.impact,
|
|
1011
|
+
score: (t.consequence ?? 3) * (t.impact ?? 3),
|
|
1012
|
+
dueDate: t.dueDate,
|
|
1013
|
+
done: t.done
|
|
1014
|
+
}))
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
case "summary": {
|
|
1018
|
+
const allOpen = await strapi.documents(CONTENT_TYPE$4).findMany({
|
|
1019
|
+
filters: { adminUserId, done: false }
|
|
1020
|
+
});
|
|
1021
|
+
const today = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
1022
|
+
const overdue = allOpen.filter(
|
|
1023
|
+
(t) => t.dueDate && t.dueDate < today
|
|
1024
|
+
);
|
|
1025
|
+
const scored = allOpen.map((t) => ({
|
|
1026
|
+
documentId: t.documentId,
|
|
1027
|
+
title: t.title,
|
|
1028
|
+
priority: t.priority,
|
|
1029
|
+
consequence: t.consequence ?? 3,
|
|
1030
|
+
impact: t.impact ?? 3,
|
|
1031
|
+
score: (t.consequence ?? 3) * (t.impact ?? 3),
|
|
1032
|
+
dueDate: t.dueDate
|
|
1033
|
+
})).sort((a, b) => b.score - a.score);
|
|
1034
|
+
const urgent = scored.filter((t) => t.priority === "urgent");
|
|
1035
|
+
return {
|
|
1036
|
+
success: true,
|
|
1037
|
+
message: "Task summary generated.",
|
|
1038
|
+
data: {
|
|
1039
|
+
totalOpen: allOpen.length,
|
|
1040
|
+
overdueCount: overdue.length,
|
|
1041
|
+
overdueTasks: overdue.map((t) => ({ documentId: t.documentId, title: t.title, dueDate: t.dueDate })),
|
|
1042
|
+
urgentTasks: urgent,
|
|
1043
|
+
top3: scored.slice(0, 3)
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
1047
|
+
default:
|
|
1048
|
+
return { success: false, message: `Unknown action: ${params.action}` };
|
|
1049
|
+
}
|
|
1050
|
+
} catch (error) {
|
|
1051
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
1052
|
+
return { success: false, message: `Task operation failed: ${detail}` };
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
850
1055
|
const listContentTypesTool = {
|
|
851
1056
|
name: "listContentTypes",
|
|
852
1057
|
description: listContentTypesDescription,
|
|
@@ -959,6 +1164,13 @@ const aggregateContentTool = {
|
|
|
959
1164
|
execute: async (args, strapi) => aggregateContent(strapi, args),
|
|
960
1165
|
publicSafe: true
|
|
961
1166
|
};
|
|
1167
|
+
const manageTaskTool = {
|
|
1168
|
+
name: "manageTask",
|
|
1169
|
+
description: manageTaskDescription,
|
|
1170
|
+
schema: manageTaskSchema,
|
|
1171
|
+
execute: async (args, strapi, context) => manageTask(strapi, args, context),
|
|
1172
|
+
internal: true
|
|
1173
|
+
};
|
|
962
1174
|
const builtInTools = [
|
|
963
1175
|
listContentTypesTool,
|
|
964
1176
|
searchContentTool,
|
|
@@ -969,7 +1181,8 @@ const builtInTools = [
|
|
|
969
1181
|
saveMemoryTool,
|
|
970
1182
|
recallMemoriesTool,
|
|
971
1183
|
recallPublicMemoriesTool,
|
|
972
|
-
aggregateContentTool
|
|
1184
|
+
aggregateContentTool,
|
|
1185
|
+
manageTaskTool
|
|
973
1186
|
];
|
|
974
1187
|
const PLUGIN_ID$2 = "ai-sdk";
|
|
975
1188
|
const bootstrap = ({ strapi }) => {
|
|
@@ -992,6 +1205,51 @@ const bootstrap = ({ strapi }) => {
|
|
|
992
1205
|
toolRegistry.register(tool2);
|
|
993
1206
|
}
|
|
994
1207
|
plugin.toolRegistry = toolRegistry;
|
|
1208
|
+
const pluginNames = Object.keys(strapi.plugins).filter((n) => n !== PLUGIN_ID$2);
|
|
1209
|
+
strapi.log.info(`[${PLUGIN_ID$2}] Scanning ${pluginNames.length} plugins for ai-tools: [${pluginNames.join(", ")}]`);
|
|
1210
|
+
for (const [pluginName, pluginInstance] of Object.entries(strapi.plugins)) {
|
|
1211
|
+
if (pluginName === PLUGIN_ID$2) continue;
|
|
1212
|
+
try {
|
|
1213
|
+
let aiToolsService = null;
|
|
1214
|
+
try {
|
|
1215
|
+
aiToolsService = strapi.plugin(pluginName)?.service?.("ai-tools");
|
|
1216
|
+
} catch {
|
|
1217
|
+
}
|
|
1218
|
+
if (!aiToolsService) {
|
|
1219
|
+
try {
|
|
1220
|
+
aiToolsService = pluginInstance.service?.("ai-tools");
|
|
1221
|
+
} catch {
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
if (!aiToolsService?.getTools) {
|
|
1225
|
+
strapi.log.debug(`[${PLUGIN_ID$2}] No ai-tools service on plugin: ${pluginName}`);
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
strapi.log.info(`[${PLUGIN_ID$2}] Found ai-tools service on plugin: ${pluginName}`);
|
|
1229
|
+
const contributed = aiToolsService.getTools();
|
|
1230
|
+
if (!Array.isArray(contributed)) continue;
|
|
1231
|
+
let count = 0;
|
|
1232
|
+
for (const tool2 of contributed) {
|
|
1233
|
+
if (!tool2.name || !tool2.execute || !tool2.schema) {
|
|
1234
|
+
strapi.log.warn(`[${PLUGIN_ID$2}] Invalid tool from ${pluginName}: ${tool2.name || "unnamed"}`);
|
|
1235
|
+
continue;
|
|
1236
|
+
}
|
|
1237
|
+
const safeName = pluginName.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
1238
|
+
const namespacedName = `${safeName}__${tool2.name}`;
|
|
1239
|
+
if (toolRegistry.has(namespacedName)) {
|
|
1240
|
+
strapi.log.warn(`[${PLUGIN_ID$2}] Duplicate tool: ${namespacedName}`);
|
|
1241
|
+
continue;
|
|
1242
|
+
}
|
|
1243
|
+
toolRegistry.register({ ...tool2, name: namespacedName });
|
|
1244
|
+
count++;
|
|
1245
|
+
}
|
|
1246
|
+
if (count > 0) {
|
|
1247
|
+
strapi.log.info(`[${PLUGIN_ID$2}] Registered ${count} tools from plugin: ${pluginName}`);
|
|
1248
|
+
}
|
|
1249
|
+
} catch (err) {
|
|
1250
|
+
strapi.log.warn(`[${PLUGIN_ID$2}] Tool discovery failed for ${pluginName}: ${err}`);
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
995
1253
|
plugin.createMcpServer = () => createMcpServer(strapi);
|
|
996
1254
|
plugin.mcpSessions = /* @__PURE__ */ new Map();
|
|
997
1255
|
strapi.log.info(`[${PLUGIN_ID$2}] MCP endpoint available at: /api/${PLUGIN_ID$2}/mcp`);
|
|
@@ -1078,17 +1336,17 @@ const config = {
|
|
|
1078
1336
|
}
|
|
1079
1337
|
}
|
|
1080
1338
|
};
|
|
1081
|
-
const kind$
|
|
1082
|
-
const collectionName$
|
|
1083
|
-
const info$
|
|
1339
|
+
const kind$3 = "collectionType";
|
|
1340
|
+
const collectionName$3 = "ai_sdk_conversations";
|
|
1341
|
+
const info$3 = {
|
|
1084
1342
|
singularName: "conversation",
|
|
1085
1343
|
pluralName: "conversations",
|
|
1086
1344
|
displayName: "AI Conversation"
|
|
1087
1345
|
};
|
|
1088
|
-
const options$
|
|
1346
|
+
const options$3 = {
|
|
1089
1347
|
draftAndPublish: false
|
|
1090
1348
|
};
|
|
1091
|
-
const pluginOptions$
|
|
1349
|
+
const pluginOptions$3 = {
|
|
1092
1350
|
"content-manager": {
|
|
1093
1351
|
visible: false
|
|
1094
1352
|
},
|
|
@@ -1096,7 +1354,7 @@ const pluginOptions$2 = {
|
|
|
1096
1354
|
visible: false
|
|
1097
1355
|
}
|
|
1098
1356
|
};
|
|
1099
|
-
const attributes$
|
|
1357
|
+
const attributes$3 = {
|
|
1100
1358
|
title: {
|
|
1101
1359
|
type: "string",
|
|
1102
1360
|
required: true,
|
|
@@ -1111,6 +1369,53 @@ const attributes$2 = {
|
|
|
1111
1369
|
required: true
|
|
1112
1370
|
}
|
|
1113
1371
|
};
|
|
1372
|
+
const schema$3 = {
|
|
1373
|
+
kind: kind$3,
|
|
1374
|
+
collectionName: collectionName$3,
|
|
1375
|
+
info: info$3,
|
|
1376
|
+
options: options$3,
|
|
1377
|
+
pluginOptions: pluginOptions$3,
|
|
1378
|
+
attributes: attributes$3
|
|
1379
|
+
};
|
|
1380
|
+
const conversation = { schema: schema$3 };
|
|
1381
|
+
const kind$2 = "collectionType";
|
|
1382
|
+
const collectionName$2 = "ai_sdk_memories";
|
|
1383
|
+
const info$2 = {
|
|
1384
|
+
singularName: "memory",
|
|
1385
|
+
pluralName: "memories",
|
|
1386
|
+
displayName: "AI Memory"
|
|
1387
|
+
};
|
|
1388
|
+
const options$2 = {
|
|
1389
|
+
draftAndPublish: false
|
|
1390
|
+
};
|
|
1391
|
+
const pluginOptions$2 = {
|
|
1392
|
+
"content-manager": {
|
|
1393
|
+
visible: false
|
|
1394
|
+
},
|
|
1395
|
+
"content-type-builder": {
|
|
1396
|
+
visible: false
|
|
1397
|
+
}
|
|
1398
|
+
};
|
|
1399
|
+
const attributes$2 = {
|
|
1400
|
+
content: {
|
|
1401
|
+
type: "text",
|
|
1402
|
+
required: true
|
|
1403
|
+
},
|
|
1404
|
+
category: {
|
|
1405
|
+
type: "enumeration",
|
|
1406
|
+
"enum": [
|
|
1407
|
+
"general",
|
|
1408
|
+
"preference",
|
|
1409
|
+
"personal",
|
|
1410
|
+
"project"
|
|
1411
|
+
],
|
|
1412
|
+
"default": "general"
|
|
1413
|
+
},
|
|
1414
|
+
adminUserId: {
|
|
1415
|
+
type: "integer",
|
|
1416
|
+
required: true
|
|
1417
|
+
}
|
|
1418
|
+
};
|
|
1114
1419
|
const schema$2 = {
|
|
1115
1420
|
kind: kind$2,
|
|
1116
1421
|
collectionName: collectionName$2,
|
|
@@ -1119,13 +1424,13 @@ const schema$2 = {
|
|
|
1119
1424
|
pluginOptions: pluginOptions$2,
|
|
1120
1425
|
attributes: attributes$2
|
|
1121
1426
|
};
|
|
1122
|
-
const
|
|
1427
|
+
const memory = { schema: schema$2 };
|
|
1123
1428
|
const kind$1 = "collectionType";
|
|
1124
|
-
const collectionName$1 = "
|
|
1429
|
+
const collectionName$1 = "ai_sdk_public_memories";
|
|
1125
1430
|
const info$1 = {
|
|
1126
|
-
singularName: "memory",
|
|
1127
|
-
pluralName: "memories",
|
|
1128
|
-
displayName: "AI Memory"
|
|
1431
|
+
singularName: "public-memory",
|
|
1432
|
+
pluralName: "public-memories",
|
|
1433
|
+
displayName: "AI Public Memory"
|
|
1129
1434
|
};
|
|
1130
1435
|
const options$1 = {
|
|
1131
1436
|
draftAndPublish: false
|
|
@@ -1147,15 +1452,11 @@ const attributes$1 = {
|
|
|
1147
1452
|
type: "enumeration",
|
|
1148
1453
|
"enum": [
|
|
1149
1454
|
"general",
|
|
1150
|
-
"
|
|
1151
|
-
"
|
|
1152
|
-
"
|
|
1455
|
+
"faq",
|
|
1456
|
+
"product",
|
|
1457
|
+
"policy"
|
|
1153
1458
|
],
|
|
1154
1459
|
"default": "general"
|
|
1155
|
-
},
|
|
1156
|
-
adminUserId: {
|
|
1157
|
-
type: "integer",
|
|
1158
|
-
required: true
|
|
1159
1460
|
}
|
|
1160
1461
|
};
|
|
1161
1462
|
const schema$1 = {
|
|
@@ -1166,39 +1467,68 @@ const schema$1 = {
|
|
|
1166
1467
|
pluginOptions: pluginOptions$1,
|
|
1167
1468
|
attributes: attributes$1
|
|
1168
1469
|
};
|
|
1169
|
-
const
|
|
1470
|
+
const publicMemory = { schema: schema$1 };
|
|
1170
1471
|
const kind = "collectionType";
|
|
1171
|
-
const collectionName = "
|
|
1472
|
+
const collectionName = "ai_sdk_tasks";
|
|
1172
1473
|
const info = {
|
|
1173
|
-
singularName: "
|
|
1174
|
-
pluralName: "
|
|
1175
|
-
displayName: "AI
|
|
1474
|
+
singularName: "task",
|
|
1475
|
+
pluralName: "tasks",
|
|
1476
|
+
displayName: "AI Task"
|
|
1176
1477
|
};
|
|
1177
1478
|
const options = {
|
|
1178
1479
|
draftAndPublish: false
|
|
1179
1480
|
};
|
|
1180
1481
|
const pluginOptions = {
|
|
1181
1482
|
"content-manager": {
|
|
1182
|
-
visible:
|
|
1483
|
+
visible: true
|
|
1183
1484
|
},
|
|
1184
1485
|
"content-type-builder": {
|
|
1185
1486
|
visible: false
|
|
1186
1487
|
}
|
|
1187
1488
|
};
|
|
1188
1489
|
const attributes = {
|
|
1189
|
-
|
|
1190
|
-
type: "
|
|
1490
|
+
title: {
|
|
1491
|
+
type: "string",
|
|
1191
1492
|
required: true
|
|
1192
1493
|
},
|
|
1193
|
-
|
|
1494
|
+
description: {
|
|
1495
|
+
type: "text"
|
|
1496
|
+
},
|
|
1497
|
+
content: {
|
|
1498
|
+
type: "richtext"
|
|
1499
|
+
},
|
|
1500
|
+
done: {
|
|
1501
|
+
type: "boolean",
|
|
1502
|
+
"default": false
|
|
1503
|
+
},
|
|
1504
|
+
priority: {
|
|
1194
1505
|
type: "enumeration",
|
|
1195
1506
|
"enum": [
|
|
1196
|
-
"
|
|
1197
|
-
"
|
|
1198
|
-
"
|
|
1199
|
-
"
|
|
1507
|
+
"low",
|
|
1508
|
+
"medium",
|
|
1509
|
+
"high",
|
|
1510
|
+
"urgent"
|
|
1200
1511
|
],
|
|
1201
|
-
"default": "
|
|
1512
|
+
"default": "medium"
|
|
1513
|
+
},
|
|
1514
|
+
consequence: {
|
|
1515
|
+
type: "integer",
|
|
1516
|
+
"default": 3,
|
|
1517
|
+
min: 1,
|
|
1518
|
+
max: 5
|
|
1519
|
+
},
|
|
1520
|
+
impact: {
|
|
1521
|
+
type: "integer",
|
|
1522
|
+
"default": 3,
|
|
1523
|
+
min: 1,
|
|
1524
|
+
max: 5
|
|
1525
|
+
},
|
|
1526
|
+
dueDate: {
|
|
1527
|
+
type: "date"
|
|
1528
|
+
},
|
|
1529
|
+
adminUserId: {
|
|
1530
|
+
type: "integer",
|
|
1531
|
+
required: true
|
|
1202
1532
|
}
|
|
1203
1533
|
};
|
|
1204
1534
|
const schema = {
|
|
@@ -1209,8 +1539,8 @@ const schema = {
|
|
|
1209
1539
|
pluginOptions,
|
|
1210
1540
|
attributes
|
|
1211
1541
|
};
|
|
1212
|
-
const
|
|
1213
|
-
const contentTypes = { conversation, memory, "public-memory": publicMemory };
|
|
1542
|
+
const task = { schema };
|
|
1543
|
+
const contentTypes = { conversation, memory, "public-memory": publicMemory, task };
|
|
1214
1544
|
function getService(strapi, ctx) {
|
|
1215
1545
|
const service2 = strapi.plugin("ai-sdk").service("service");
|
|
1216
1546
|
if (!service2.isInitialized()) {
|
|
@@ -1509,20 +1839,20 @@ const mcpController = ({ strapi }) => {
|
|
|
1509
1839
|
}
|
|
1510
1840
|
};
|
|
1511
1841
|
};
|
|
1512
|
-
const CONTENT_TYPE$
|
|
1513
|
-
function getAdminUserId$
|
|
1842
|
+
const CONTENT_TYPE$3 = "plugin::ai-sdk.conversation";
|
|
1843
|
+
function getAdminUserId$2(ctx) {
|
|
1514
1844
|
const id = ctx.state?.user?.id;
|
|
1515
1845
|
return typeof id === "number" ? id : null;
|
|
1516
1846
|
}
|
|
1517
1847
|
const conversationController = ({ strapi }) => ({
|
|
1518
1848
|
async find(ctx) {
|
|
1519
|
-
const adminUserId = getAdminUserId$
|
|
1849
|
+
const adminUserId = getAdminUserId$2(ctx);
|
|
1520
1850
|
if (!adminUserId) {
|
|
1521
1851
|
ctx.status = 401;
|
|
1522
1852
|
ctx.body = { error: "Unauthorized" };
|
|
1523
1853
|
return;
|
|
1524
1854
|
}
|
|
1525
|
-
const conversations = await strapi.documents(CONTENT_TYPE$
|
|
1855
|
+
const conversations = await strapi.documents(CONTENT_TYPE$3).findMany({
|
|
1526
1856
|
filters: { adminUserId },
|
|
1527
1857
|
fields: ["title", "createdAt", "updatedAt"],
|
|
1528
1858
|
sort: { updatedAt: "desc" }
|
|
@@ -1530,14 +1860,14 @@ const conversationController = ({ strapi }) => ({
|
|
|
1530
1860
|
ctx.body = { data: conversations };
|
|
1531
1861
|
},
|
|
1532
1862
|
async findOne(ctx) {
|
|
1533
|
-
const adminUserId = getAdminUserId$
|
|
1863
|
+
const adminUserId = getAdminUserId$2(ctx);
|
|
1534
1864
|
if (!adminUserId) {
|
|
1535
1865
|
ctx.status = 401;
|
|
1536
1866
|
ctx.body = { error: "Unauthorized" };
|
|
1537
1867
|
return;
|
|
1538
1868
|
}
|
|
1539
1869
|
const { id } = ctx.params;
|
|
1540
|
-
const conversation2 = await strapi.documents(CONTENT_TYPE$
|
|
1870
|
+
const conversation2 = await strapi.documents(CONTENT_TYPE$3).findOne({
|
|
1541
1871
|
documentId: id
|
|
1542
1872
|
});
|
|
1543
1873
|
if (!conversation2 || conversation2.adminUserId !== adminUserId) {
|
|
@@ -1548,14 +1878,14 @@ const conversationController = ({ strapi }) => ({
|
|
|
1548
1878
|
ctx.body = { data: conversation2 };
|
|
1549
1879
|
},
|
|
1550
1880
|
async create(ctx) {
|
|
1551
|
-
const adminUserId = getAdminUserId$
|
|
1881
|
+
const adminUserId = getAdminUserId$2(ctx);
|
|
1552
1882
|
if (!adminUserId) {
|
|
1553
1883
|
ctx.status = 401;
|
|
1554
1884
|
ctx.body = { error: "Unauthorized" };
|
|
1555
1885
|
return;
|
|
1556
1886
|
}
|
|
1557
1887
|
const { title, messages } = ctx.request.body;
|
|
1558
|
-
const conversation2 = await strapi.documents(CONTENT_TYPE$
|
|
1888
|
+
const conversation2 = await strapi.documents(CONTENT_TYPE$3).create({
|
|
1559
1889
|
data: {
|
|
1560
1890
|
title: title || "New conversation",
|
|
1561
1891
|
messages: messages || [],
|
|
@@ -1566,14 +1896,14 @@ const conversationController = ({ strapi }) => ({
|
|
|
1566
1896
|
ctx.body = { data: conversation2 };
|
|
1567
1897
|
},
|
|
1568
1898
|
async update(ctx) {
|
|
1569
|
-
const adminUserId = getAdminUserId$
|
|
1899
|
+
const adminUserId = getAdminUserId$2(ctx);
|
|
1570
1900
|
if (!adminUserId) {
|
|
1571
1901
|
ctx.status = 401;
|
|
1572
1902
|
ctx.body = { error: "Unauthorized" };
|
|
1573
1903
|
return;
|
|
1574
1904
|
}
|
|
1575
1905
|
const { id } = ctx.params;
|
|
1576
|
-
const existing = await strapi.documents(CONTENT_TYPE$
|
|
1906
|
+
const existing = await strapi.documents(CONTENT_TYPE$3).findOne({
|
|
1577
1907
|
documentId: id
|
|
1578
1908
|
});
|
|
1579
1909
|
if (!existing || existing.adminUserId !== adminUserId) {
|
|
@@ -1585,21 +1915,21 @@ const conversationController = ({ strapi }) => ({
|
|
|
1585
1915
|
const data = {};
|
|
1586
1916
|
if (title !== void 0) data.title = title;
|
|
1587
1917
|
if (messages !== void 0) data.messages = messages;
|
|
1588
|
-
const conversation2 = await strapi.documents(CONTENT_TYPE$
|
|
1918
|
+
const conversation2 = await strapi.documents(CONTENT_TYPE$3).update({
|
|
1589
1919
|
documentId: id,
|
|
1590
1920
|
data
|
|
1591
1921
|
});
|
|
1592
1922
|
ctx.body = { data: conversation2 };
|
|
1593
1923
|
},
|
|
1594
1924
|
async delete(ctx) {
|
|
1595
|
-
const adminUserId = getAdminUserId$
|
|
1925
|
+
const adminUserId = getAdminUserId$2(ctx);
|
|
1596
1926
|
if (!adminUserId) {
|
|
1597
1927
|
ctx.status = 401;
|
|
1598
1928
|
ctx.body = { error: "Unauthorized" };
|
|
1599
1929
|
return;
|
|
1600
1930
|
}
|
|
1601
1931
|
const { id } = ctx.params;
|
|
1602
|
-
const existing = await strapi.documents(CONTENT_TYPE$
|
|
1932
|
+
const existing = await strapi.documents(CONTENT_TYPE$3).findOne({
|
|
1603
1933
|
documentId: id
|
|
1604
1934
|
});
|
|
1605
1935
|
if (!existing || existing.adminUserId !== adminUserId) {
|
|
@@ -1607,25 +1937,25 @@ const conversationController = ({ strapi }) => ({
|
|
|
1607
1937
|
ctx.body = { error: "Conversation not found" };
|
|
1608
1938
|
return;
|
|
1609
1939
|
}
|
|
1610
|
-
await strapi.documents(CONTENT_TYPE$
|
|
1940
|
+
await strapi.documents(CONTENT_TYPE$3).delete({ documentId: id });
|
|
1611
1941
|
ctx.status = 200;
|
|
1612
1942
|
ctx.body = { data: { documentId: id } };
|
|
1613
1943
|
}
|
|
1614
1944
|
});
|
|
1615
|
-
const CONTENT_TYPE$
|
|
1616
|
-
function getAdminUserId(ctx) {
|
|
1945
|
+
const CONTENT_TYPE$2 = "plugin::ai-sdk.memory";
|
|
1946
|
+
function getAdminUserId$1(ctx) {
|
|
1617
1947
|
const id = ctx.state?.user?.id;
|
|
1618
1948
|
return typeof id === "number" ? id : null;
|
|
1619
1949
|
}
|
|
1620
1950
|
const memoryController = ({ strapi }) => ({
|
|
1621
1951
|
async find(ctx) {
|
|
1622
|
-
const adminUserId = getAdminUserId(ctx);
|
|
1952
|
+
const adminUserId = getAdminUserId$1(ctx);
|
|
1623
1953
|
if (!adminUserId) {
|
|
1624
1954
|
ctx.status = 401;
|
|
1625
1955
|
ctx.body = { error: "Unauthorized" };
|
|
1626
1956
|
return;
|
|
1627
1957
|
}
|
|
1628
|
-
const memories = await strapi.documents(CONTENT_TYPE$
|
|
1958
|
+
const memories = await strapi.documents(CONTENT_TYPE$2).findMany({
|
|
1629
1959
|
filters: { adminUserId },
|
|
1630
1960
|
fields: ["content", "category", "createdAt"],
|
|
1631
1961
|
sort: { createdAt: "desc" }
|
|
@@ -1633,7 +1963,7 @@ const memoryController = ({ strapi }) => ({
|
|
|
1633
1963
|
ctx.body = { data: memories };
|
|
1634
1964
|
},
|
|
1635
1965
|
async create(ctx) {
|
|
1636
|
-
const adminUserId = getAdminUserId(ctx);
|
|
1966
|
+
const adminUserId = getAdminUserId$1(ctx);
|
|
1637
1967
|
if (!adminUserId) {
|
|
1638
1968
|
ctx.status = 401;
|
|
1639
1969
|
ctx.body = { error: "Unauthorized" };
|
|
@@ -1645,7 +1975,7 @@ const memoryController = ({ strapi }) => ({
|
|
|
1645
1975
|
ctx.body = { error: "content is required" };
|
|
1646
1976
|
return;
|
|
1647
1977
|
}
|
|
1648
|
-
const memory2 = await strapi.documents(CONTENT_TYPE$
|
|
1978
|
+
const memory2 = await strapi.documents(CONTENT_TYPE$2).create({
|
|
1649
1979
|
data: {
|
|
1650
1980
|
content,
|
|
1651
1981
|
category: category || "general",
|
|
@@ -1656,14 +1986,14 @@ const memoryController = ({ strapi }) => ({
|
|
|
1656
1986
|
ctx.body = { data: memory2 };
|
|
1657
1987
|
},
|
|
1658
1988
|
async update(ctx) {
|
|
1659
|
-
const adminUserId = getAdminUserId(ctx);
|
|
1989
|
+
const adminUserId = getAdminUserId$1(ctx);
|
|
1660
1990
|
if (!adminUserId) {
|
|
1661
1991
|
ctx.status = 401;
|
|
1662
1992
|
ctx.body = { error: "Unauthorized" };
|
|
1663
1993
|
return;
|
|
1664
1994
|
}
|
|
1665
1995
|
const { id } = ctx.params;
|
|
1666
|
-
const existing = await strapi.documents(CONTENT_TYPE$
|
|
1996
|
+
const existing = await strapi.documents(CONTENT_TYPE$2).findOne({
|
|
1667
1997
|
documentId: id
|
|
1668
1998
|
});
|
|
1669
1999
|
if (!existing || existing.adminUserId !== adminUserId) {
|
|
@@ -1675,21 +2005,21 @@ const memoryController = ({ strapi }) => ({
|
|
|
1675
2005
|
const data = {};
|
|
1676
2006
|
if (content !== void 0) data.content = content;
|
|
1677
2007
|
if (category !== void 0) data.category = category;
|
|
1678
|
-
const memory2 = await strapi.documents(CONTENT_TYPE$
|
|
2008
|
+
const memory2 = await strapi.documents(CONTENT_TYPE$2).update({
|
|
1679
2009
|
documentId: id,
|
|
1680
2010
|
data
|
|
1681
2011
|
});
|
|
1682
2012
|
ctx.body = { data: memory2 };
|
|
1683
2013
|
},
|
|
1684
2014
|
async delete(ctx) {
|
|
1685
|
-
const adminUserId = getAdminUserId(ctx);
|
|
2015
|
+
const adminUserId = getAdminUserId$1(ctx);
|
|
1686
2016
|
if (!adminUserId) {
|
|
1687
2017
|
ctx.status = 401;
|
|
1688
2018
|
ctx.body = { error: "Unauthorized" };
|
|
1689
2019
|
return;
|
|
1690
2020
|
}
|
|
1691
2021
|
const { id } = ctx.params;
|
|
1692
|
-
const existing = await strapi.documents(CONTENT_TYPE$
|
|
2022
|
+
const existing = await strapi.documents(CONTENT_TYPE$2).findOne({
|
|
1693
2023
|
documentId: id
|
|
1694
2024
|
});
|
|
1695
2025
|
if (!existing || existing.adminUserId !== adminUserId) {
|
|
@@ -1697,15 +2027,15 @@ const memoryController = ({ strapi }) => ({
|
|
|
1697
2027
|
ctx.body = { error: "Memory not found" };
|
|
1698
2028
|
return;
|
|
1699
2029
|
}
|
|
1700
|
-
await strapi.documents(CONTENT_TYPE$
|
|
2030
|
+
await strapi.documents(CONTENT_TYPE$2).delete({ documentId: id });
|
|
1701
2031
|
ctx.status = 200;
|
|
1702
2032
|
ctx.body = { data: { documentId: id } };
|
|
1703
2033
|
}
|
|
1704
2034
|
});
|
|
1705
|
-
const CONTENT_TYPE = "plugin::ai-sdk.public-memory";
|
|
2035
|
+
const CONTENT_TYPE$1 = "plugin::ai-sdk.public-memory";
|
|
1706
2036
|
const publicMemoryController = ({ strapi }) => ({
|
|
1707
2037
|
async find(ctx) {
|
|
1708
|
-
const memories = await strapi.documents(CONTENT_TYPE).findMany({
|
|
2038
|
+
const memories = await strapi.documents(CONTENT_TYPE$1).findMany({
|
|
1709
2039
|
fields: ["content", "category", "createdAt"],
|
|
1710
2040
|
sort: { createdAt: "desc" }
|
|
1711
2041
|
});
|
|
@@ -1718,7 +2048,7 @@ const publicMemoryController = ({ strapi }) => ({
|
|
|
1718
2048
|
ctx.body = { error: "content is required" };
|
|
1719
2049
|
return;
|
|
1720
2050
|
}
|
|
1721
|
-
const memory2 = await strapi.documents(CONTENT_TYPE).create({
|
|
2051
|
+
const memory2 = await strapi.documents(CONTENT_TYPE$1).create({
|
|
1722
2052
|
data: { content, category: category || "general" }
|
|
1723
2053
|
});
|
|
1724
2054
|
ctx.status = 201;
|
|
@@ -1726,7 +2056,7 @@ const publicMemoryController = ({ strapi }) => ({
|
|
|
1726
2056
|
},
|
|
1727
2057
|
async update(ctx) {
|
|
1728
2058
|
const { id } = ctx.params;
|
|
1729
|
-
const existing = await strapi.documents(CONTENT_TYPE).findOne({ documentId: id });
|
|
2059
|
+
const existing = await strapi.documents(CONTENT_TYPE$1).findOne({ documentId: id });
|
|
1730
2060
|
if (!existing) {
|
|
1731
2061
|
ctx.status = 404;
|
|
1732
2062
|
ctx.body = { error: "Public memory not found" };
|
|
@@ -1736,7 +2066,7 @@ const publicMemoryController = ({ strapi }) => ({
|
|
|
1736
2066
|
const data = {};
|
|
1737
2067
|
if (content !== void 0) data.content = content;
|
|
1738
2068
|
if (category !== void 0) data.category = category;
|
|
1739
|
-
const memory2 = await strapi.documents(CONTENT_TYPE).update({
|
|
2069
|
+
const memory2 = await strapi.documents(CONTENT_TYPE$1).update({
|
|
1740
2070
|
documentId: id,
|
|
1741
2071
|
data
|
|
1742
2072
|
});
|
|
@@ -1744,12 +2074,103 @@ const publicMemoryController = ({ strapi }) => ({
|
|
|
1744
2074
|
},
|
|
1745
2075
|
async delete(ctx) {
|
|
1746
2076
|
const { id } = ctx.params;
|
|
1747
|
-
const existing = await strapi.documents(CONTENT_TYPE).findOne({ documentId: id });
|
|
2077
|
+
const existing = await strapi.documents(CONTENT_TYPE$1).findOne({ documentId: id });
|
|
1748
2078
|
if (!existing) {
|
|
1749
2079
|
ctx.status = 404;
|
|
1750
2080
|
ctx.body = { error: "Public memory not found" };
|
|
1751
2081
|
return;
|
|
1752
2082
|
}
|
|
2083
|
+
await strapi.documents(CONTENT_TYPE$1).delete({ documentId: id });
|
|
2084
|
+
ctx.status = 200;
|
|
2085
|
+
ctx.body = { data: { documentId: id } };
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
const CONTENT_TYPE = "plugin::ai-sdk.task";
|
|
2089
|
+
function getAdminUserId(ctx) {
|
|
2090
|
+
const id = ctx.state?.user?.id;
|
|
2091
|
+
return typeof id === "number" ? id : null;
|
|
2092
|
+
}
|
|
2093
|
+
const taskController = ({ strapi }) => ({
|
|
2094
|
+
async find(ctx) {
|
|
2095
|
+
const adminUserId = getAdminUserId(ctx);
|
|
2096
|
+
if (!adminUserId) {
|
|
2097
|
+
ctx.status = 401;
|
|
2098
|
+
ctx.body = { error: "Unauthorized" };
|
|
2099
|
+
return;
|
|
2100
|
+
}
|
|
2101
|
+
const tasks = await strapi.documents(CONTENT_TYPE).findMany({
|
|
2102
|
+
filters: { adminUserId },
|
|
2103
|
+
sort: { createdAt: "desc" }
|
|
2104
|
+
});
|
|
2105
|
+
ctx.body = { data: tasks };
|
|
2106
|
+
},
|
|
2107
|
+
async create(ctx) {
|
|
2108
|
+
const adminUserId = getAdminUserId(ctx);
|
|
2109
|
+
if (!adminUserId) {
|
|
2110
|
+
ctx.status = 401;
|
|
2111
|
+
ctx.body = { error: "Unauthorized" };
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
const body = ctx.request.body;
|
|
2115
|
+
const task2 = await strapi.documents(CONTENT_TYPE).create({
|
|
2116
|
+
data: {
|
|
2117
|
+
title: body.title,
|
|
2118
|
+
description: body.description,
|
|
2119
|
+
content: body.content,
|
|
2120
|
+
done: body.done ?? false,
|
|
2121
|
+
priority: body.priority ?? "medium",
|
|
2122
|
+
consequence: body.consequence ?? 3,
|
|
2123
|
+
impact: body.impact ?? 3,
|
|
2124
|
+
dueDate: body.dueDate,
|
|
2125
|
+
adminUserId
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
2128
|
+
ctx.status = 201;
|
|
2129
|
+
ctx.body = { data: task2 };
|
|
2130
|
+
},
|
|
2131
|
+
async update(ctx) {
|
|
2132
|
+
const adminUserId = getAdminUserId(ctx);
|
|
2133
|
+
if (!adminUserId) {
|
|
2134
|
+
ctx.status = 401;
|
|
2135
|
+
ctx.body = { error: "Unauthorized" };
|
|
2136
|
+
return;
|
|
2137
|
+
}
|
|
2138
|
+
const { id } = ctx.params;
|
|
2139
|
+
const existing = await strapi.documents(CONTENT_TYPE).findOne({
|
|
2140
|
+
documentId: id
|
|
2141
|
+
});
|
|
2142
|
+
if (!existing || existing.adminUserId !== adminUserId) {
|
|
2143
|
+
ctx.status = 404;
|
|
2144
|
+
ctx.body = { error: "Task not found" };
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
const body = ctx.request.body;
|
|
2148
|
+
const data = {};
|
|
2149
|
+
for (const key of ["title", "description", "content", "done", "priority", "consequence", "impact", "dueDate"]) {
|
|
2150
|
+
if (body[key] !== void 0) data[key] = body[key];
|
|
2151
|
+
}
|
|
2152
|
+
const task2 = await strapi.documents(CONTENT_TYPE).update({
|
|
2153
|
+
documentId: id,
|
|
2154
|
+
data
|
|
2155
|
+
});
|
|
2156
|
+
ctx.body = { data: task2 };
|
|
2157
|
+
},
|
|
2158
|
+
async delete(ctx) {
|
|
2159
|
+
const adminUserId = getAdminUserId(ctx);
|
|
2160
|
+
if (!adminUserId) {
|
|
2161
|
+
ctx.status = 401;
|
|
2162
|
+
ctx.body = { error: "Unauthorized" };
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
const { id } = ctx.params;
|
|
2166
|
+
const existing = await strapi.documents(CONTENT_TYPE).findOne({
|
|
2167
|
+
documentId: id
|
|
2168
|
+
});
|
|
2169
|
+
if (!existing || existing.adminUserId !== adminUserId) {
|
|
2170
|
+
ctx.status = 404;
|
|
2171
|
+
ctx.body = { error: "Task not found" };
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
1753
2174
|
await strapi.documents(CONTENT_TYPE).delete({ documentId: id });
|
|
1754
2175
|
ctx.status = 200;
|
|
1755
2176
|
ctx.body = { data: { documentId: id } };
|
|
@@ -1760,7 +2181,8 @@ const controllers = {
|
|
|
1760
2181
|
mcp: mcpController,
|
|
1761
2182
|
conversation: conversationController,
|
|
1762
2183
|
memory: memoryController,
|
|
1763
|
-
"public-memory": publicMemoryController
|
|
2184
|
+
"public-memory": publicMemoryController,
|
|
2185
|
+
task: taskController
|
|
1764
2186
|
};
|
|
1765
2187
|
const promptInjection = [
|
|
1766
2188
|
"ignore (all |any )?(previous|prior|above) (instructions|prompts|rules)",
|
|
@@ -2100,6 +2522,30 @@ const adminAPIRoutes = {
|
|
|
2100
2522
|
path: "/public-memories/:id",
|
|
2101
2523
|
handler: "public-memory.delete",
|
|
2102
2524
|
config: { policies: [] }
|
|
2525
|
+
},
|
|
2526
|
+
{
|
|
2527
|
+
method: "GET",
|
|
2528
|
+
path: "/tasks",
|
|
2529
|
+
handler: "task.find",
|
|
2530
|
+
config: { policies: [] }
|
|
2531
|
+
},
|
|
2532
|
+
{
|
|
2533
|
+
method: "POST",
|
|
2534
|
+
path: "/tasks",
|
|
2535
|
+
handler: "task.create",
|
|
2536
|
+
config: { policies: [] }
|
|
2537
|
+
},
|
|
2538
|
+
{
|
|
2539
|
+
method: "PUT",
|
|
2540
|
+
path: "/tasks/:id",
|
|
2541
|
+
handler: "task.update",
|
|
2542
|
+
config: { policies: [] }
|
|
2543
|
+
},
|
|
2544
|
+
{
|
|
2545
|
+
method: "DELETE",
|
|
2546
|
+
path: "/tasks/:id",
|
|
2547
|
+
handler: "task.delete",
|
|
2548
|
+
config: { policies: [] }
|
|
2103
2549
|
}
|
|
2104
2550
|
]
|
|
2105
2551
|
};
|
|
@@ -2177,12 +2623,16 @@ const DEFAULT_PREAMBLE = `You are a Strapi CMS assistant. Use your tools to fulf
|
|
|
2177
2623
|
|
|
2178
2624
|
For analytics and counting questions (e.g. "how many", "count", "distribution", "trends", "breakdown"), use the aggregateContent tool instead of searchContent — it is faster and purpose-built for these queries. Present analytics results as markdown tables. After showing analytics results, suggest 2-3 follow-up questions the user might find useful under a "**You might also want to know:**" heading.
|
|
2179
2625
|
|
|
2626
|
+
Plugin tools: When specialized tools from plugins are available (listed below), ALWAYS prefer them over the generic searchContent tool. For example, use searchMentions for social mentions (it has BM25 relevance scoring), semanticSearch for vector similarity search across embeddings, and ragQuery for question-answering grounded in embedded content. Only fall back to searchContent when no specialized tool covers the query.
|
|
2627
|
+
|
|
2180
2628
|
Strapi filter syntax for searchContent and aggregateContent:
|
|
2181
2629
|
- Scalar fields: { title: { $containsi: "hello" } }
|
|
2182
2630
|
- Relation (manyToOne): { author: { name: { $eq: "John" } } }
|
|
2183
2631
|
- Relation (manyToMany): { contentTags: { title: { $eq: "tutorial" } } }
|
|
2184
2632
|
- Always nest relation filters as: { relationField: { fieldOnRelatedType: { $operator: value } } }
|
|
2185
|
-
- Never use flat dot-path syntax like "contentTags.title" in filters — always use nested objects
|
|
2633
|
+
- Never use flat dot-path syntax like "contentTags.title" in filters — always use nested objects.
|
|
2634
|
+
|
|
2635
|
+
Task management: You have a manageTask tool for tracking the user's tasks. At the START of every conversation, proactively use manageTask with action "summary" to check for open tasks, then greet the user with a brief status and suggest what to tackle next based on consequence × impact score. When the user mentions action items, commitments, or things they need to do during conversation, proactively create tasks by calling manageTask with action "create" — do NOT include consequence or impact scores, just omit them. A UI form will appear in the chat for the user to set scores and confirm. Never ask for scores in text. When presenting task lists, use markdown tables.`;
|
|
2186
2636
|
const DEFAULT_PUBLIC_PREAMBLE = `You are a helpful public assistant for this website. Use your tools to answer questions about the site content. You cannot modify any content or perform administrative actions.
|
|
2187
2637
|
|
|
2188
2638
|
For analytics and counting questions (e.g. "how many", "count", "distribution", "trends", "breakdown"), use the aggregateContent tool instead of searchContent — it is faster and purpose-built for these queries. Present analytics results as markdown tables. After showing analytics results, suggest 2-3 follow-up questions the user might find useful under a "**You might also want to know:**" heading.
|