@sqlrooms/ai-core 0.26.0-rc.6 → 0.26.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.
Files changed (85) hide show
  1. package/README.md +171 -2
  2. package/dist/AiSlice.d.ts +35 -5
  3. package/dist/AiSlice.d.ts.map +1 -1
  4. package/dist/AiSlice.js +148 -14
  5. package/dist/AiSlice.js.map +1 -1
  6. package/dist/agents/AgentUtils.d.ts +61 -0
  7. package/dist/agents/AgentUtils.d.ts.map +1 -0
  8. package/dist/agents/AgentUtils.js +90 -0
  9. package/dist/agents/AgentUtils.js.map +1 -0
  10. package/dist/chatTransport.d.ts +17 -4
  11. package/dist/chatTransport.d.ts.map +1 -1
  12. package/dist/chatTransport.js +244 -19
  13. package/dist/chatTransport.js.map +1 -1
  14. package/dist/components/AnalysisAnswer.d.ts +2 -0
  15. package/dist/components/AnalysisAnswer.d.ts.map +1 -1
  16. package/dist/components/AnalysisAnswer.js +4 -2
  17. package/dist/components/AnalysisAnswer.js.map +1 -1
  18. package/dist/components/AnalysisResult.d.ts +7 -0
  19. package/dist/components/AnalysisResult.d.ts.map +1 -1
  20. package/dist/components/AnalysisResult.js +42 -42
  21. package/dist/components/AnalysisResult.js.map +1 -1
  22. package/dist/components/AnalysisResultsContainer.d.ts +4 -0
  23. package/dist/components/AnalysisResultsContainer.d.ts.map +1 -1
  24. package/dist/components/AnalysisResultsContainer.js +11 -4
  25. package/dist/components/AnalysisResultsContainer.js.map +1 -1
  26. package/dist/components/DeleteConfirmationDialog.d.ts +14 -0
  27. package/dist/components/DeleteConfirmationDialog.d.ts.map +1 -0
  28. package/dist/components/DeleteConfirmationDialog.js +6 -0
  29. package/dist/components/DeleteConfirmationDialog.js.map +1 -0
  30. package/dist/components/GroupedMessageParts.d.ts +25 -0
  31. package/dist/components/GroupedMessageParts.d.ts.map +1 -0
  32. package/dist/components/GroupedMessageParts.js +34 -0
  33. package/dist/components/GroupedMessageParts.js.map +1 -0
  34. package/dist/components/MessagePartsList.d.ts +23 -0
  35. package/dist/components/MessagePartsList.d.ts.map +1 -0
  36. package/dist/components/MessagePartsList.js +27 -0
  37. package/dist/components/MessagePartsList.js.map +1 -0
  38. package/dist/components/PromptSuggestions.d.ts +32 -0
  39. package/dist/components/PromptSuggestions.d.ts.map +1 -0
  40. package/dist/components/PromptSuggestions.js +69 -0
  41. package/dist/components/PromptSuggestions.js.map +1 -0
  42. package/dist/components/QueryControls.d.ts.map +1 -1
  43. package/dist/components/QueryControls.js +11 -4
  44. package/dist/components/QueryControls.js.map +1 -1
  45. package/dist/components/ReasoningBox.d.ts +21 -0
  46. package/dist/components/ReasoningBox.d.ts.map +1 -0
  47. package/dist/components/ReasoningBox.js +29 -0
  48. package/dist/components/ReasoningBox.js.map +1 -0
  49. package/dist/components/ToolCallInfo.d.ts.map +1 -1
  50. package/dist/components/ToolCallInfo.js +1 -11
  51. package/dist/components/ToolCallInfo.js.map +1 -1
  52. package/dist/components/ToolPartRenderer.d.ts +20 -0
  53. package/dist/components/ToolPartRenderer.d.ts.map +1 -0
  54. package/dist/components/ToolPartRenderer.js +85 -0
  55. package/dist/components/ToolPartRenderer.js.map +1 -0
  56. package/dist/components/tools/ToolErrorMessage.d.ts.map +1 -1
  57. package/dist/components/tools/ToolErrorMessage.js +1 -2
  58. package/dist/components/tools/ToolErrorMessage.js.map +1 -1
  59. package/dist/components/tools/ToolResult.d.ts.map +1 -1
  60. package/dist/components/tools/ToolResult.js +1 -1
  61. package/dist/components/tools/ToolResult.js.map +1 -1
  62. package/dist/hooks/useAiChat.d.ts +2 -0
  63. package/dist/hooks/useAiChat.d.ts.map +1 -1
  64. package/dist/hooks/useAiChat.js +56 -10
  65. package/dist/hooks/useAiChat.js.map +1 -1
  66. package/dist/hooks/useAssistantMessageParts.d.ts +14 -0
  67. package/dist/hooks/useAssistantMessageParts.d.ts.map +1 -0
  68. package/dist/hooks/useAssistantMessageParts.js +44 -0
  69. package/dist/hooks/useAssistantMessageParts.js.map +1 -0
  70. package/dist/hooks/useScrollToBottom.d.ts.map +1 -1
  71. package/dist/hooks/useScrollToBottom.js +4 -3
  72. package/dist/hooks/useScrollToBottom.js.map +1 -1
  73. package/dist/hooks/useToolGrouping.d.ts +23 -0
  74. package/dist/hooks/useToolGrouping.d.ts.map +1 -0
  75. package/dist/hooks/useToolGrouping.js +290 -0
  76. package/dist/hooks/useToolGrouping.js.map +1 -0
  77. package/dist/index.d.ts +5 -0
  78. package/dist/index.d.ts.map +1 -1
  79. package/dist/index.js +4 -0
  80. package/dist/index.js.map +1 -1
  81. package/dist/utils.d.ts +41 -1
  82. package/dist/utils.d.ts.map +1 -1
  83. package/dist/utils.js +91 -0
  84. package/dist/utils.js.map +1 -1
  85. package/package.json +8 -8
