bitrix24-tasks-mcp-server 1.5.2 → 1.6.2
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/build/bitrix24/client.d.ts +57 -0
- package/build/bitrix24/client.d.ts.map +1 -1
- package/build/bitrix24/client.js +222 -2
- package/build/bitrix24/client.js.map +1 -1
- package/build/bitrix24/compositeLock.d.ts +2 -0
- package/build/bitrix24/compositeLock.d.ts.map +1 -0
- package/build/bitrix24/compositeLock.js +217 -0
- package/build/bitrix24/compositeLock.js.map +1 -0
- package/build/bitrix24/compositePublisher.d.ts +74 -0
- package/build/bitrix24/compositePublisher.d.ts.map +1 -0
- package/build/bitrix24/compositePublisher.js +288 -0
- package/build/bitrix24/compositePublisher.js.map +1 -0
- package/build/index.js +3 -2
- package/build/index.js.map +1 -1
- package/build/tools/index.d.ts +7 -1
- package/build/tools/index.d.ts.map +1 -1
- package/build/tools/index.js +463 -10
- package/build/tools/index.js.map +1 -1
- package/build/tools/validation.d.ts +3 -0
- package/build/tools/validation.d.ts.map +1 -0
- package/build/tools/validation.js +141 -0
- package/build/tools/validation.js.map +1 -0
- package/build/utils/toolLogging.d.ts +2 -0
- package/build/utils/toolLogging.d.ts.map +1 -0
- package/build/utils/toolLogging.js +93 -0
- package/build/utils/toolLogging.js.map +1 -0
- package/package.json +2 -2
package/build/tools/index.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
1
2
|
import { bitrix24Client } from '../bitrix24/client.js';
|
|
3
|
+
import { publishTaskComposite } from '../bitrix24/compositePublisher.js';
|
|
4
|
+
import { validateToolArguments } from './validation.js';
|
|
2
5
|
function stripBase64FromDownloadedFile(file) {
|
|
3
6
|
if (!file.base64) {
|
|
4
7
|
return file;
|
|
@@ -16,6 +19,42 @@ function collectFilesWithContent(...groups) {
|
|
|
16
19
|
function normalizeStageTitle(value) {
|
|
17
20
|
return String(value ?? '').trim().toLocaleLowerCase('ru-RU');
|
|
18
21
|
}
|
|
22
|
+
function compareNumericIds(left, right) {
|
|
23
|
+
if (!/^\d+$/.test(left) || !/^\d+$/.test(right)) {
|
|
24
|
+
return left.localeCompare(right, 'en', { numeric: true });
|
|
25
|
+
}
|
|
26
|
+
const leftValue = BigInt(left);
|
|
27
|
+
const rightValue = BigInt(right);
|
|
28
|
+
return leftValue < rightValue ? -1 : leftValue > rightValue ? 1 : 0;
|
|
29
|
+
}
|
|
30
|
+
function compactText(value, maxChars) {
|
|
31
|
+
if (value === undefined || value.length <= maxChars) {
|
|
32
|
+
return {
|
|
33
|
+
text: value,
|
|
34
|
+
truncated: false,
|
|
35
|
+
originalChars: value?.length ?? 0
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
text: value.slice(0, maxChars),
|
|
40
|
+
truncated: true,
|
|
41
|
+
originalChars: value.length,
|
|
42
|
+
sha256: createHash('sha256').update(value).digest('hex')
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function boundedOptionalString(value, maxChars) {
|
|
46
|
+
if (value === undefined || value === null) {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
return String(value).slice(0, maxChars);
|
|
50
|
+
}
|
|
51
|
+
function boundErrors(errors) {
|
|
52
|
+
return {
|
|
53
|
+
errors: errors.slice(0, 10).map((error) => String(error).slice(0, 512)),
|
|
54
|
+
errorsTruncated: errors.length > 10 || errors.some((error) => String(error).length > 512),
|
|
55
|
+
originalErrorCount: errors.length
|
|
56
|
+
};
|
|
57
|
+
}
|
|
19
58
|
// Task Management Tools
|
|
20
59
|
export const createTaskTool = {
|
|
21
60
|
name: 'bitrix24_create_task',
|
|
@@ -125,6 +164,65 @@ export const getTaskTool = {
|
|
|
125
164
|
required: ['id']
|
|
126
165
|
}
|
|
127
166
|
};
|
|
167
|
+
export const getTaskSummaryTool = {
|
|
168
|
+
name: 'bitrix24_get_task_summary',
|
|
169
|
+
description: 'Read a strict bounded task projection for workflow intake and routing. DESCRIPTION is capped at 12000 characters; TITLE is display metadata and must not be used as a routing signal.',
|
|
170
|
+
inputSchema: {
|
|
171
|
+
type: 'object',
|
|
172
|
+
additionalProperties: false,
|
|
173
|
+
properties: {
|
|
174
|
+
taskId: {
|
|
175
|
+
type: 'string',
|
|
176
|
+
minLength: 1,
|
|
177
|
+
maxLength: 32,
|
|
178
|
+
pattern: '^\\d+$',
|
|
179
|
+
description: 'Task ID'
|
|
180
|
+
},
|
|
181
|
+
select: {
|
|
182
|
+
type: 'array',
|
|
183
|
+
minItems: 1,
|
|
184
|
+
maxItems: 12,
|
|
185
|
+
items: {
|
|
186
|
+
type: 'string',
|
|
187
|
+
enum: [
|
|
188
|
+
'ID',
|
|
189
|
+
'TITLE',
|
|
190
|
+
'DESCRIPTION',
|
|
191
|
+
'GROUP_ID',
|
|
192
|
+
'STAGE_ID',
|
|
193
|
+
'STATUS',
|
|
194
|
+
'CHANGED_DATE',
|
|
195
|
+
'CREATED_DATE',
|
|
196
|
+
'RESPONSIBLE_ID',
|
|
197
|
+
'DEADLINE',
|
|
198
|
+
'PRIORITY',
|
|
199
|
+
'PARENT_ID'
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
description: 'Optional Bitrix task fields. Defaults to ID, TITLE, DESCRIPTION, GROUP_ID, STAGE_ID, STATUS, CHANGED_DATE, RESPONSIBLE_ID.'
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
required: ['taskId']
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
export const getTaskStageTool = {
|
|
209
|
+
name: 'bitrix24_get_task_stage',
|
|
210
|
+
description: 'Read the current task stage and minimal routing metadata without loading comments, description, or files.',
|
|
211
|
+
inputSchema: {
|
|
212
|
+
type: 'object',
|
|
213
|
+
additionalProperties: false,
|
|
214
|
+
properties: {
|
|
215
|
+
taskId: {
|
|
216
|
+
type: 'string',
|
|
217
|
+
minLength: 1,
|
|
218
|
+
maxLength: 32,
|
|
219
|
+
pattern: '^\\d+$',
|
|
220
|
+
description: 'Task ID'
|
|
221
|
+
}
|
|
222
|
+
},
|
|
223
|
+
required: ['taskId']
|
|
224
|
+
}
|
|
225
|
+
};
|
|
128
226
|
export const listTasksTool = {
|
|
129
227
|
name: 'bitrix24_list_tasks',
|
|
130
228
|
description: 'List tasks with optional filtering and ordering',
|
|
@@ -206,7 +304,7 @@ export const getTaskCommentsTool = {
|
|
|
206
304
|
description: 'Legacy comment FILTER (task.commentitem.getlist only)'
|
|
207
305
|
},
|
|
208
306
|
limit: {
|
|
209
|
-
type: '
|
|
307
|
+
type: 'integer',
|
|
210
308
|
description: 'Max messages for chat API (1-50, default 50)',
|
|
211
309
|
default: 50
|
|
212
310
|
},
|
|
@@ -250,17 +348,86 @@ export const getTaskCommentsTool = {
|
|
|
250
348
|
required: ['taskId']
|
|
251
349
|
}
|
|
252
350
|
};
|
|
351
|
+
export const getTaskCommentsAfterTool = {
|
|
352
|
+
name: 'bitrix24_get_comments_after',
|
|
353
|
+
description: 'Read compact comments newer than a known comment/message ID. Returns text and metadata only; never downloads attachments or file bytes.',
|
|
354
|
+
inputSchema: {
|
|
355
|
+
type: 'object',
|
|
356
|
+
additionalProperties: false,
|
|
357
|
+
properties: {
|
|
358
|
+
taskId: {
|
|
359
|
+
type: 'string',
|
|
360
|
+
minLength: 1,
|
|
361
|
+
maxLength: 32,
|
|
362
|
+
pattern: '^\\d+$',
|
|
363
|
+
description: 'Task ID'
|
|
364
|
+
},
|
|
365
|
+
afterCommentId: {
|
|
366
|
+
type: 'string',
|
|
367
|
+
minLength: 1,
|
|
368
|
+
maxLength: 32,
|
|
369
|
+
pattern: '^\\d+$',
|
|
370
|
+
description: 'Return only comments/messages whose numeric ID is greater than this watermark'
|
|
371
|
+
},
|
|
372
|
+
preferApi: {
|
|
373
|
+
type: 'string',
|
|
374
|
+
enum: ['auto', 'chat', 'legacy'],
|
|
375
|
+
description: 'API strategy',
|
|
376
|
+
default: 'auto'
|
|
377
|
+
},
|
|
378
|
+
limit: {
|
|
379
|
+
type: 'integer',
|
|
380
|
+
minimum: 1,
|
|
381
|
+
maximum: 20,
|
|
382
|
+
description: 'Maximum comments to inspect and return',
|
|
383
|
+
default: 20
|
|
384
|
+
},
|
|
385
|
+
includeSystemMessages: {
|
|
386
|
+
type: 'boolean',
|
|
387
|
+
description: 'Include system messages',
|
|
388
|
+
default: false
|
|
389
|
+
},
|
|
390
|
+
maxCommentChars: {
|
|
391
|
+
type: 'integer',
|
|
392
|
+
minimum: 256,
|
|
393
|
+
maximum: 8000,
|
|
394
|
+
description: 'Per-comment text cap. Truncated comments include originalChars and sha256.',
|
|
395
|
+
default: 4000
|
|
396
|
+
},
|
|
397
|
+
maxTotalChars: {
|
|
398
|
+
type: 'integer',
|
|
399
|
+
minimum: 512,
|
|
400
|
+
maximum: 32000,
|
|
401
|
+
description: 'Hard cap for text across the returned page.',
|
|
402
|
+
default: 16000
|
|
403
|
+
}
|
|
404
|
+
},
|
|
405
|
+
required: ['taskId', 'afterCommentId']
|
|
406
|
+
}
|
|
407
|
+
};
|
|
253
408
|
export const addTaskCommentTool = {
|
|
254
409
|
name: 'bitrix24_add_task_comment',
|
|
255
410
|
description: 'Post a comment/message to a task. Modern path: tasks.task.chat.message.send + im.disk.file.commit; legacy fallback: task.commentitem.add.',
|
|
256
411
|
inputSchema: {
|
|
257
412
|
type: 'object',
|
|
413
|
+
additionalProperties: false,
|
|
258
414
|
properties: {
|
|
259
|
-
taskId: {
|
|
260
|
-
|
|
415
|
+
taskId: {
|
|
416
|
+
type: 'string',
|
|
417
|
+
minLength: 1,
|
|
418
|
+
maxLength: 32,
|
|
419
|
+
pattern: '^\\d+$',
|
|
420
|
+
description: 'Task ID'
|
|
421
|
+
},
|
|
422
|
+
text: {
|
|
423
|
+
type: 'string',
|
|
424
|
+
maxLength: 32000,
|
|
425
|
+
description: 'Comment text (required if no filePaths)'
|
|
426
|
+
},
|
|
261
427
|
filePaths: {
|
|
262
428
|
type: 'array',
|
|
263
|
-
|
|
429
|
+
maxItems: 12,
|
|
430
|
+
items: { type: 'string', minLength: 1, maxLength: 4096 },
|
|
264
431
|
description: 'Local files to upload and attach to the comment/message'
|
|
265
432
|
},
|
|
266
433
|
diskFolderId: {
|
|
@@ -311,16 +478,141 @@ export const getTaskFilesTool = {
|
|
|
311
478
|
required: ['taskId']
|
|
312
479
|
}
|
|
313
480
|
};
|
|
481
|
+
export const getTaskFilesMetadataTool = {
|
|
482
|
+
name: 'bitrix24_get_task_files_metadata',
|
|
483
|
+
description: 'Read one bounded page of task attachment metadata without downloading file bytes or emitting base64.',
|
|
484
|
+
inputSchema: {
|
|
485
|
+
type: 'object',
|
|
486
|
+
additionalProperties: false,
|
|
487
|
+
properties: {
|
|
488
|
+
taskId: {
|
|
489
|
+
type: 'string',
|
|
490
|
+
minLength: 1,
|
|
491
|
+
maxLength: 32,
|
|
492
|
+
pattern: '^\\d+$',
|
|
493
|
+
description: 'Task ID'
|
|
494
|
+
},
|
|
495
|
+
diskFileIds: {
|
|
496
|
+
type: 'array',
|
|
497
|
+
maxItems: 50,
|
|
498
|
+
items: { type: 'string', minLength: 1, maxLength: 64 },
|
|
499
|
+
description: 'Optional exact disk file IDs; omitted means all task file references'
|
|
500
|
+
},
|
|
501
|
+
imagesOnly: {
|
|
502
|
+
type: 'boolean',
|
|
503
|
+
description: 'Return image metadata only',
|
|
504
|
+
default: false
|
|
505
|
+
},
|
|
506
|
+
afterFileId: {
|
|
507
|
+
type: 'string',
|
|
508
|
+
minLength: 1,
|
|
509
|
+
maxLength: 64,
|
|
510
|
+
description: 'Pagination watermark from nextAfterFileId'
|
|
511
|
+
},
|
|
512
|
+
limit: {
|
|
513
|
+
type: 'integer',
|
|
514
|
+
minimum: 1,
|
|
515
|
+
maximum: 25,
|
|
516
|
+
default: 25,
|
|
517
|
+
description: 'Maximum metadata records in one page'
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
required: ['taskId']
|
|
521
|
+
}
|
|
522
|
+
};
|
|
523
|
+
export const publishTaskCompositeTool = {
|
|
524
|
+
name: 'bitrix24_publish_task_composite',
|
|
525
|
+
description: 'Idempotently publish a bounded ordered set of final comments/evidence attachments and then move the task to one exact stage with read-back verification. Use one call for final workflow publication.',
|
|
526
|
+
inputSchema: {
|
|
527
|
+
type: 'object',
|
|
528
|
+
additionalProperties: false,
|
|
529
|
+
properties: {
|
|
530
|
+
taskId: {
|
|
531
|
+
type: 'string',
|
|
532
|
+
minLength: 1,
|
|
533
|
+
maxLength: 32,
|
|
534
|
+
pattern: '^\\d+$',
|
|
535
|
+
description: 'Task ID'
|
|
536
|
+
},
|
|
537
|
+
runId: {
|
|
538
|
+
type: 'string',
|
|
539
|
+
minLength: 1,
|
|
540
|
+
maxLength: 256,
|
|
541
|
+
description: 'Stable workflow run/dispatch ID'
|
|
542
|
+
},
|
|
543
|
+
evidenceSha256: {
|
|
544
|
+
type: 'string',
|
|
545
|
+
pattern: '^[a-fA-F0-9]{64}$',
|
|
546
|
+
description: 'SHA-256 of the evidence manifest being published'
|
|
547
|
+
},
|
|
548
|
+
comments: {
|
|
549
|
+
type: 'array',
|
|
550
|
+
maxItems: 12,
|
|
551
|
+
items: {
|
|
552
|
+
type: 'object',
|
|
553
|
+
additionalProperties: false,
|
|
554
|
+
properties: {
|
|
555
|
+
text: { type: 'string', minLength: 1, maxLength: 32000 },
|
|
556
|
+
filePaths: {
|
|
557
|
+
type: 'array',
|
|
558
|
+
maxItems: 12,
|
|
559
|
+
items: { type: 'string', minLength: 1, maxLength: 4096 },
|
|
560
|
+
description: 'Optional local evidence files for this comment'
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
required: ['text']
|
|
564
|
+
}
|
|
565
|
+
},
|
|
566
|
+
targetStageId: {
|
|
567
|
+
type: 'string',
|
|
568
|
+
minLength: 1,
|
|
569
|
+
maxLength: 64,
|
|
570
|
+
description: 'Exact target stage ID'
|
|
571
|
+
},
|
|
572
|
+
expectedCurrentStageId: {
|
|
573
|
+
type: 'string',
|
|
574
|
+
minLength: 1,
|
|
575
|
+
maxLength: 64,
|
|
576
|
+
description: 'Optional compare-and-set guard for the current stage'
|
|
577
|
+
},
|
|
578
|
+
preferApi: {
|
|
579
|
+
type: 'string',
|
|
580
|
+
enum: ['auto', 'chat', 'legacy'],
|
|
581
|
+
default: 'auto'
|
|
582
|
+
},
|
|
583
|
+
diskFolderId: {
|
|
584
|
+
type: 'string',
|
|
585
|
+
description: 'Optional Bitrix Disk folder for evidence uploads'
|
|
586
|
+
}
|
|
587
|
+
},
|
|
588
|
+
required: [
|
|
589
|
+
'taskId',
|
|
590
|
+
'runId',
|
|
591
|
+
'evidenceSha256',
|
|
592
|
+
'comments',
|
|
593
|
+
'targetStageId'
|
|
594
|
+
]
|
|
595
|
+
}
|
|
596
|
+
};
|
|
314
597
|
export const attachFilesToTaskTool = {
|
|
315
598
|
name: 'bitrix24_attach_files_to_task',
|
|
316
599
|
description: 'Upload local files (images, documents) to Bitrix24 Disk and attach them to an existing task',
|
|
317
600
|
inputSchema: {
|
|
318
601
|
type: 'object',
|
|
602
|
+
additionalProperties: false,
|
|
319
603
|
properties: {
|
|
320
|
-
taskId: {
|
|
604
|
+
taskId: {
|
|
605
|
+
type: 'string',
|
|
606
|
+
minLength: 1,
|
|
607
|
+
maxLength: 32,
|
|
608
|
+
pattern: '^\\d+$',
|
|
609
|
+
description: 'Task ID'
|
|
610
|
+
},
|
|
321
611
|
filePaths: {
|
|
322
612
|
type: 'array',
|
|
323
|
-
|
|
613
|
+
minItems: 1,
|
|
614
|
+
maxItems: 12,
|
|
615
|
+
items: { type: 'string', minLength: 1, maxLength: 4096 },
|
|
324
616
|
description: 'Local file paths to upload and attach'
|
|
325
617
|
},
|
|
326
618
|
diskFolderId: {
|
|
@@ -403,9 +695,21 @@ export const moveTaskToStageTool = {
|
|
|
403
695
|
description: 'Move a task to another Kanban/My Plan stage using task.stages.movetask. Provide stageId directly or stageName with entityId.',
|
|
404
696
|
inputSchema: {
|
|
405
697
|
type: 'object',
|
|
698
|
+
additionalProperties: false,
|
|
406
699
|
properties: {
|
|
407
|
-
taskId: {
|
|
408
|
-
|
|
700
|
+
taskId: {
|
|
701
|
+
type: 'string',
|
|
702
|
+
minLength: 1,
|
|
703
|
+
maxLength: 32,
|
|
704
|
+
pattern: '^\\d+$',
|
|
705
|
+
description: 'Task ID'
|
|
706
|
+
},
|
|
707
|
+
stageId: {
|
|
708
|
+
type: 'string',
|
|
709
|
+
minLength: 1,
|
|
710
|
+
maxLength: 64,
|
|
711
|
+
description: 'Target stage ID'
|
|
712
|
+
},
|
|
409
713
|
stageName: {
|
|
410
714
|
type: 'string',
|
|
411
715
|
description: 'Target stage title. Used to resolve stageId when stageId is omitted.'
|
|
@@ -695,19 +999,24 @@ export const resolveUserNamesTool = {
|
|
|
695
999
|
required: ['userIds']
|
|
696
1000
|
}
|
|
697
1001
|
};
|
|
698
|
-
|
|
699
|
-
export const allTools = [
|
|
1002
|
+
const allToolCatalog = [
|
|
700
1003
|
createTaskTool,
|
|
1004
|
+
getTaskSummaryTool,
|
|
1005
|
+
getTaskStageTool,
|
|
701
1006
|
getTaskTool,
|
|
702
1007
|
listTasksTool,
|
|
703
1008
|
getLatestTasksTool,
|
|
704
1009
|
getTasksFromDateRangeTool,
|
|
1010
|
+
getTaskCommentsTool,
|
|
1011
|
+
getTaskCommentsAfterTool,
|
|
705
1012
|
updateTaskTool,
|
|
706
1013
|
getTaskStagesTool,
|
|
707
1014
|
canMoveTaskInStagesTool,
|
|
708
1015
|
moveTaskToStageTool,
|
|
709
1016
|
getTaskFilesTool,
|
|
1017
|
+
getTaskFilesMetadataTool,
|
|
710
1018
|
addTaskCommentTool,
|
|
1019
|
+
publishTaskCompositeTool,
|
|
711
1020
|
attachFilesToTaskTool,
|
|
712
1021
|
addTaskChecklistItemTool,
|
|
713
1022
|
listTaskChecklistItemsTool,
|
|
@@ -727,8 +1036,35 @@ export const allTools = [
|
|
|
727
1036
|
getAllUsersTool,
|
|
728
1037
|
resolveUserNamesTool
|
|
729
1038
|
];
|
|
1039
|
+
const WORKFLOW_TOOL_NAMES = new Set([
|
|
1040
|
+
'bitrix24_get_task_summary',
|
|
1041
|
+
'bitrix24_get_task_stage',
|
|
1042
|
+
'bitrix24_get_comments_after',
|
|
1043
|
+
'bitrix24_get_task_files_metadata',
|
|
1044
|
+
'bitrix24_publish_task_composite',
|
|
1045
|
+
'bitrix24_add_task_comment',
|
|
1046
|
+
'bitrix24_attach_files_to_task',
|
|
1047
|
+
'bitrix24_move_task_to_stage'
|
|
1048
|
+
]);
|
|
1049
|
+
export function toolsForProfile(profile = process.env.BITRIX24_TOOL_PROFILE) {
|
|
1050
|
+
const normalized = profile?.trim().toLowerCase();
|
|
1051
|
+
if (!normalized || normalized === 'full') {
|
|
1052
|
+
return [...allToolCatalog];
|
|
1053
|
+
}
|
|
1054
|
+
if (normalized === 'workflow') {
|
|
1055
|
+
return allToolCatalog.filter((tool) => WORKFLOW_TOOL_NAMES.has(tool.name));
|
|
1056
|
+
}
|
|
1057
|
+
throw new Error(`Unsupported BITRIX24_TOOL_PROFILE ${JSON.stringify(profile)}; expected full or workflow`);
|
|
1058
|
+
}
|
|
1059
|
+
/** Tools exposed via MCP ListTools for the configured deployment profile. */
|
|
1060
|
+
export const allTools = toolsForProfile();
|
|
730
1061
|
export async function executeToolCall(name, args) {
|
|
731
1062
|
try {
|
|
1063
|
+
const tool = allTools.find((candidate) => candidate.name === name);
|
|
1064
|
+
if (!tool) {
|
|
1065
|
+
throw new Error(`Tool is not exposed by the active profile: ${name}`);
|
|
1066
|
+
}
|
|
1067
|
+
args = validateToolArguments(tool, args ?? {});
|
|
732
1068
|
switch (name) {
|
|
733
1069
|
case 'bitrix24_create_task': {
|
|
734
1070
|
const task = {
|
|
@@ -795,6 +1131,88 @@ export async function executeToolCall(name, args) {
|
|
|
795
1131
|
message: `Task created with ID: ${taskId}`
|
|
796
1132
|
};
|
|
797
1133
|
}
|
|
1134
|
+
case 'bitrix24_get_task_summary': {
|
|
1135
|
+
const task = await bitrix24Client.getTaskSummary(args.taskId, Array.isArray(args.select) && args.select.length > 0
|
|
1136
|
+
? args.select
|
|
1137
|
+
: undefined);
|
|
1138
|
+
return {
|
|
1139
|
+
success: true,
|
|
1140
|
+
task
|
|
1141
|
+
};
|
|
1142
|
+
}
|
|
1143
|
+
case 'bitrix24_get_task_stage': {
|
|
1144
|
+
const stage = await bitrix24Client.getTaskStage(args.taskId);
|
|
1145
|
+
return {
|
|
1146
|
+
success: true,
|
|
1147
|
+
...stage
|
|
1148
|
+
};
|
|
1149
|
+
}
|
|
1150
|
+
case 'bitrix24_get_comments_after': {
|
|
1151
|
+
const afterCommentId = String(args.afterCommentId);
|
|
1152
|
+
const afterCommentNumber = Number(afterCommentId);
|
|
1153
|
+
if (!Number.isSafeInteger(afterCommentNumber)) {
|
|
1154
|
+
throw new Error('afterCommentId exceeds the supported safe integer range');
|
|
1155
|
+
}
|
|
1156
|
+
const limit = Math.min(20, Math.max(1, Math.trunc(Number(args.limit ?? 20))));
|
|
1157
|
+
const maxCommentChars = Math.min(8_000, Math.max(256, Number(args.maxCommentChars ?? 4_000)));
|
|
1158
|
+
const maxTotalChars = Math.min(32_000, Math.max(512, Number(args.maxTotalChars ?? 16_000)));
|
|
1159
|
+
const commentsResult = await bitrix24Client.getTaskComments(args.taskId, {
|
|
1160
|
+
preferApi: args.preferApi,
|
|
1161
|
+
firstId: afterCommentNumber,
|
|
1162
|
+
limit: Math.min(50, limit + 1),
|
|
1163
|
+
includeSystemMessages: args.includeSystemMessages === true,
|
|
1164
|
+
includeAttachments: false,
|
|
1165
|
+
includeContent: false
|
|
1166
|
+
});
|
|
1167
|
+
const candidates = commentsResult.comments
|
|
1168
|
+
.filter((comment) => /^\d{1,32}$/.test(String(comment.id)))
|
|
1169
|
+
.filter((comment) => compareNumericIds(comment.id, afterCommentId) > 0)
|
|
1170
|
+
.sort((left, right) => compareNumericIds(left.id, right.id));
|
|
1171
|
+
const comments = [];
|
|
1172
|
+
let totalCommentChars = 0;
|
|
1173
|
+
for (const comment of candidates) {
|
|
1174
|
+
if (comments.length >= limit) {
|
|
1175
|
+
break;
|
|
1176
|
+
}
|
|
1177
|
+
const remainingChars = maxTotalChars - totalCommentChars;
|
|
1178
|
+
if (remainingChars <= 0) {
|
|
1179
|
+
break;
|
|
1180
|
+
}
|
|
1181
|
+
const effectiveCap = Math.max(1, Math.min(maxCommentChars, remainingChars));
|
|
1182
|
+
const compacted = compactText(comment.postMessage, effectiveCap);
|
|
1183
|
+
const textLength = compacted.text?.length ?? 0;
|
|
1184
|
+
if (comments.length > 0 && textLength > remainingChars) {
|
|
1185
|
+
break;
|
|
1186
|
+
}
|
|
1187
|
+
comments.push({
|
|
1188
|
+
id: comment.id,
|
|
1189
|
+
authorId: boundedOptionalString(comment.authorId, 64),
|
|
1190
|
+
authorName: boundedOptionalString(comment.authorName, 256),
|
|
1191
|
+
postDate: boundedOptionalString(comment.postDate, 128),
|
|
1192
|
+
postMessage: compacted.text,
|
|
1193
|
+
truncated: compacted.truncated,
|
|
1194
|
+
originalChars: compacted.originalChars,
|
|
1195
|
+
sha256: compacted.sha256
|
|
1196
|
+
});
|
|
1197
|
+
totalCommentChars += textLength;
|
|
1198
|
+
}
|
|
1199
|
+
const nextAfterCommentId = comments.length > 0
|
|
1200
|
+
? String(comments[comments.length - 1].id)
|
|
1201
|
+
: afterCommentId;
|
|
1202
|
+
const boundedErrors = boundErrors(commentsResult.errors);
|
|
1203
|
+
return {
|
|
1204
|
+
success: commentsResult.errors.length === 0,
|
|
1205
|
+
taskId: commentsResult.taskId,
|
|
1206
|
+
apiMode: commentsResult.apiMode,
|
|
1207
|
+
afterCommentId,
|
|
1208
|
+
nextAfterCommentId,
|
|
1209
|
+
hasMore: candidates.some((comment) => compareNumericIds(comment.id, nextAfterCommentId) > 0),
|
|
1210
|
+
pageSize: comments.length,
|
|
1211
|
+
totalCommentChars,
|
|
1212
|
+
comments,
|
|
1213
|
+
...boundedErrors
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
798
1216
|
case 'bitrix24_get_task_comments': {
|
|
799
1217
|
const order = {};
|
|
800
1218
|
order[args.orderBy || 'POST_DATE'] = args.orderDirection || 'asc';
|
|
@@ -892,6 +1310,25 @@ export async function executeToolCall(name, args) {
|
|
|
892
1310
|
: `Retrieved ${filesResult.files.length} file(s) for task ${args.taskId}`
|
|
893
1311
|
};
|
|
894
1312
|
}
|
|
1313
|
+
case 'bitrix24_get_task_files_metadata': {
|
|
1314
|
+
const filesResult = await bitrix24Client.getTaskFilesMetadata(args.taskId, {
|
|
1315
|
+
diskFileIds: args.diskFileIds,
|
|
1316
|
+
imagesOnly: args.imagesOnly === true,
|
|
1317
|
+
afterFileId: args.afterFileId,
|
|
1318
|
+
limit: args.limit
|
|
1319
|
+
});
|
|
1320
|
+
const boundedErrors = boundErrors(filesResult.errors);
|
|
1321
|
+
return {
|
|
1322
|
+
success: filesResult.errors.length === 0,
|
|
1323
|
+
taskId: filesResult.taskId,
|
|
1324
|
+
afterFileId: filesResult.afterFileId,
|
|
1325
|
+
nextAfterFileId: filesResult.nextAfterFileId,
|
|
1326
|
+
hasMore: filesResult.hasMore,
|
|
1327
|
+
pageSize: filesResult.files.length,
|
|
1328
|
+
files: filesResult.files,
|
|
1329
|
+
...boundedErrors
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
895
1332
|
case 'bitrix24_attach_files_to_task': {
|
|
896
1333
|
const attachmentResult = await bitrix24Client.attachLocalFilesToTask(args.taskId, args.filePaths, args.diskFolderId);
|
|
897
1334
|
return {
|
|
@@ -904,6 +1341,22 @@ export async function executeToolCall(name, args) {
|
|
|
904
1341
|
: `Attached ${attachmentResult.attached.length} file(s) with ${attachmentResult.errors.length} error(s)`
|
|
905
1342
|
};
|
|
906
1343
|
}
|
|
1344
|
+
case 'bitrix24_publish_task_composite': {
|
|
1345
|
+
const receipt = await publishTaskComposite(bitrix24Client, {
|
|
1346
|
+
taskId: args.taskId,
|
|
1347
|
+
runId: args.runId,
|
|
1348
|
+
evidenceSha256: args.evidenceSha256,
|
|
1349
|
+
comments: args.comments,
|
|
1350
|
+
targetStageId: args.targetStageId,
|
|
1351
|
+
expectedCurrentStageId: args.expectedCurrentStageId,
|
|
1352
|
+
preferApi: args.preferApi,
|
|
1353
|
+
diskFolderId: args.diskFolderId
|
|
1354
|
+
});
|
|
1355
|
+
return {
|
|
1356
|
+
success: true,
|
|
1357
|
+
receipt
|
|
1358
|
+
};
|
|
1359
|
+
}
|
|
907
1360
|
case 'bitrix24_get_task': {
|
|
908
1361
|
const details = await bitrix24Client.getTaskDetails(args.id, {
|
|
909
1362
|
includeComments: args.includeComments,
|