strapi-plugin-ai-sdk 0.7.9 → 0.8.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.
@@ -3131,6 +3131,26 @@ function describeTools(tools) {
3131
3131
  return `Available tools:
3132
3132
  ${lines.join("\n")}`;
3133
3133
  }
3134
+ function trimMessages(messages, max) {
3135
+ if (messages.length <= max) return messages;
3136
+ const sliced = messages.slice(-max);
3137
+ while (sliced.length > 0 && hasOrphanedToolCalls(sliced[0])) {
3138
+ sliced.shift();
3139
+ }
3140
+ return sliced;
3141
+ }
3142
+ function hasOrphanedToolCalls(message) {
3143
+ if (message.role !== "assistant") return false;
3144
+ if (message.parts) {
3145
+ return message.parts.some(
3146
+ (part) => part.type === "tool-invocation"
3147
+ );
3148
+ }
3149
+ if (message.toolInvocations?.length) {
3150
+ return true;
3151
+ }
3152
+ return false;
3153
+ }
3134
3154
  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.
3135
3155
 
3136
3156
  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.
@@ -3194,7 +3214,7 @@ const service = ({ strapi }) => {
3194
3214
  const maxMessages = config2?.maxConversationMessages ?? DEFAULT_MAX_CONVERSATION_MESSAGES;
3195
3215
  const maxOutputTokens = config2?.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
3196
3216
  const maxSteps = config2?.maxSteps ?? DEFAULT_MAX_STEPS;
3197
- const trimmedMessages = messages.length > maxMessages ? messages.slice(-maxMessages) : messages;
3217
+ const trimmedMessages = trimMessages(messages, maxMessages);
3198
3218
  const modelMessages = await ai.convertToModelMessages(trimmedMessages);
3199
3219
  const tools = createTools(strapi, { adminUserId: options2?.adminUserId, enabledToolSources: options2?.enabledToolSources });
3200
3220
  const toolsDescription = describeTools(tools);
@@ -3239,7 +3259,7 @@ ${lines.join("\n")}`;
3239
3259
  const publicModel = publicConfig?.chatModel ?? DEFAULT_PUBLIC_CHAT_MODEL;
3240
3260
  const allowedContentTypes = publicConfig?.allowedContentTypes ?? [];
3241
3261
  const publicToolSources = publicConfig?.publicToolSources;
3242
- const trimmedMessages = messages.length > maxMessages ? messages.slice(-maxMessages) : messages;
3262
+ const trimmedMessages = trimMessages(messages, maxMessages);
3243
3263
  const modelMessages = await ai.convertToModelMessages(trimmedMessages);
3244
3264
  const tools = createPublicTools(strapi, allowedContentTypes, publicToolSources);
3245
3265
  const toolsDescription = describeTools(tools);
@@ -3111,6 +3111,26 @@ function describeTools(tools) {
3111
3111
  return `Available tools:
3112
3112
  ${lines.join("\n")}`;
3113
3113
  }
3114
+ function trimMessages(messages, max) {
3115
+ if (messages.length <= max) return messages;
3116
+ const sliced = messages.slice(-max);
3117
+ while (sliced.length > 0 && hasOrphanedToolCalls(sliced[0])) {
3118
+ sliced.shift();
3119
+ }
3120
+ return sliced;
3121
+ }
3122
+ function hasOrphanedToolCalls(message) {
3123
+ if (message.role !== "assistant") return false;
3124
+ if (message.parts) {
3125
+ return message.parts.some(
3126
+ (part) => part.type === "tool-invocation"
3127
+ );
3128
+ }
3129
+ if (message.toolInvocations?.length) {
3130
+ return true;
3131
+ }
3132
+ return false;
3133
+ }
3114
3134
  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.
3115
3135
 
3116
3136
  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.
@@ -3174,7 +3194,7 @@ const service = ({ strapi }) => {
3174
3194
  const maxMessages = config2?.maxConversationMessages ?? DEFAULT_MAX_CONVERSATION_MESSAGES;
3175
3195
  const maxOutputTokens = config2?.maxOutputTokens ?? DEFAULT_MAX_OUTPUT_TOKENS;
3176
3196
  const maxSteps = config2?.maxSteps ?? DEFAULT_MAX_STEPS;
3177
- const trimmedMessages = messages.length > maxMessages ? messages.slice(-maxMessages) : messages;
3197
+ const trimmedMessages = trimMessages(messages, maxMessages);
3178
3198
  const modelMessages = await convertToModelMessages(trimmedMessages);
3179
3199
  const tools = createTools(strapi, { adminUserId: options2?.adminUserId, enabledToolSources: options2?.enabledToolSources });
3180
3200
  const toolsDescription = describeTools(tools);
@@ -3219,7 +3239,7 @@ ${lines.join("\n")}`;
3219
3239
  const publicModel = publicConfig?.chatModel ?? DEFAULT_PUBLIC_CHAT_MODEL;
3220
3240
  const allowedContentTypes = publicConfig?.allowedContentTypes ?? [];
3221
3241
  const publicToolSources = publicConfig?.publicToolSources;
3222
- const trimmedMessages = messages.length > maxMessages ? messages.slice(-maxMessages) : messages;
3242
+ const trimmedMessages = trimMessages(messages, maxMessages);
3223
3243
  const modelMessages = await convertToModelMessages(trimmedMessages);
3224
3244
  const tools = createPublicTools(strapi, allowedContentTypes, publicToolSources);
3225
3245
  const toolsDescription = describeTools(tools);
@@ -0,0 +1,11 @@
1
+ import type { UIMessage } from 'ai';
2
+ /**
3
+ * Trim messages to a max count while keeping tool call/result pairs intact.
4
+ *
5
+ * When slicing from the end, the first remaining message might be an assistant
6
+ * message with tool invocations whose results lived in earlier (now-dropped)
7
+ * messages. The AI SDK throws MissingToolResultsError if it encounters an
8
+ * unmatched tool call. This function drops leading assistant messages that
9
+ * contain tool invocations to prevent that.
10
+ */
11
+ export declare function trimMessages(messages: UIMessage[], max: number): UIMessage[];
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.7.9",
2
+ "version": "0.8.0",
3
3
  "keywords": [
4
4
  "strapi",
5
5
  "strapi-plugin",