package/dist/utils.d.ts CHANGED
@@ -1,8 +1,37 @@
1
1
  /**
2
2
  * Utility functions for AI Chat UI configuration
3
3
  */
4
- import { AiSettingsSliceConfig, UIMessagePart } from '@sqlrooms/ai-config';
4
+ import { AiSettingsSliceConfig, AnalysisSessionSchema, UIMessagePart } from '@sqlrooms/ai-config';
5
5
  import { TextUIPart, ToolUIPart } from 'ai';
6
+ /**
7
+ * Custom error class for operation abort errors.
8
+ * This allows for type-safe error handling when operations are cancelled by the user.
9
+ *
10
+ * Tools should throw this error when they detect an abort signal,
11
+ * and error handlers can check for this specific error type to provide
12
+ * appropriate user feedback.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * if (abortSignal?.aborted) {
17
+ * throw new ToolAbortError('Operation was aborted');
18
+ * }
19
+ * ```
20
+ *
21
+ * @example
22
+ * ```ts
23
+ * try {
24
+ * await someTool.execute(params, { abortSignal });
25
+ * } catch (error) {
26
+ * if (error instanceof ToolAbortError) {
27
+ * console.log('User cancelled the operation');
28
+ * }
29
+ * }
30
+ * ```
31
+ */
32
+ export declare class ToolAbortError extends Error {
33
+ constructor(message?: string);
34
+ }
6
35
  /**
7
36
  * Extract models from aiSettings in the format expected by ModelSelector
8
37
  * @param config - The AI model configuration
@@ -34,4 +63,15 @@ export declare function isReasoningPart(part: UIMessagePart): part is Extract<UI
34
63
  * @returns True if the part is a tool part
35
64
  */
36
65
  export declare function isToolPart(part: UIMessagePart): part is ToolUIPart;
66
+ /**
67
+ * Cleans up pending analysis results from interrupted conversations and restores them
68
+ * with proper IDs from actual user messages. This handles the case where a page refresh
69
+ * occurred during an active analysis, leaving orphaned "__pending__" results.
70
+ *
71
+ * Should be called once when loading persisted session data, not in migrations.
72
+ *
73
+ * @param session - The session to clean up
74
+ * @returns The cleaned session with restored analysis results
75
+ */
76
+ export declare function cleanupPendingAnalysisResults(session: AnalysisSessionSchema): AnalysisSessionSchema;
37
77
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,qBAAqB,EAErB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAY,UAAU,EAAE,UAAU,EAAC,MAAM,IAAI,CAAC;AAErD;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,KAAK,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CA4BD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,GAClB,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,qBAAqB,EAErB,qBAAqB,EACrB,aAAa,EACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAC,UAAU,EAAE,UAAU,EAAC,MAAM,IAAI,CAAC;AAE1C;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,GAAE,MAAgC;CAQtD;AAED;;;;GAIG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,qBAAqB,GAC5B,KAAK,CAAC;IACP,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf,CAAC,CA4BD;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,aAAa,GAClB,IAAI,IAAI,OAAO,CAAC,aAAa,EAAE;IAAC,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAC,CAAC,CAEnE;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,aAAa,GAAG,IAAI,IAAI,UAAU,CAElE;AAED;;;;;;;;;GASG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,qBAAqB,GAC7B,qBAAqB,CAuDvB"}
package/dist/utils.js CHANGED
@@ -1,6 +1,42 @@
1
1
  /**
2
2
  * Utility functions for AI Chat UI configuration
3
3
  */
