Skip to content

Commit 7327b44

Browse files
aadamgoughAdam GoughAdam Gough
authored
Improvement(sharepoint): added ability to create list items, different from create list (#1379)
* added add list items (cherry picked from commit df6ea35) * bun run lint * minor changes --------- Co-authored-by: Adam Gough <[email protected]> Co-authored-by: Adam Gough <[email protected]>
1 parent eb1e90b commit 7327b44

File tree

7 files changed

+210
-17
lines changed

7 files changed

+210
-17
lines changed

apps/docs/content/docs/en/tools/meta.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"google_calendar",
1818
"google_docs",
1919
"google_drive",
20+
"google_forms",
2021
"google_search",
2122
"google_sheets",
2223
"huggingface",

apps/docs/content/docs/en/tools/sharepoint.mdx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,25 @@ Update the properties (fields) on a SharePoint list item
183183
| --------- | ---- | ----------- |
184184
| `item` | object | Updated SharePoint list item |
185185

186+
### `sharepoint_add_list_items`
187+
188+
Add a new item to a SharePoint list
189+
190+
#### Input
191+
192+
| Parameter | Type | Required | Description |
193+
| --------- | ---- | -------- | ----------- |
194+
| `siteSelector` | string | No | Select the SharePoint site |
195+
| `siteId` | string | No | The ID of the SharePoint site \(internal use\) |
196+
| `listId` | string | Yes | The ID of the list to add the item to |
197+
| `listItemFields` | object | Yes | Field values for the new list item |
198+
199+
#### Output
200+
201+
| Parameter | Type | Description |
202+
| --------- | ---- | ----------- |
203+
| `item` | object | Created SharePoint list item |
204+
186205

187206

188207
## Notes

apps/sim/blocks/blocks/sharepoint.ts

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
1616
bgColor: '#E0E0E0',
1717
icon: MicrosoftSharepointIcon,
1818
subBlocks: [
19-
// Operation selector
2019
{
2120
id: 'operation',
2221
title: 'Operation',
@@ -29,9 +28,9 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
2928
{ label: 'Create List', id: 'create_list' },
3029
{ label: 'Read List', id: 'read_list' },
3130
{ label: 'Update List', id: 'update_list' },
31+
{ label: 'Add List Items', id: 'add_list_items' },
3232
],
3333
},
34-
// Sharepoint Credentials
3534
{
3635
id: 'credential',
3736
title: 'Microsoft Account',
@@ -81,6 +80,7 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
8180
'create_list',
8281
'read_list',
8382
'update_list',
83+
'add_list_items',
8484
],
8585
},
8686
},
@@ -111,7 +111,7 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
111111
layout: 'full',
112112
placeholder: 'Enter list ID (GUID). Required for Update; optional for Read.',
113113
canonicalParamId: 'listId',
114-
condition: { field: 'operation', value: ['read_list', 'update_list'] },
114+
condition: { field: 'operation', value: ['read_list', 'update_list', 'add_list_items'] },
115115
},
116116

117117
{
@@ -178,7 +178,7 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
178178
layout: 'full',
179179
placeholder: 'Enter list item fields',
180180
canonicalParamId: 'listItemFields',
181-
condition: { field: 'operation', value: 'update_list' },
181+
condition: { field: 'operation', value: ['update_list', 'add_list_items'] },
182182
},
183183
],
184184
tools: {
@@ -189,6 +189,7 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
189189
'sharepoint_create_list',
190190
'sharepoint_get_list',
191191
'sharepoint_update_list',
192+
'sharepoint_add_list_items',
192193
],
193194
config: {
194195
tool: (params) => {
@@ -205,14 +206,15 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
205206
return 'sharepoint_get_list'
206207
case 'update_list':
207208
return 'sharepoint_update_list'
209+
case 'add_list_items':
210+
return 'sharepoint_add_list_items'
208211
default:
209212
throw new Error(`Invalid Sharepoint operation: ${params.operation}`)
210213
}
211214
},
212215
params: (params) => {
213216
const { credential, siteSelector, manualSiteId, mimeType, ...rest } = params
214217

215-
// Use siteSelector if provided, otherwise use manualSiteId
216218
const effectiveSiteId = (siteSelector || manualSiteId || '').trim()
217219

218220
const {
@@ -234,12 +236,10 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
234236
})
235237
}
236238
}
237-
// Ensure listItemFields is an object for the tool schema
238239
if (typeof parsedItemFields !== 'object' || parsedItemFields === null) {
239240
parsedItemFields = undefined
240241
}
241242

242-
// Sanitize item ID (required by tool)
243243
const rawItemId = providedItemId ?? listItemId
244244
const sanitizedItemId =
245245
rawItemId === undefined || rawItemId === null
@@ -252,10 +252,9 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
252252
return undefined
253253
}
254254

