@rjsebening/n8n-nodes-learningsuite 1.3.2 → 1.3.4

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.
@@ -10,6 +10,12 @@ exports.aiProperties = [
10
10
  default: 'ragChat',
11
11
  displayOptions: { show: { resource: ['ai'] } },
12
12
  options: [
13
+ {
14
+ name: 'Agent Chat',
15
+ value: 'agentChat',
16
+ description: 'Send a message to an AI agent and get the response',
17
+ action: 'Send message to AI agent',
18
+ },
13
19
  {
14
20
  name: 'Get Agent Actions',
15
21
  value: 'getAgentActions',
@@ -30,6 +36,74 @@ exports.aiProperties = [
30
36
  },
31
37
  ],
32
38
  },
39
+ {
40
+ displayName: 'AI Agent Name or ID',
41
+ name: 'agentId',
42
+ type: 'options',
43
+ typeOptions: { loadOptionsMethod: 'ai_getAiAgents' },
44
+ required: true,
45
+ default: '',
46
+ description: 'The AI agent to chat with. For the global AI Concierge agent, you may also use the shortcut "concierge". Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
47
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
48
+ },
49
+ {
50
+ displayName: 'User Name or ID',
51
+ name: 'userId',
52
+ type: 'options',
53
+ typeOptions: { loadOptionsMethod: 'member_getMembers' },
54
+ required: true,
55
+ default: '',
56
+ description: 'The user ID of the member sending the message. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
57
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
58
+ },
59
+ {
60
+ displayName: 'Message',
61
+ name: 'message',
62
+ type: 'string',
63
+ default: '',
64
+ description: 'The message you want to send to the AI agent',
65
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
66
+ },
67
+ {
68
+ displayName: 'Chat ID',
69
+ name: 'chatId',
70
+ type: 'string',
71
+ default: '',
72
+ description: 'The chat/conversation you want to send the message to. Leave empty to start a new chat.',
73
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
74
+ },
75
+ {
76
+ displayName: 'Include Chat History',
77
+ name: 'includeChatHistory',
78
+ type: 'boolean',
79
+ default: false,
80
+ description: 'Whether to return the full chat history in the response. Otherwise, only the latest agent response is returned.',
81
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
82
+ },
83
+ {
84
+ displayName: 'End Chat',
85
+ name: 'endChat',
86
+ type: 'boolean',
87
+ default: false,
88
+ description: 'Whether to end the chat after this message. The agent will not generate a response. Useful when filling out a form is complete.',
89
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
90
+ },
91
+ {
92
+ displayName: 'Metadata',
93
+ name: 'metadata',
94
+ type: 'json',
95
+ default: '{}',
96
+ description: 'If a previous agent response included metadata, it should be included in the next request. Provide as JSON object.',
97
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
98
+ },
99
+ {
100
+ displayName: 'Profile Context',
101
+ name: 'profileContext',
102
+ type: 'json',
103
+ default: '{}',
104
+ description: 'Optional profile context to use when interacting with custom field (forms). Only used if the agent config supports it. Provide as JSON object with a "selectedProfileIdByCard" property.',
105
+ displayOptions: { show: { resource: ['ai'], operation: ['agentChat'] } },
106
+ },
33
107
  {
34
108
  displayName: 'Question',
35
109
  name: 'question',
@@ -16,6 +16,12 @@ exports.communityProperties = [
16
16
  description: 'Assign one or more badges to a member',
17
17
  action: 'Assign badges to member',
18
18
  },
19
+ {
20
+ name: 'Create Community Post',
21
+ value: 'createCommunityPost',
22
+ description: 'Create a community post or answer in a discussion',
23
+ action: 'Create community post',
24
+ },
19
25
  {
20
26
  name: 'Create Community Post Comment',
21
27
  value: 'commentOnPost',
@@ -132,9 +138,10 @@ exports.communityProperties = [
132
138
  name: 'authorUserId',
133
139
  type: 'options',
134
140
  typeOptions: { loadOptionsMethod: 'teamMember_getTeamMembersById' },
135
- displayOptions: { show: { resource: ['community'], operation: ['commentOnPost'] } },
141
+ displayOptions: { show: { resource: ['community'], operation: ['commentOnPost', 'createCommunityPost'] } },
136
142
  default: '',
137
- description: 'Select a team member as author who writes the comment. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
143
+ required: true,
144
+ description: 'Select a team member as author. The author must have access to the target forum. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
138
145
  },
139
146
  {
140
147
  displayName: 'Comment Text',
@@ -191,23 +198,78 @@ exports.communityProperties = [
191
198
  type: 'options',
192
199
  typeOptions: { loadOptionsMethod: 'community_getAreas' },
193
200
  displayOptions: {
194
- show: { resource: ['community'], operation: ['getCommunityPosts'] },
201
+ show: { resource: ['community'], operation: ['getCommunityPosts', 'createCommunityPost'] },
195
202
  },
196
203
  default: '',
197
204
  placeholder: 'Select Area (optional)',
198
- description: 'Filter posts by community area. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
205
+ description: 'Filter forums by community area. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
199
206
  },
200
207
  {
201
208
  displayName: 'Forum Name or ID',
202
209
  name: 'forumId',
203
210
  type: 'options',
204
- typeOptions: { loadOptionsMethod: 'community_getForums' },
211
+ typeOptions: {
212
+ loadOptionsMethod: 'community_getForums',
213
+ loadOptionsDependsOn: ['areaId'],
214
+ },
205
215
  displayOptions: {
206
- show: { resource: ['community'], operation: ['getCommunityPosts'] },
216
+ show: { resource: ['community'], operation: ['getCommunityPosts', 'createCommunityPost'] },
207
217
  },
208
218
  default: '',
209
- placeholder: 'Select Forum (optional)',
210
- description: 'Filter posts by community forum. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
219
+ placeholder: 'Select Forum',
220
+ description: 'The forum in which the post should be published. Choose from the list, or specify an ID using an <a href="https://docs.n8n.io/code/expressions/">expression</a>.',
221
+ },
222
+ {
223
+ displayName: 'Post Title',
224
+ name: 'postTitle',
225
+ type: 'string',
226
+ displayOptions: { show: { resource: ['community'], operation: ['createCommunityPost'] } },
227
+ default: '',
228
+ description: 'Title of the post. Only applicable to discussions.',
229
+ },
230
+ {
231
+ displayName: 'Answer to Post ID',
232
+ name: 'answerToPostId',
233
+ type: 'string',
234
+ displayOptions: { show: { resource: ['community'], operation: ['createCommunityPost'] } },
235
+ default: '',
236
+ description: 'If set, this post is created as an answer to another post. Only applicable to discussions.',
237
+ },
238
+ {
239
+ displayName: 'Content Format',
240
+ name: 'contentFormat',
241
+ type: 'options',
242
+ displayOptions: { show: { resource: ['community'], operation: ['createCommunityPost'] } },
243
+ options: [
244
+ { name: 'Text or HTML', value: 'string' },
245
+ { name: 'JSON Array', value: 'json' },
246
+ ],
247
+ default: 'string',
248
+ description: 'Format to send for the post content',
249
+ },
250
+ {
251
+ displayName: 'Content',
252
+ name: 'content',
253
+ type: 'string',
254
+ typeOptions: { rows: 6 },
255
+ displayOptions: {
256
+ show: { resource: ['community'], operation: ['createCommunityPost'], contentFormat: ['string'] },
257
+ },
258
+ default: '',
259
+ required: true,
260
+ description: 'Content of the post. May be plain text or HTML.',
261
+ },
262
+ {
263
+ displayName: 'Content JSON',
264
+ name: 'contentJson',
265
+ type: 'json',
266
+ typeOptions: { rows: 6 },
267
+ displayOptions: {
268
+ show: { resource: ['community'], operation: ['createCommunityPost'], contentFormat: ['json'] },
269
+ },
270
+ default: '[]',
271
+ required: true,
272
+ description: 'Content of the post as a JSON array of objects, for example Slate content',
211
273
  },
212
274
  {
213
275
  displayName: 'Order',
@@ -1,5 +1,6 @@
1
1
  import type { ExecuteHandler } from '../exec.types';
2
2
  export declare const aiHandlers: {
3
+ agentChat: ExecuteHandler;
3
4
  getAgentActions: ExecuteHandler;
4
5
  getAiAgents: ExecuteHandler;
5
6
  ragChat: ExecuteHandler;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.aiHandlers = void 0;
4
+ const n8n_workflow_1 = require("n8n-workflow");
4
5
  const shared_1 = require("../shared");
5
6
  const getAgentActions = async (ctx) => {
6
7
  return await shared_1.lsRequest.call(ctx, 'GET', '/agent-actions');
@@ -8,6 +9,40 @@ const getAgentActions = async (ctx) => {
8
9
  const getAiAgents = async (ctx) => {
9
10
  return await shared_1.lsRequest.call(ctx, 'GET', '/ai-agents');
10
11
  };
12
+ function parseJsonObjectParam(ctx, i, name) {
13
+ const raw = ctx.getNodeParameter(name, i, '');
14
+ if (raw === undefined || raw === null || raw === '')
15
+ return undefined;
16
+ if (typeof raw === 'object')
17
+ return raw;
18
+ let parsed;
19
+ try {
20
+ parsed = JSON.parse(raw);
21
+ }
22
+ catch (err) {
23
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Invalid JSON in "${name}": ${String(err)}`);
24
+ }
25
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
26
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `"${name}" must be a JSON object`);
27
+ }
28
+ return parsed;
29
+ }
30
+ const agentChat = async (ctx, i) => {
31
+ const agentId = ctx.getNodeParameter('agentId', i);
32
+ if (!agentId)
33
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'AI Agent is required');
34
+ const body = {
35
+ userId: ctx.getNodeParameter('userId', i),
36
+ chatId: ctx.getNodeParameter('chatId', i, undefined),
37
+ message: ctx.getNodeParameter('message', i, undefined),
38
+ includeChatHistory: ctx.getNodeParameter('includeChatHistory', i, false),
39
+ endChat: ctx.getNodeParameter('endChat', i, false),
40
+ metadata: parseJsonObjectParam(ctx, i, 'metadata'),
41
+ profileContext: parseJsonObjectParam(ctx, i, 'profileContext'),
42
+ };
43
+ const cleanBody = Object.fromEntries(Object.entries(body).filter(([, v]) => v !== undefined && v !== ''));
44
+ return await shared_1.lsRequest.call(ctx, 'POST', `/ai-agents/${encodeURIComponent(agentId)}/chat`, { body: cleanBody });
45
+ };
11
46
  const ragChat = async (ctx, i) => {
12
47
  const body = {
13
48
  question: ctx.getNodeParameter('question', i),
@@ -25,6 +60,7 @@ const ragChat = async (ctx, i) => {
25
60
  return await shared_1.lsRequest.call(ctx, 'POST', '/ai/rag-chat', { body: cleanBody });
26
61
  };
27
62
  exports.aiHandlers = {
63
+ agentChat,
28
64
  getAgentActions,
29
65
  getAiAgents,
30
66
  ragChat,
@@ -6,6 +6,7 @@ export declare const communityHandlers: {
6
6
  getBadges: ExecuteHandler;
7
7
  assignBadgesToUser: ExecuteHandler;
8
8
  removeBadgesFromUser: ExecuteHandler;
9
+ createCommunityPost: ExecuteHandler;
9
10
  commentOnPost: ExecuteHandler;
10
11
  getCommunityPosts: ExecuteHandler;
11
12
  };
@@ -57,6 +57,50 @@ const removeBadgesFromUser = async (ctx, i) => {
57
57
  const body = { userId: memberId, badgeIds };
58
58
  return await shared_1.lsRequest.call(ctx, 'DELETE', '/community/badges/user', { body });
59
59
  };
60
+ const createCommunityPost = async (ctx, i) => {
61
+ const authorUserId = String(ctx.getNodeParameter('authorUserId', i, '') || '').trim();
62
+ const forumId = String(ctx.getNodeParameter('forumId', i, '') || '').trim();
63
+ const postTitle = String(ctx.getNodeParameter('postTitle', i, '') || '').trim();
64
+ const answerToPostId = String(ctx.getNodeParameter('answerToPostId', i, '') || '').trim();
65
+ const contentFormat = ctx.getNodeParameter('contentFormat', i, 'string');
66
+ if (!authorUserId) {
67
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide authorUserId.');
68
+ }
69
+ if (!forumId) {
70
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Please provide a forum ID.');
71
+ }
72
+ let content;
73
+ if (contentFormat === 'json') {
74
+ const contentJson = ctx.getNodeParameter('contentJson', i, '[]');
75
+ try {
76
+ content = JSON.parse(contentJson);
77
+ }
78
+ catch (err) {
79
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), `Invalid JSON in content: ${String(err)}`);
80
+ }
81
+ if (!Array.isArray(content)) {
82
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'Content JSON must be an array of objects.');
83
+ }
84
+ }
85
+ else {
86
+ content = String(ctx.getNodeParameter('content', i, '') || '').trim();
87
+ if (!content) {
88
+ throw new n8n_workflow_1.NodeOperationError(ctx.getNode(), 'The post content cannot be empty.');
89
+ }
90
+ }
91
+ const body = {
92
+ authorUserId,
93
+ forumId,
94
+ content,
95
+ };
96
+ if (postTitle) {
97
+ body.postTitle = postTitle;
98
+ }
99
+ if (answerToPostId) {
100
+ body.answerToPostId = answerToPostId;
101
+ }
102
+ return shared_1.lsRequest.call(ctx, 'POST', '/community/posts', { body });
103
+ };
60
104
  const commentOnPost = async (ctx, i) => {
61
105
  const postId = String(ctx.getNodeParameter('postId', i, '') || '').trim();
62
106
  const authorUserId = String(ctx.getNodeParameter('authorUserId', i, '') || '').trim();
@@ -89,6 +133,7 @@ exports.communityHandlers = {
89
133
  getBadges,
90
134
  assignBadgesToUser,
91
135
  removeBadgesFromUser,
136
+ createCommunityPost,
92
137
  commentOnPost: exports.commentOnPost,
93
138
  getCommunityPosts,
94
139
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rjsebening/n8n-nodes-learningsuite",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "description": "n8n node for LearningSuite API",
5
5
  "keywords": [
6
6
  "n8n-community-node-package",