4
+ /**
5
+ * Custom error class for operation abort errors.
6
+ * This allows for type-safe error handling when operations are cancelled by the user.
7
+ *
8
+ * Tools should throw this error when they detect an abort signal,
9
+ * and error handlers can check for this specific error type to provide
10
+ * appropriate user feedback.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * if (abortSignal?.aborted) {
15
+ * throw new ToolAbortError('Operation was aborted');
16
+ * }
17
+ * ```
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * try {
22
+ * await someTool.execute(params, { abortSignal });
23
+ * } catch (error) {
24
+ * if (error instanceof ToolAbortError) {
25
+ * console.log('User cancelled the operation');
26
+ * }
27
+ * }
28
+ * ```
29
+ */
30
+ export class ToolAbortError extends Error {
31
+ constructor(message = 'Operation was aborted') {
32
+ super(message);
33
+ this.name = 'ToolAbortError';
34
+ // Maintains proper stack trace for where our error was thrown (only available on V8)
35
+ if (Error.captureStackTrace) {
36
+ Error.captureStackTrace(this, ToolAbortError);
37
+ }
38
+ }
39
+ }
4
40
  /**
5
41
  * Extract models from aiSettings in the format expected by ModelSelector
6
42
  * @param config - The AI model configuration
@@ -52,4 +88,59 @@ export function isReasoningPart(part) {
52
88
  export function isToolPart(part) {
53
89
  return typeof part.type === 'string' && part.type.startsWith('tool-');
54
90
  }
91
+ /**
92
+ * Cleans up pending analysis results from interrupted conversations and restores them
93
+ * with proper IDs from actual user messages. This handles the case where a page refresh
94
+ * occurred during an active analysis, leaving orphaned "__pending__" results.
95
+ *
96
+ * Should be called once when loading persisted session data, not in migrations.
97
+ *
98
+ * @param session - The session to clean up
99
+ * @returns The cleaned session with restored analysis results
100
+ */
101
+ export function cleanupPendingAnalysisResults(session) {
102
+ const { analysisResults, uiMessages } = session;
103
+ if (!Array.isArray(analysisResults) || !Array.isArray(uiMessages)) {
104
+ return session;
105
+ }
106
+ // Remove all pending results
107
+ const nonPendingResults = analysisResults.filter((result) => result.id !== '__pending__');
108
+ // Find all user messages that don't have a corresponding assistant response
109
+ const orphanedUserMessages = [];
110
+ for (let i = 0; i < uiMessages.length; i++) {
111
+ const message = uiMessages[i];
112
+ if (!message || message.role !== 'user') {
113
+ continue;
114
+ }
115
+ // Check if there's an assistant message after this user message
116
+ const hasAssistantResponse = uiMessages
117
+ .slice(i + 1)
118
+ .some((m) => m && m.role === 'assistant');
119
+ if (!hasAssistantResponse) {
120
+ // Extract text from message parts
121
+ const prompt = message.parts
122
+ .filter((part) => part.type === 'text')
123
+ .map((part) => part.text)
124
+ .join('');
125
+ orphanedUserMessages.push({
126
+ id: message.id,
127
+ prompt,
128
+ });
129
+ }
130
+ }
131
+ // For each orphaned user message, check if it already has an analysis result
132
+ // If not, create one
133
+ const existingResultIds = new Set(nonPendingResults.map((r) => r.id));
134
+ const restoredResults = orphanedUserMessages
135
+ .filter(({ id }) => !existingResultIds.has(id))
136
+ .map(({ id, prompt }) => ({
137
+ id,
138
+ prompt,
139
+ isCompleted: true, // Mark as completed since the user did submit it
140
+ }));
141
+ return {
142
+ ...session,
143
+ analysisResults: [...nonPendingResults, ...restoredResults],
144
+ };
145
+ }
55
146
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAA6B;IAM7B,MAAM,MAAM,GAIP,EAAE,CAAC;IAER,gCAAgC;IAChC,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE,EAAE;QACnE,QAAQ,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YAChC,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,WAAW;gBACrB,KAAK,EAAE,KAAK,CAAC,SAAS;gBACtB,KAAK,EAAE,KAAK,CAAC,SAAS;aACvB,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,oBAAoB;IACpB,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,CAAC,WAAW,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC;YACV,QAAQ,EAAE,QAAQ;YAClB,KAAK,EAAE,WAAW,CAAC,SAAS;YAC5B,KAAK,EAAE,WAAW,CAAC,SAAS;SAC7B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAmB;IAC5C,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAmB;IAEnB,OAAO,IAAI,CAAC,IAAI,KAAK,WAAW,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CAAC,IAAmB;IAC5C,OAAO,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AACxE,CAAC","sourcesContent":["/**\n * Utility functions for AI Chat UI configuration\n */\n\nimport {\n AiSettingsSliceConfig,\n AnalysisResultSchema,\n UIMessagePart,\n} from '@sqlrooms/ai-config';\nimport {UIMessage, TextUIPart, ToolUIPart} from 'ai';\n\n/**\n * Extract models from aiSettings in the format expected by ModelSelector\n * @param config - The AI model configuration\n * @returns Array of models with provider, label, and value properties\n */\nexport function extractModelsFromSettings(\n config: AiSettingsSliceConfig,\n): Array<{\n provider: string;\n label: string;\n value: string;\n}> {\n const models: Array<{\n provider: string;\n label: string;\n value: string;\n }> = [];\n\n // Extract models from providers\n Object.entries(config.providers).forEach(([providerKey, provider]) => {\n provider.models.forEach((model) => {\n models.push({\n provider: providerKey,\n label: model.modelName,\n value: model.modelName,\n });\n });\n });\n\n // Add custom models\n config.customModels.forEach((customModel) => {\n models.push({\n provider: 'custom',\n label: customModel.modelName,\n value: customModel.modelName,\n });\n });\n\n return models;\n}\n\n/**\n * Type guard to check if a UIMessagePart is a text part\n * @param part - The message part to check\n * @returns True if the part is a text part\n */\nexport function isTextPart(part: UIMessagePart): part is TextUIPart {\n return part.type === 'text';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a reasoning part\n * @param part - The message part to check\n * @returns True if the part is a reasoning part\n */\nexport function isReasoningPart(\n part: UIMessagePart,\n): part is Extract<UIMessagePart, {type: 'reasoning'; text: string}> {\n return part.type === 'reasoning';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a tool part (type starts with 'tool-')\n * @param part - The message part to check\n * @returns True if the part is a tool part\n */\nexport function isToolPart(part: UIMessagePart): part is ToolUIPart {\n return typeof part.type === 'string' && part.type.startsWith('tool-');\n}\n"]}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Utility functions for AI Chat UI configuration\n */\n\nimport {\n AiSettingsSliceConfig,\n AnalysisResultSchema,\n AnalysisSessionSchema,\n UIMessagePart,\n} from '@sqlrooms/ai-config';\nimport {TextUIPart, ToolUIPart} from 'ai';\n\n/**\n * Custom error class for operation abort errors.\n * This allows for type-safe error handling when operations are cancelled by the user.\n *\n * Tools should throw this error when they detect an abort signal,\n * and error handlers can check for this specific error type to provide\n * appropriate user feedback.\n *\n * @example\n * ```ts\n * if (abortSignal?.aborted) {\n * throw new ToolAbortError('Operation was aborted');\n * }\n * ```\n *\n * @example\n * ```ts\n * try {\n * await someTool.execute(params, { abortSignal });\n * } catch (error) {\n * if (error instanceof ToolAbortError) {\n * console.log('User cancelled the operation');\n * }\n * }\n * ```\n */\nexport class ToolAbortError extends Error {\n constructor(message: string = 'Operation was aborted') {\n super(message);\n this.name = 'ToolAbortError';\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, ToolAbortError);\n }\n }\n}\n\n/**\n * Extract models from aiSettings in the format expected by ModelSelector\n * @param config - The AI model configuration\n * @returns Array of models with provider, label, and value properties\n */\nexport function extractModelsFromSettings(\n config: AiSettingsSliceConfig,\n): Array<{\n provider: string;\n label: string;\n value: string;\n}> {\n const models: Array<{\n provider: string;\n label: string;\n value: string;\n }> = [];\n\n // Extract models from providers\n Object.entries(config.providers).forEach(([providerKey, provider]) => {\n provider.models.forEach((model) => {\n models.push({\n provider: providerKey,\n label: model.modelName,\n value: model.modelName,\n });\n });\n });\n\n // Add custom models\n config.customModels.forEach((customModel) => {\n models.push({\n provider: 'custom',\n label: customModel.modelName,\n value: customModel.modelName,\n });\n });\n\n return models;\n}\n\n/**\n * Type guard to check if a UIMessagePart is a text part\n * @param part - The message part to check\n * @returns True if the part is a text part\n */\nexport function isTextPart(part: UIMessagePart): part is TextUIPart {\n return part.type === 'text';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a reasoning part\n * @param part - The message part to check\n * @returns True if the part is a reasoning part\n */\nexport function isReasoningPart(\n part: UIMessagePart,\n): part is Extract<UIMessagePart, {type: 'reasoning'; text: string}> {\n return part.type === 'reasoning';\n}\n\n/**\n * Type guard to check if a UIMessagePart is a tool part (type starts with 'tool-')\n * @param part - The message part to check\n * @returns True if the part is a tool part\n */\nexport function isToolPart(part: UIMessagePart): part is ToolUIPart {\n return typeof part.type === 'string' && part.type.startsWith('tool-');\n}\n\n/**\n * Cleans up pending analysis results from interrupted conversations and restores them\n * with proper IDs from actual user messages. This handles the case where a page refresh\n * occurred during an active analysis, leaving orphaned \"__pending__\" results.\n *\n * Should be called once when loading persisted session data, not in migrations.\n *\n * @param session - The session to clean up\n * @returns The cleaned session with restored analysis results\n */\nexport function cleanupPendingAnalysisResults(\n session: AnalysisSessionSchema,\n): AnalysisSessionSchema {\n const {analysisResults, uiMessages} = session;\n\n if (!Array.isArray(analysisResults) || !Array.isArray(uiMessages)) {\n return session;\n }\n\n // Remove all pending results\n const nonPendingResults = analysisResults.filter(\n (result) => result.id !== '__pending__',\n );\n\n // Find all user messages that don't have a corresponding assistant response\n const orphanedUserMessages: Array<{id: string; prompt: string}> = [];\n\n for (let i = 0; i < uiMessages.length; i++) {\n const message = uiMessages[i];\n if (!message || message.role !== 'user') {\n continue;\n }\n\n // Check if there's an assistant message after this user message\n const hasAssistantResponse = uiMessages\n .slice(i + 1)\n .some((m) => m && m.role === 'assistant');\n\n if (!hasAssistantResponse) {\n // Extract text from message parts\n const prompt = message.parts\n .filter((part) => part.type === 'text')\n .map((part) => (part as {text: string}).text)\n .join('');\n\n orphanedUserMessages.push({\n id: message.id,\n prompt,\n });\n }\n }\n\n // For each orphaned user message, check if it already has an analysis result\n // If not, create one\n const existingResultIds = new Set(nonPendingResults.map((r) => r.id));\n const restoredResults: AnalysisResultSchema[] = orphanedUserMessages\n .filter(({id}) => !existingResultIds.has(id))\n .map(({id, prompt}) => ({\n id,\n prompt,\n isCompleted: true, // Mark as completed since the user did submit it\n }));\n\n return {\n ...session,\n analysisResults: [...nonPendingResults, ...restoredResults],\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sqlrooms/ai-core",
3
- "version": "0.26.0-rc.6",
3
+ "version": "0.26.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "module": "dist/index.js",
@@ -23,12 +23,12 @@
23
23
  "@ai-sdk/react": "^2.0.44",
24
24
  "@openassistant/utils": "1.0.0-alpha.0",
25
25
  "@paralleldrive/cuid2": "^2.2.2",
26
- "@sqlrooms/ai-config": "0.26.0-rc.6",
27
- "@sqlrooms/monaco-editor": "0.26.0-rc.6",
28
- "@sqlrooms/room-config": "0.26.0-rc.6",
29
- "@sqlrooms/room-store": "0.26.0-rc.6",
30
- "@sqlrooms/ui": "0.26.0-rc.6",
31
- "@sqlrooms/utils": "0.26.0-rc.6",
26
+ "@sqlrooms/ai-config": "0.26.0",
27
+ "@sqlrooms/monaco-editor": "0.26.0",
28
+ "@sqlrooms/room-config": "0.26.0",
29
+ "@sqlrooms/room-store": "0.26.0",
30
+ "@sqlrooms/ui": "0.26.0",
31
+ "@sqlrooms/utils": "0.26.0",
32
32
  "ai": "^5.0.44",
33
33
  "immer": "^10.1.1",
34
34
  "lucide-react": "^0.475.0",
@@ -48,5 +48,5 @@
48
48
  "typecheck": "tsc --noEmit",
49
49
  "typedoc": "typedoc"
50
50
  },
51
- "gitHead": "f7b18280e7d81f653bb437cf81b1e23243809053"
51
+ "gitHead": "3376e76ddfa3c54097b79a20b88a1c37814dca61"
52
52
  }