255-
// Debug logging for update_list param mapping
256-
if (others.operation === 'update_list') {
255+
if (others.operation === 'update_list' || others.operation === 'add_list_items') {
257256
try {
258-
logger.info('SharepointBlock update_list param check', {
257+
logger.info('SharepointBlock list item param check', {
259258
siteId: effectiveSiteId || undefined,
260259
listId: (others as any)?.listId,
261260
listTitle: (others as any)?.listTitle,
@@ -275,7 +274,6 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
275274
pageSize: others.pageSize ? Number.parseInt(others.pageSize as string, 10) : undefined,
276275
mimeType: mimeType,
277276
...others,
278-
// Map to tool param names
279277
itemId: sanitizedItemId,
280278
listItemFields: parsedItemFields,
281279
includeColumns: coerceBoolean(includeColumns),
@@ -287,26 +285,20 @@ export const SharepointBlock: BlockConfig<SharepointResponse> = {
287285
inputs: {
288286
operation: { type: 'string', description: 'Operation to perform' },
289287
credential: { type: 'string', description: 'Microsoft account credential' },
290-
// Create Page operation inputs
291288
pageName: { type: 'string', description: 'Page name' },
292289
pageContent: { type: 'string', description: 'Page content' },
293290
pageTitle: { type: 'string', description: 'Page title' },
294-
// Read Page operation inputs
295291
pageId: { type: 'string', description: 'Page ID' },
296-
// List operation inputs
297292
siteSelector: { type: 'string', description: 'Site selector' },
298293
manualSiteId: { type: 'string', description: 'Manual site ID' },
299294
pageSize: { type: 'number', description: 'Results per page' },
300-
// Create List operation inputs
301295
listDisplayName: { type: 'string', description: 'List display name' },
302296
listDescription: { type: 'string', description: 'List description' },
303297
listTemplate: { type: 'string', description: 'List template' },
304-
// Read List operation inputs
305298
listId: { type: 'string', description: 'List ID' },
306299
listTitle: { type: 'string', description: 'List title' },
307300
includeColumns: { type: 'boolean', description: 'Include columns in response' },
308301
includeItems: { type: 'boolean', description: 'Include items in response' },
309-
// Update List Item operation inputs
310302
listItemId: { type: 'string', description: 'List item ID' },
311303
listItemFields: { type: 'string', description: 'List item fields' },
312304
},

apps/sim/tools/registry.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ import { redditGetCommentsTool, redditGetPostsTool, redditHotPostsTool } from '@
145145
import { s3GetObjectTool } from '@/tools/s3'
146146
import { searchTool as serperSearch } from '@/tools/serper'
147147
import {
148+
sharepointAddListItemTool,
148149
sharepointCreateListTool,
149150
sharepointCreatePageTool,
150151
sharepointGetListTool,
@@ -370,6 +371,7 @@ export const tools: Record<string, ToolConfig> = {
370371
sharepoint_get_list: sharepointGetListTool,
371372
sharepoint_create_list: sharepointCreateListTool,
372373
sharepoint_update_list: sharepointUpdateListItemTool,
374+
sharepoint_add_list_items: sharepointAddListItemTool,
373375
// Provider chat tools
374376
// Provider chat tools - handled separately in agent blocks
375377
}
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
import { createLogger } from '@/lib/logs/console/logger'
2+
import type { SharepointAddListItemResponse, SharepointToolParams } from '@/tools/sharepoint/types'
3+
import type { ToolConfig } from '@/tools/types'
4+
5+
const logger = createLogger('SharePointAddListItem')
6+
7+
export const addListItemTool: ToolConfig<SharepointToolParams, SharepointAddListItemResponse> = {
8+
id: 'sharepoint_add_list_items',
9+
name: 'Add SharePoint List Item',
10+
description: 'Add a new item to a SharePoint list',
11+
version: '1.0',
12+
13+
oauth: {
14+
required: true,
15+
provider: 'sharepoint',
16+
additionalScopes: ['openid', 'profile', 'email', 'Sites.ReadWrite.All', 'offline_access'],
17+
},
18+
19+
params: {
20+
accessToken: {
21+
type: 'string',
22+
required: true,
23+
visibility: 'hidden',
24+
description: 'The access token for the SharePoint API',
25+
},
26+
siteSelector: {
27+
type: 'string',
28+
required: false,
29+
visibility: 'user-only',
30+
description: 'Select the SharePoint site',
31+
},
32+
siteId: {
33+
type: 'string',
34+
required: false,
35+
visibility: 'hidden',
36+
description: 'The ID of the SharePoint site (internal use)',
37+
},
38+
listId: {
39+
type: 'string',
40+
required: true,
41+
visibility: 'user-only',
42+
description: 'The ID of the list to add the item to',
43+
},
44+
listItemFields: {
45+
type: 'object',
46+
required: true,
47+
visibility: 'user-only',
48+
description: 'Field values for the new list item',
49+
},
50+
},
51+
52+
request: {
53+
url: (params) => {
54+
const siteId = params.siteId || params.siteSelector || 'root'
55+
if (!params.listId) {
56+
throw new Error('listId must be provided')
57+
}
58+
const listSegment = params.listId
59+
return `https://graph.microsoft.com/v1.0/sites/${siteId}/lists/${listSegment}/items`
60+
},
61+
method: 'POST',
62+
headers: (params) => ({
63+
Authorization: `Bearer ${params.accessToken}`,
64+
'Content-Type': 'application/json',
65+
Accept: 'application/json',
66+
}),
67+
body: (params) => {
68+
if (!params.listItemFields || Object.keys(params.listItemFields).length === 0) {
69+
throw new Error('listItemFields must not be empty')
70+
}
71+
72+
const providedFields =
73+
typeof params.listItemFields === 'object' &&
74+
params.listItemFields !== null &&
75+
'fields' in (params.listItemFields as Record<string, unknown>) &&
76+
Object.keys(params.listItemFields as Record<string, unknown>).length === 1
77+
? ((params.listItemFields as any).fields as Record<string, unknown>)
78+
: (params.listItemFields as Record<string, unknown>)
79+
80+
if (!providedFields || Object.keys(providedFields).length === 0) {
81+
throw new Error('No fields provided to create the SharePoint list item')
82+
}
83+
84+
const readOnlyFields = new Set<string>([
85+
'Id',
86+
'id',
87+
'UniqueId',
88+
'GUID',
89+
'ContentTypeId',
90+
'Created',
91+
'Modified',
92+
'Author',
93+
'Editor',
94+
'CreatedBy',
95+
'ModifiedBy',
96+
'AuthorId',
97+
'EditorId',
98+
'_UIVersionString',
99+
'Attachments',
100+
'FileRef',
101+
'FileDirRef',
102+
'FileLeafRef',
103+
])
104+
105+
const entries = Object.entries(providedFields)
106+
const creatableEntries = entries.filter(([key]) => !readOnlyFields.has(key))
107+
108+
if (creatableEntries.length !== entries.length) {
109+
const removed = entries.filter(([key]) => readOnlyFields.has(key)).map(([key]) => key)
110+
logger.warn('Removed read-only SharePoint fields from create', {
111+
removed,
112+
})
113+
}
114+
115+
if (creatableEntries.length === 0) {
116+
const requestedKeys = Object.keys(providedFields)
117+
throw new Error(
118+
`All provided fields are read-only and cannot be set: ${requestedKeys.join(', ')}`
119+
)
120+
}
121+
122+
const sanitizedFields = Object.fromEntries(creatableEntries)
123+
124+
logger.info('Creating SharePoint list item', {
125+
listId: params.listId,
126+
fieldsKeys: Object.keys(sanitizedFields),
127+
})
128+
129+
return {
130+
fields: sanitizedFields,
131+
}
132+
},
133+
},
134+
135+
transformResponse: async (response: Response, params) => {
136+
let data: any
137+
try {
138+
data = await response.json()
139+
} catch {
140+
data = undefined
141+
}
142+
143+
const itemId: string | undefined = data?.id
144+
const fields: Record<string, unknown> | undefined = data?.fields || params?.listItemFields
145+
146+
return {
147+
success: true,
148+
output: {
149+
item: {
150+
id: itemId || 'unknown',
151+
fields,
152+
},
153+
},
154+
}
155+
},
156+
157+
outputs: {
158+
item: {
159+
type: 'object',
160+
description: 'Created SharePoint list item',
161+
properties: {
162+
id: { type: 'string', description: 'Item ID' },
163+
fields: { type: 'object', description: 'Field values for the new item' },
164+
},
165+
},
166+
},
167+
}

apps/sim/tools/sharepoint/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { addListItemTool } from '@/tools/sharepoint/add_list_items'
12
import { createListTool } from '@/tools/sharepoint/create_list'
23
import { createPageTool } from '@/tools/sharepoint/create_page'
34
import { getListTool } from '@/tools/sharepoint/get_list'
@@ -11,3 +12,4 @@ export const sharepointGetListTool = getListTool
1112
export const sharepointListSitesTool = listSitesTool
1213
export const sharepointReadPageTool = readPageTool
1314
export const sharepointUpdateListItemTool = updateListItemTool
15+
export const sharepointAddListItemTool = addListItemTool

apps/sim/tools/sharepoint/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@ export type SharepointResponse =
259259
| SharepointGetListResponse
260260
| SharepointCreateListResponse
261261
| SharepointUpdateListItemResponse
262+
| SharepointAddListItemResponse
262263

263264
export interface SharepointGetListResponse extends ToolResponse {
264265
output: {
@@ -282,3 +283,12 @@ export interface SharepointUpdateListItemResponse extends ToolResponse {
282283
}
283284
}
284285
}
286+
287+
export interface SharepointAddListItemResponse extends ToolResponse {
288+
output: {
289+
item: {
290+
id: string
291+
fields?: Record<string, unknown>
292+
}
293+
}
294+
}

0 commit comments

Comments
 (0)