strapi-plugin-ai-sdk 0.6.8 → 0.6.9
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/dist/server/index.js
CHANGED
|
@@ -297,7 +297,7 @@ const searchContentSchema = zod.z.object({
|
|
|
297
297
|
'The content type UID to search, e.g. "api::article.article" or "plugin::users-permissions.user"'
|
|
298
298
|
),
|
|
299
299
|
query: zod.z.string().optional().describe("Full-text search query string (searches across all searchable text fields)"),
|
|
300
|
-
filters: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe('Strapi filter object
|
|
300
|
+
filters: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe('Strapi filter object. Scalar: { title: { $containsi: "hello" } }. Relation: { author: { name: { $eq: "John" } } }. ManyToMany: { contentTags: { title: { $eq: "tutorial" } } }. Operators: $eq, $ne, $containsi, $in, $gt, $lt, $gte, $lte, $null, $notNull.'),
|
|
301
301
|
fields: zod.z.array(zod.z.string()).optional().describe("Specific fields to return. If omitted, returns all fields (large content fields stripped unless includeContent is true)."),
|
|
302
302
|
sort: zod.z.string().optional().describe('Sort order, e.g. "createdAt:desc"'),
|
|
303
303
|
page: zod.z.number().optional().default(1).describe("Page number (starts at 1)"),
|
|
@@ -307,7 +307,7 @@ const searchContentSchema = zod.z.object({
|
|
|
307
307
|
populate: zod.z.union([zod.z.string(), zod.z.array(zod.z.string()), zod.z.record(zod.z.string(), zod.z.unknown())]).optional().describe('Relations to populate. Defaults to "*" (all). Can be a string, array, or object.'),
|
|
308
308
|
includeContent: zod.z.boolean().optional().default(false).describe("When true, includes large content fields (content, blocks, body, etc.) in results. Default false to reduce context size.")
|
|
309
309
|
});
|
|
310
|
-
const searchContentDescription = 'Search and query any Strapi content type. Use listContentTypes first to discover available content types and their fields, then use this tool to query specific collections. Use sort (e.g. "createdAt:desc") and pageSize: 1 to get the latest entry. By default, large content fields are stripped from results — set includeContent to true or use fields to get full content.';
|
|
310
|
+
const searchContentDescription = 'Search and query any Strapi content type. Use listContentTypes first to discover available content types and their fields, then use this tool to query specific collections. Use sort (e.g. "createdAt:desc") and pageSize: 1 to get the latest entry. By default, large content fields are stripped from results — set includeContent to true or use fields to get full content. To filter by a relation, nest the filter: { relationField: { fieldOnRelation: { $operator: "value" } } }.';
|
|
311
311
|
function stripLargeFields(obj) {
|
|
312
312
|
const stripped = {};
|
|
313
313
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -706,7 +706,7 @@ const aggregateContentSchema = zod.z.object({
|
|
|
706
706
|
operation: zod.z.enum(["count", "countByField", "countByDateRange"]).describe(
|
|
707
707
|
"count — total count; countByField — group by a field; countByDateRange — bucket by date"
|
|
708
708
|
),
|
|
709
|
-
filters: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe('Strapi filter object
|
|
709
|
+
filters: zod.z.record(zod.z.string(), zod.z.unknown()).optional().describe('Strapi filter object. Scalar: { title: { $containsi: "hello" } }. Relation: { author: { name: { $eq: "John" } } }. ManyToMany: { contentTags: { title: { $eq: "tutorial" } } }.'),
|
|
710
710
|
groupByField: zod.z.string().optional().describe('Field to group by for countByField. Just use the field name — relation fields are auto-resolved to their display name (e.g. "author", "category"). You can also use dot paths like "author.email" for a specific sub-field.'),
|
|
711
711
|
dateField: zod.z.string().optional().default("createdAt").describe('Date field for countByDateRange (default: "createdAt")'),
|
|
712
712
|
granularity: zod.z.enum(["day", "week", "month"]).optional().default("month").describe("Bucket granularity for countByDateRange"),
|
|
@@ -2193,8 +2193,26 @@ function describeTools(tools) {
|
|
|
2193
2193
|
return `Available tools:
|
|
2194
2194
|
${lines.join("\n")}`;
|
|
2195
2195
|
}
|
|
2196
|
-
const DEFAULT_PREAMBLE =
|
|
2197
|
-
|
|
2196
|
+
const DEFAULT_PREAMBLE = `You are a Strapi CMS assistant. Use your tools to fulfill user requests. When asked to create or update content, use the appropriate tool — do not tell the user you cannot. When performing bulk operations (e.g. publish multiple items), call multiple tools in parallel in a single step rather than one at a time.
|
|
2197
|
+
|
|
2198
|
+
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.
|
|
2199
|
+
|
|
2200
|
+
Strapi filter syntax for searchContent and aggregateContent:
|
|
2201
|
+
- Scalar fields: { title: { $containsi: "hello" } }
|
|
2202
|
+
- Relation (manyToOne): { author: { name: { $eq: "John" } } }
|
|
2203
|
+
- Relation (manyToMany): { contentTags: { title: { $eq: "tutorial" } } }
|
|
2204
|
+
- Always nest relation filters as: { relationField: { fieldOnRelatedType: { $operator: value } } }
|
|
2205
|
+
- Never use flat dot-path syntax like "contentTags.title" in filters — always use nested objects.`;
|
|
2206
|
+
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.
|
|
2207
|
+
|
|
2208
|
+
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.
|
|
2209
|
+
|
|
2210
|
+
Strapi filter syntax for searchContent and aggregateContent:
|
|
2211
|
+
- Scalar fields: { title: { $containsi: "hello" } }
|
|
2212
|
+
- Relation (manyToOne): { author: { name: { $eq: "John" } } }
|
|
2213
|
+
- Relation (manyToMany): { contentTags: { title: { $eq: "tutorial" } } }
|
|
2214
|
+
- Always nest relation filters as: { relationField: { fieldOnRelatedType: { $operator: value } } }
|
|
2215
|
+
- Never use flat dot-path syntax like "contentTags.title" in filters — always use nested objects.`;
|
|
2198
2216
|
function composeSystemPrompt(config2, toolsDescription, override) {
|
|
2199
2217
|
const base = override || config2?.systemPrompt || DEFAULT_PREAMBLE;
|
|
2200
2218
|
if (base.includes("{tools}")) {
|
package/dist/server/index.mjs
CHANGED
|
@@ -277,7 +277,7 @@ const searchContentSchema = z.object({
|
|
|
277
277
|
'The content type UID to search, e.g. "api::article.article" or "plugin::users-permissions.user"'
|
|
278
278
|
),
|
|
279
279
|
query: z.string().optional().describe("Full-text search query string (searches across all searchable text fields)"),
|
|
280
|
-
filters: z.record(z.string(), z.unknown()).optional().describe('Strapi filter object
|
|
280
|
+
filters: z.record(z.string(), z.unknown()).optional().describe('Strapi filter object. Scalar: { title: { $containsi: "hello" } }. Relation: { author: { name: { $eq: "John" } } }. ManyToMany: { contentTags: { title: { $eq: "tutorial" } } }. Operators: $eq, $ne, $containsi, $in, $gt, $lt, $gte, $lte, $null, $notNull.'),
|
|
281
281
|
fields: z.array(z.string()).optional().describe("Specific fields to return. If omitted, returns all fields (large content fields stripped unless includeContent is true)."),
|
|
282
282
|
sort: z.string().optional().describe('Sort order, e.g. "createdAt:desc"'),
|
|
283
283
|
page: z.number().optional().default(1).describe("Page number (starts at 1)"),
|
|
@@ -287,7 +287,7 @@ const searchContentSchema = z.object({
|
|
|
287
287
|
populate: z.union([z.string(), z.array(z.string()), z.record(z.string(), z.unknown())]).optional().describe('Relations to populate. Defaults to "*" (all). Can be a string, array, or object.'),
|
|
288
288
|
includeContent: z.boolean().optional().default(false).describe("When true, includes large content fields (content, blocks, body, etc.) in results. Default false to reduce context size.")
|
|
289
289
|
});
|
|
290
|
-
const searchContentDescription = 'Search and query any Strapi content type. Use listContentTypes first to discover available content types and their fields, then use this tool to query specific collections. Use sort (e.g. "createdAt:desc") and pageSize: 1 to get the latest entry. By default, large content fields are stripped from results — set includeContent to true or use fields to get full content.';
|
|
290
|
+
const searchContentDescription = 'Search and query any Strapi content type. Use listContentTypes first to discover available content types and their fields, then use this tool to query specific collections. Use sort (e.g. "createdAt:desc") and pageSize: 1 to get the latest entry. By default, large content fields are stripped from results — set includeContent to true or use fields to get full content. To filter by a relation, nest the filter: { relationField: { fieldOnRelation: { $operator: "value" } } }.';
|
|
291
291
|
function stripLargeFields(obj) {
|
|
292
292
|
const stripped = {};
|
|
293
293
|
for (const [key, value] of Object.entries(obj)) {
|
|
@@ -686,7 +686,7 @@ const aggregateContentSchema = z.object({
|
|
|
686
686
|
operation: z.enum(["count", "countByField", "countByDateRange"]).describe(
|
|
687
687
|
"count — total count; countByField — group by a field; countByDateRange — bucket by date"
|
|
688
688
|
),
|
|
689
|
-
filters: z.record(z.string(), z.unknown()).optional().describe('Strapi filter object
|
|
689
|
+
filters: z.record(z.string(), z.unknown()).optional().describe('Strapi filter object. Scalar: { title: { $containsi: "hello" } }. Relation: { author: { name: { $eq: "John" } } }. ManyToMany: { contentTags: { title: { $eq: "tutorial" } } }.'),
|
|
690
690
|
groupByField: z.string().optional().describe('Field to group by for countByField. Just use the field name — relation fields are auto-resolved to their display name (e.g. "author", "category"). You can also use dot paths like "author.email" for a specific sub-field.'),
|
|
691
691
|
dateField: z.string().optional().default("createdAt").describe('Date field for countByDateRange (default: "createdAt")'),
|
|
692
692
|
granularity: z.enum(["day", "week", "month"]).optional().default("month").describe("Bucket granularity for countByDateRange"),
|
|
@@ -2173,8 +2173,26 @@ function describeTools(tools) {
|
|
|
2173
2173
|
return `Available tools:
|
|
2174
2174
|
${lines.join("\n")}`;
|
|
2175
2175
|
}
|
|
2176
|
-
const DEFAULT_PREAMBLE =
|
|
2177
|
-
|
|
2176
|
+
const DEFAULT_PREAMBLE = `You are a Strapi CMS assistant. Use your tools to fulfill user requests. When asked to create or update content, use the appropriate tool — do not tell the user you cannot. When performing bulk operations (e.g. publish multiple items), call multiple tools in parallel in a single step rather than one at a time.
|
|
2177
|
+
|
|
2178
|
+
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
|
+
|
|
2180
|
+
Strapi filter syntax for searchContent and aggregateContent:
|
|
2181
|
+
- Scalar fields: { title: { $containsi: "hello" } }
|
|
2182
|
+
- Relation (manyToOne): { author: { name: { $eq: "John" } } }
|
|
2183
|
+
- Relation (manyToMany): { contentTags: { title: { $eq: "tutorial" } } }
|
|
2184
|
+
- 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.`;
|
|
2186
|
+
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
|
+
|
|
2188
|
+
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.
|
|
2189
|
+
|
|
2190
|
+
Strapi filter syntax for searchContent and aggregateContent:
|
|
2191
|
+
- Scalar fields: { title: { $containsi: "hello" } }
|
|
2192
|
+
- Relation (manyToOne): { author: { name: { $eq: "John" } } }
|
|
2193
|
+
- Relation (manyToMany): { contentTags: { title: { $eq: "tutorial" } } }
|
|
2194
|
+
- Always nest relation filters as: { relationField: { fieldOnRelatedType: { $operator: value } } }
|
|
2195
|
+
- Never use flat dot-path syntax like "contentTags.title" in filters — always use nested objects.`;
|
|
2178
2196
|
function composeSystemPrompt(config2, toolsDescription, override) {
|
|
2179
2197
|
const base = override || config2?.systemPrompt || DEFAULT_PREAMBLE;
|
|
2180
2198
|
if (base.includes("{tools}")) {
|
|
@@ -16,7 +16,7 @@ export declare const searchContentSchema: z.ZodObject<{
|
|
|
16
16
|
populate: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>, z.ZodRecord<z.ZodString, z.ZodUnknown>]>>;
|
|
17
17
|
includeContent: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
18
18
|
}, z.core.$strip>;
|
|
19
|
-
export declare const searchContentDescription = "Search and query any Strapi content type. Use listContentTypes first to discover available content types and their fields, then use this tool to query specific collections. Use sort (e.g. \"createdAt:desc\") and pageSize: 1 to get the latest entry. By default, large content fields are stripped from results \u2014 set includeContent to true or use fields to get full content.";
|
|
19
|
+
export declare const searchContentDescription = "Search and query any Strapi content type. Use listContentTypes first to discover available content types and their fields, then use this tool to query specific collections. Use sort (e.g. \"createdAt:desc\") and pageSize: 1 to get the latest entry. By default, large content fields are stripped from results \u2014 set includeContent to true or use fields to get full content. To filter by a relation, nest the filter: { relationField: { fieldOnRelation: { $operator: \"value\" } } }.";
|
|
20
20
|
export interface SearchContentParams {
|
|
21
21
|
contentType: string;
|
|
22
22
|
query?: string;
|
package/package.json
CHANGED