feat(rootly): expand Rootly integration from 14 to 27 tools (#3902)

* feat(rootly): expand Rootly integration from 14 to 27 tools

Add 13 new tools: delete_incident, get_alert, update_alert,
acknowledge_alert, resolve_alert, create_action_item, list_action_items,
list_users, list_on_calls, list_schedules, list_escalation_policies,
list_causes, list_playbooks. Includes tool files, types, registry,
block definition with subBlocks/conditions/params, and docs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(rootly): handle 204 No Content response for delete_incident

DELETE /v1/incidents/{id} returns 204 with empty body. Avoid calling
response.json() on success — return success/message instead.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(rootly): remove non-TSDoc comments, add empty body to acknowledge_alert

Remove all inline section comments from block definition per CLAUDE.md
guidelines. Add explicit empty JSON:API body to acknowledge_alert POST
to prevent potential 400 from servers expecting a body with Content-Type.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(rootly): send empty body on resolve_alert, guard assignedToUserId parse

resolve_alert now sends { data: {} } instead of undefined when no
optional params are provided, matching the acknowledge_alert fix.
create_action_item now validates assignedToUserId is numeric before
parseInt to avoid silent NaN coercion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(rootly): extract on-call relationships from JSON:API relationships/included

On-call user, schedule, and escalation policy are exposed as JSON:API
relationships, not flat attributes. Now extracts IDs from
item.relationships and looks up names from the included array.
Adds ?include=user,schedule,escalation_policy to the request URL.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(rootly): remove last non-TSDoc comment from block definition

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* docs

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Waleed
2026-04-02 13:40:45 -07:00
committed by GitHub
parent e2e53aba76
commit f9d73db65c
21 changed files with 2879 additions and 16 deletions
+381
View File
@@ -245,6 +245,7 @@ Create a new alert in Rootly for on-call notification and routing.
| --------- | ---- | ----------- |
| `alert` | object | The created alert |
| ↳ `id` | string | Unique alert ID |
| ↳ `shortId` | string | Short alert ID |
| ↳ `summary` | string | Alert summary |
| ↳ `description` | string | Alert description |
| ↳ `source` | string | Alert source |
@@ -254,6 +255,8 @@ Create a new alert in Rootly for on-call notification and routing.
| ↳ `deduplicationKey` | string | Deduplication key |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| ↳ `startedAt` | string | Start date |
| ↳ `endedAt` | string | End date |
### `rootly_list_alerts`
@@ -278,6 +281,7 @@ List alerts from Rootly with optional filtering by status, source, and services.
| --------- | ---- | ----------- |
| `alerts` | array | List of alerts |
| ↳ `id` | string | Unique alert ID |
| ↳ `shortId` | string | Short alert ID |
| ↳ `summary` | string | Alert summary |
| ↳ `description` | string | Alert description |
| ↳ `source` | string | Alert source |
@@ -287,6 +291,8 @@ List alerts from Rootly with optional filtering by status, source, and services.
| ↳ `deduplicationKey` | string | Deduplication key |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| ↳ `startedAt` | string | Start date |
| ↳ `endedAt` | string | End date |
| `totalCount` | number | Total number of alerts returned |
### `rootly_add_incident_event`
@@ -507,4 +513,379 @@ List incident retrospectives (post-mortems) from Rootly.
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of retrospectives returned |
### `rootly_delete_incident`
Delete an incident by ID from Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `incidentId` | string | Yes | The ID of the incident to delete |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `success` | boolean | Whether the deletion succeeded |
| `message` | string | Result message |
### `rootly_get_alert`
Retrieve a single alert by ID from Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `alertId` | string | Yes | The ID of the alert to retrieve |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alert` | object | The alert details |
| ↳ `id` | string | Unique alert ID |
| ↳ `shortId` | string | Short alert ID |
| ↳ `summary` | string | Alert summary |
| ↳ `description` | string | Alert description |
| ↳ `source` | string | Alert source |
| ↳ `status` | string | Alert status |
| ↳ `externalId` | string | External ID |
| ↳ `externalUrl` | string | External URL |
| ↳ `deduplicationKey` | string | Deduplication key |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| ↳ `startedAt` | string | Start date |
| ↳ `endedAt` | string | End date |
### `rootly_update_alert`
Update an existing alert in Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `alertId` | string | Yes | The ID of the alert to update |
| `summary` | string | No | Updated alert summary |
| `description` | string | No | Updated alert description |
| `source` | string | No | Updated alert source |
| `serviceIds` | string | No | Comma-separated service IDs to attach |
| `groupIds` | string | No | Comma-separated team/group IDs to attach |
| `environmentIds` | string | No | Comma-separated environment IDs to attach |
| `externalId` | string | No | Updated external ID |
| `externalUrl` | string | No | Updated external URL |
| `deduplicationKey` | string | No | Updated deduplication key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alert` | object | The updated alert |
| ↳ `id` | string | Unique alert ID |
| ↳ `shortId` | string | Short alert ID |
| ↳ `summary` | string | Alert summary |
| ↳ `description` | string | Alert description |
| ↳ `source` | string | Alert source |
| ↳ `status` | string | Alert status |
| ↳ `externalId` | string | External ID |
| ↳ `externalUrl` | string | External URL |
| ↳ `deduplicationKey` | string | Deduplication key |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| ↳ `startedAt` | string | Start date |
| ↳ `endedAt` | string | End date |
### `rootly_acknowledge_alert`
Acknowledge an alert in Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `alertId` | string | Yes | The ID of the alert to acknowledge |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alert` | object | The acknowledged alert |
| ↳ `id` | string | Unique alert ID |
| ↳ `shortId` | string | Short alert ID |
| ↳ `summary` | string | Alert summary |
| ↳ `description` | string | Alert description |
| ↳ `source` | string | Alert source |
| ↳ `status` | string | Alert status |
| ↳ `externalId` | string | External ID |
| ↳ `externalUrl` | string | External URL |
| ↳ `deduplicationKey` | string | Deduplication key |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| ↳ `startedAt` | string | Start date |
| ↳ `endedAt` | string | End date |
### `rootly_resolve_alert`
Resolve an alert in Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `alertId` | string | Yes | The ID of the alert to resolve |
| `resolutionMessage` | string | No | Message describing how the alert was resolved |
| `resolveRelatedIncidents` | boolean | No | Whether to also resolve related incidents |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alert` | object | The resolved alert |
| ↳ `id` | string | Unique alert ID |
| ↳ `shortId` | string | Short alert ID |
| ↳ `summary` | string | Alert summary |
| ↳ `description` | string | Alert description |
| ↳ `source` | string | Alert source |
| ↳ `status` | string | Alert status |
| ↳ `externalId` | string | External ID |
| ↳ `externalUrl` | string | External URL |
| ↳ `deduplicationKey` | string | Deduplication key |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| ↳ `startedAt` | string | Start date |
| ↳ `endedAt` | string | End date |
### `rootly_create_action_item`
Create a new action item for an incident in Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `incidentId` | string | Yes | The ID of the incident to add the action item to |
| `summary` | string | Yes | The title of the action item |
| `description` | string | No | A detailed description of the action item |
| `kind` | string | No | The kind of action item \(task, follow_up\) |
| `priority` | string | No | Priority level \(high, medium, low\) |
| `status` | string | No | Action item status \(open, in_progress, cancelled, done\) |
| `assignedToUserId` | string | No | The user ID to assign the action item to |
| `dueDate` | string | No | Due date for the action item |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `actionItem` | object | The created action item |
| ↳ `id` | string | Unique action item ID |
| ↳ `summary` | string | Action item title |
| ↳ `description` | string | Action item description |
| ↳ `kind` | string | Action item kind \(task, follow_up\) |
| ↳ `priority` | string | Priority level |
| ↳ `status` | string | Action item status |
| ↳ `dueDate` | string | Due date |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
### `rootly_list_action_items`
List action items for an incident in Rootly.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `incidentId` | string | Yes | The ID of the incident to list action items for |
| `pageSize` | number | No | Number of items per page \(default: 20\) |
| `pageNumber` | number | No | Page number for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `actionItems` | array | List of action items |
| ↳ `id` | string | Unique action item ID |
| ↳ `summary` | string | Action item title |
| ↳ `description` | string | Action item description |
| ↳ `kind` | string | Action item kind \(task, follow_up\) |
| ↳ `priority` | string | Priority level |
| ↳ `status` | string | Action item status |
| ↳ `dueDate` | string | Due date |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of action items returned |
### `rootly_list_users`
List users from Rootly with optional search and email filtering.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `search` | string | No | Search term to filter users |
| `email` | string | No | Filter users by email address |
| `pageSize` | number | No | Number of items per page \(default: 20\) |
| `pageNumber` | number | No | Page number for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `users` | array | List of users |
| ↳ `id` | string | Unique user ID |
| ↳ `email` | string | User email address |
| ↳ `firstName` | string | User first name |
| ↳ `lastName` | string | User last name |
| ↳ `fullName` | string | User full name |
| ↳ `timeZone` | string | User time zone |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of users returned |
### `rootly_list_on_calls`
List current on-call entries from Rootly with optional filtering.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `scheduleIds` | string | No | Comma-separated schedule IDs to filter by |
| `escalationPolicyIds` | string | No | Comma-separated escalation policy IDs to filter by |
| `userIds` | string | No | Comma-separated user IDs to filter by |
| `serviceIds` | string | No | Comma-separated service IDs to filter by |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `onCalls` | array | List of on-call entries |
| ↳ `id` | string | Unique on-call entry ID |
| ↳ `userId` | string | ID of the on-call user |
| ↳ `userName` | string | Name of the on-call user |
| ↳ `scheduleId` | string | ID of the associated schedule |
| ↳ `scheduleName` | string | Name of the associated schedule |
| ↳ `escalationPolicyId` | string | ID of the associated escalation policy |
| ↳ `startTime` | string | On-call start time |
| ↳ `endTime` | string | On-call end time |
| `totalCount` | number | Total number of on-call entries returned |
### `rootly_list_schedules`
List on-call schedules from Rootly with optional search filtering.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `search` | string | No | Search term to filter schedules |
| `pageSize` | number | No | Number of items per page \(default: 20\) |
| `pageNumber` | number | No | Page number for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `schedules` | array | List of schedules |
| ↳ `id` | string | Unique schedule ID |
| ↳ `name` | string | Schedule name |
| ↳ `description` | string | Schedule description |
| ↳ `allTimeCoverage` | boolean | Whether schedule provides 24/7 coverage |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of schedules returned |
### `rootly_list_escalation_policies`
List escalation policies from Rootly with optional search filtering.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `search` | string | No | Search term to filter escalation policies |
| `pageSize` | number | No | Number of items per page \(default: 20\) |
| `pageNumber` | number | No | Page number for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `escalationPolicies` | array | List of escalation policies |
| ↳ `id` | string | Unique escalation policy ID |
| ↳ `name` | string | Escalation policy name |
| ↳ `description` | string | Escalation policy description |
| ↳ `repeatCount` | number | Number of times to repeat escalation |
| ↳ `groupIds` | array | Associated group IDs |
| ↳ `serviceIds` | array | Associated service IDs |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of escalation policies returned |
### `rootly_list_causes`
List causes from Rootly with optional search filtering.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `search` | string | No | Search term to filter causes |
| `pageSize` | number | No | Number of items per page \(default: 20\) |
| `pageNumber` | number | No | Page number for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `causes` | array | List of causes |
| ↳ `id` | string | Unique cause ID |
| ↳ `name` | string | Cause name |
| ↳ `slug` | string | Cause slug |
| ↳ `description` | string | Cause description |
| ↳ `position` | number | Cause position |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of causes returned |
### `rootly_list_playbooks`
List playbooks from Rootly with pagination support.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | Rootly API key |
| `pageSize` | number | No | Number of items per page \(default: 20\) |
| `pageNumber` | number | No | Page number for pagination |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `playbooks` | array | List of playbooks |
| ↳ `id` | string | Unique playbook ID |
| ↳ `title` | string | Playbook title |
| ↳ `summary` | string | Playbook summary |
| ↳ `externalUrl` | string | External URL |
| ↳ `createdAt` | string | Creation date |
| ↳ `updatedAt` | string | Last update date |
| `totalCount` | number | Total number of playbooks returned |
@@ -9820,9 +9820,61 @@
{
"name": "List Retrospectives",
"description": "List incident retrospectives (post-mortems) from Rootly."
},
{
"name": "Delete Incident",
"description": "Delete an incident by ID from Rootly."
},
{
"name": "Get Alert",
"description": "Retrieve a single alert by ID from Rootly."
},
{
"name": "Update Alert",
"description": "Update an existing alert in Rootly."
},
{
"name": "Acknowledge Alert",
"description": "Acknowledge an alert in Rootly."
},
{
"name": "Resolve Alert",
"description": "Resolve an alert in Rootly."
},
{
"name": "Create Action Item",
"description": "Create a new action item for an incident in Rootly."
},
{
"name": "List Action Items",
"description": "List action items for an incident in Rootly."
},
{
"name": "List Users",
"description": "List users from Rootly with optional search and email filtering."
},
{
"name": "List On-Calls",
"description": "List current on-call entries from Rootly with optional filtering."
},
{
"name": "List Schedules",
"description": "List on-call schedules from Rootly with optional search filtering."
},
{
"name": "List Escalation Policies",
"description": "List escalation policies from Rootly with optional search filtering."
},
{
"name": "List Causes",
"description": "List causes from Rootly with optional search filtering."
},
{
"name": "List Playbooks",
"description": "List playbooks from Rootly with pagination support."
}
],
"operationCount": 14,
"operationCount": 27,
"triggers": [],
"triggerCount": 0,
"authType": "api-key",
+637 -15
View File
@@ -36,11 +36,23 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
{ label: 'List Incident Types', id: 'rootly_list_incident_types' },
{ label: 'List Functionalities', id: 'rootly_list_functionalities' },
{ label: 'List Retrospectives', id: 'rootly_list_retrospectives' },
{ label: 'Delete Incident', id: 'rootly_delete_incident' },
{ label: 'Get Alert', id: 'rootly_get_alert' },
{ label: 'Update Alert', id: 'rootly_update_alert' },
{ label: 'Acknowledge Alert', id: 'rootly_acknowledge_alert' },
{ label: 'Resolve Alert', id: 'rootly_resolve_alert' },
{ label: 'Create Action Item', id: 'rootly_create_action_item' },
{ label: 'List Action Items', id: 'rootly_list_action_items' },
{ label: 'List Users', id: 'rootly_list_users' },
{ label: 'List On-Calls', id: 'rootly_list_on_calls' },
{ label: 'List Schedules', id: 'rootly_list_schedules' },
{ label: 'List Escalation Policies', id: 'rootly_list_escalation_policies' },
{ label: 'List Causes', id: 'rootly_list_causes' },
{ label: 'List Playbooks', id: 'rootly_list_playbooks' },
],
value: () => 'rootly_create_incident',
},
// Create Incident fields
{
id: 'title',
title: 'Title',
@@ -170,7 +182,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// Get Incident fields
{
id: 'getIncidentId',
title: 'Incident ID',
@@ -180,7 +191,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
required: { field: 'operation', value: 'rootly_get_incident' },
},
// Update Incident fields
{
id: 'updateIncidentId',
title: 'Incident ID',
@@ -341,7 +351,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Incidents fields
{
id: 'listIncidentsStatus',
title: 'Status Filter',
@@ -434,7 +443,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// Create Alert fields
{
id: 'alertSummary',
title: 'Summary',
@@ -520,7 +528,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Alerts fields
{
id: 'listAlertsStatus',
title: 'Status Filter',
@@ -585,7 +592,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// Add Incident Event fields
{
id: 'eventIncidentId',
title: 'Incident ID',
@@ -616,7 +622,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Services fields
{
id: 'servicesSearch',
title: 'Search',
@@ -641,7 +646,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Severities fields
{
id: 'severitiesSearch',
title: 'Search',
@@ -666,7 +670,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Teams fields
{
id: 'teamsSearch',
title: 'Search',
@@ -691,7 +694,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Environments fields
{
id: 'environmentsSearch',
title: 'Search',
@@ -716,7 +718,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Incident Types fields
{
id: 'incidentTypesSearch',
title: 'Name Filter',
@@ -741,7 +742,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Functionalities fields
{
id: 'functionalitiesSearch',
title: 'Search',
@@ -766,7 +766,6 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// List Retrospectives fields
{
id: 'retrospectivesStatus',
title: 'Status Filter',
@@ -803,7 +802,404 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
mode: 'advanced',
},
// API Key (common)
{
id: 'deleteIncidentId',
title: 'Incident ID',
type: 'short-input',
placeholder: 'The ID of the incident to delete',
condition: { field: 'operation', value: 'rootly_delete_incident' },
required: { field: 'operation', value: 'rootly_delete_incident' },
},
{
id: 'getAlertId',
title: 'Alert ID',
type: 'short-input',
placeholder: 'The ID of the alert to retrieve',
condition: { field: 'operation', value: 'rootly_get_alert' },
required: { field: 'operation', value: 'rootly_get_alert' },
},
{
id: 'updateAlertId',
title: 'Alert ID',
type: 'short-input',
placeholder: 'The ID of the alert to update',
condition: { field: 'operation', value: 'rootly_update_alert' },
required: { field: 'operation', value: 'rootly_update_alert' },
},
{
id: 'updateAlertSummary',
title: 'Summary',
type: 'short-input',
placeholder: 'Updated alert summary',
condition: { field: 'operation', value: 'rootly_update_alert' },
},
{
id: 'updateAlertDescription',
title: 'Description',
type: 'long-input',
placeholder: 'Updated alert description',
condition: { field: 'operation', value: 'rootly_update_alert' },
},
{
id: 'updateAlertSource',
title: 'Source',
type: 'short-input',
placeholder: 'Alert source (e.g., api, datadog)',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'updateAlertServiceIds',
title: 'Service IDs',
type: 'short-input',
placeholder: 'Comma-separated service IDs',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'updateAlertGroupIds',
title: 'Team IDs',
type: 'short-input',
placeholder: 'Comma-separated team/group IDs',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'updateAlertEnvironmentIds',
title: 'Environment IDs',
type: 'short-input',
placeholder: 'Comma-separated environment IDs',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'updateAlertExternalId',
title: 'External ID',
type: 'short-input',
placeholder: 'External alert ID',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'updateAlertExternalUrl',
title: 'External URL',
type: 'short-input',
placeholder: 'Link to external source',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'updateAlertDeduplicationKey',
title: 'Deduplication Key',
type: 'short-input',
placeholder: 'Key to deduplicate alerts',
condition: { field: 'operation', value: 'rootly_update_alert' },
mode: 'advanced',
},
{
id: 'ackAlertId',
title: 'Alert ID',
type: 'short-input',
placeholder: 'The ID of the alert to acknowledge',
condition: { field: 'operation', value: 'rootly_acknowledge_alert' },
required: { field: 'operation', value: 'rootly_acknowledge_alert' },
},
{
id: 'resolveAlertId',
title: 'Alert ID',
type: 'short-input',
placeholder: 'The ID of the alert to resolve',
condition: { field: 'operation', value: 'rootly_resolve_alert' },
required: { field: 'operation', value: 'rootly_resolve_alert' },
},
{
id: 'resolveResolutionMessage',
title: 'Resolution Message',
type: 'long-input',
placeholder: 'How was the alert resolved?',
condition: { field: 'operation', value: 'rootly_resolve_alert' },
},
{
id: 'resolveRelatedIncidents',
title: 'Resolve Related Incidents',
type: 'dropdown',
options: [
{ label: 'No', id: '' },
{ label: 'Yes', id: 'true' },
],
value: () => '',
condition: { field: 'operation', value: 'rootly_resolve_alert' },
mode: 'advanced',
},
{
id: 'actionItemIncidentId',
title: 'Incident ID',
type: 'short-input',
placeholder: 'The ID of the incident',
condition: { field: 'operation', value: 'rootly_create_action_item' },
required: { field: 'operation', value: 'rootly_create_action_item' },
},
{
id: 'actionItemSummary',
title: 'Summary',
type: 'short-input',
placeholder: 'Action item title',
condition: { field: 'operation', value: 'rootly_create_action_item' },
required: { field: 'operation', value: 'rootly_create_action_item' },
},
{
id: 'actionItemDescription',
title: 'Description',
type: 'long-input',
placeholder: 'Describe the action item',
condition: { field: 'operation', value: 'rootly_create_action_item' },
},
{
id: 'actionItemKind',
title: 'Kind',
type: 'dropdown',
options: [
{ label: 'Default', id: '' },
{ label: 'Task', id: 'task' },
{ label: 'Follow Up', id: 'follow_up' },
],
value: () => '',
condition: { field: 'operation', value: 'rootly_create_action_item' },
},
{
id: 'actionItemPriority',
title: 'Priority',
type: 'dropdown',
options: [
{ label: 'Default', id: '' },
{ label: 'High', id: 'high' },
{ label: 'Medium', id: 'medium' },
{ label: 'Low', id: 'low' },
],
value: () => '',
condition: { field: 'operation', value: 'rootly_create_action_item' },
},
{
id: 'actionItemStatus',
title: 'Status',
type: 'dropdown',
options: [
{ label: 'Default', id: '' },
{ label: 'Open', id: 'open' },
{ label: 'In Progress', id: 'in_progress' },
{ label: 'Cancelled', id: 'cancelled' },
{ label: 'Done', id: 'done' },
],
value: () => '',
condition: { field: 'operation', value: 'rootly_create_action_item' },
mode: 'advanced',
},
{
id: 'actionItemAssignedToUserId',
title: 'Assigned To User ID',
type: 'short-input',
placeholder: 'User ID to assign (use List Users to find IDs)',
condition: { field: 'operation', value: 'rootly_create_action_item' },
mode: 'advanced',
},
{
id: 'actionItemDueDate',
title: 'Due Date',
type: 'short-input',
placeholder: 'YYYY-MM-DD',
condition: { field: 'operation', value: 'rootly_create_action_item' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt:
'Generate a date in YYYY-MM-DD format for the requested due date. Return ONLY the date string - no explanations, no extra text.',
placeholder: 'Describe the due date (e.g., "next Friday", "in 2 weeks")...',
generationType: 'timestamp',
},
},
{
id: 'listActionItemsIncidentId',
title: 'Incident ID',
type: 'short-input',
placeholder: 'The ID of the incident',
condition: { field: 'operation', value: 'rootly_list_action_items' },
required: { field: 'operation', value: 'rootly_list_action_items' },
},
{
id: 'listActionItemsPageSize',
title: 'Page Size',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'rootly_list_action_items' },
mode: 'advanced',
},
{
id: 'listActionItemsPageNumber',
title: 'Page Number',
type: 'short-input',
placeholder: '1',
condition: { field: 'operation', value: 'rootly_list_action_items' },
mode: 'advanced',
},
{
id: 'usersSearch',
title: 'Search',
type: 'short-input',
placeholder: 'Search users...',
condition: { field: 'operation', value: 'rootly_list_users' },
},
{
id: 'usersEmail',
title: 'Email Filter',
type: 'short-input',
placeholder: 'Filter by email address',
condition: { field: 'operation', value: 'rootly_list_users' },
mode: 'advanced',
},
{
id: 'usersPageSize',
title: 'Page Size',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'rootly_list_users' },
mode: 'advanced',
},
{
id: 'usersPageNumber',
title: 'Page Number',
type: 'short-input',
placeholder: '1',
condition: { field: 'operation', value: 'rootly_list_users' },
mode: 'advanced',
},
{
id: 'onCallsScheduleIds',
title: 'Schedule IDs',
type: 'short-input',
placeholder: 'Comma-separated schedule IDs',
condition: { field: 'operation', value: 'rootly_list_on_calls' },
},
{
id: 'onCallsEscalationPolicyIds',
title: 'Escalation Policy IDs',
type: 'short-input',
placeholder: 'Comma-separated escalation policy IDs',
condition: { field: 'operation', value: 'rootly_list_on_calls' },
},
{
id: 'onCallsUserIds',
title: 'User IDs',
type: 'short-input',
placeholder: 'Comma-separated user IDs',
condition: { field: 'operation', value: 'rootly_list_on_calls' },
mode: 'advanced',
},
{
id: 'onCallsServiceIds',
title: 'Service IDs',
type: 'short-input',
placeholder: 'Comma-separated service IDs',
condition: { field: 'operation', value: 'rootly_list_on_calls' },
mode: 'advanced',
},
{
id: 'schedulesSearch',
title: 'Search',
type: 'short-input',
placeholder: 'Search schedules...',
condition: { field: 'operation', value: 'rootly_list_schedules' },
},
{
id: 'schedulesPageSize',
title: 'Page Size',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'rootly_list_schedules' },
mode: 'advanced',
},
{
id: 'schedulesPageNumber',
title: 'Page Number',
type: 'short-input',
placeholder: '1',
condition: { field: 'operation', value: 'rootly_list_schedules' },
mode: 'advanced',
},
{
id: 'escalationPoliciesSearch',
title: 'Search',
type: 'short-input',
placeholder: 'Search escalation policies...',
condition: { field: 'operation', value: 'rootly_list_escalation_policies' },
},
{
id: 'escalationPoliciesPageSize',
title: 'Page Size',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'rootly_list_escalation_policies' },
mode: 'advanced',
},
{
id: 'escalationPoliciesPageNumber',
title: 'Page Number',
type: 'short-input',
placeholder: '1',
condition: { field: 'operation', value: 'rootly_list_escalation_policies' },
mode: 'advanced',
},
{
id: 'causesSearch',
title: 'Search',
type: 'short-input',
placeholder: 'Search causes...',
condition: { field: 'operation', value: 'rootly_list_causes' },
},
{
id: 'causesPageSize',
title: 'Page Size',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'rootly_list_causes' },
mode: 'advanced',
},
{
id: 'causesPageNumber',
title: 'Page Number',
type: 'short-input',
placeholder: '1',
condition: { field: 'operation', value: 'rootly_list_causes' },
mode: 'advanced',
},
{
id: 'playbooksPageSize',
title: 'Page Size',
type: 'short-input',
placeholder: '20',
condition: { field: 'operation', value: 'rootly_list_playbooks' },
mode: 'advanced',
},
{
id: 'playbooksPageNumber',
title: 'Page Number',
type: 'short-input',
placeholder: '1',
condition: { field: 'operation', value: 'rootly_list_playbooks' },
mode: 'advanced',
},
{
id: 'apiKey',
title: 'API Key',
@@ -829,6 +1225,19 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
'rootly_list_incident_types',
'rootly_list_functionalities',
'rootly_list_retrospectives',
'rootly_delete_incident',
'rootly_get_alert',
'rootly_update_alert',
'rootly_acknowledge_alert',
'rootly_resolve_alert',
'rootly_create_action_item',
'rootly_list_action_items',
'rootly_list_users',
'rootly_list_on_calls',
'rootly_list_schedules',
'rootly_list_escalation_policies',
'rootly_list_causes',
'rootly_list_playbooks',
],
config: {
tool: (params) => params.operation,
@@ -1012,6 +1421,131 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
: undefined,
}
case 'rootly_delete_incident':
return {
...baseParams,
incidentId: params.deleteIncidentId,
}
case 'rootly_get_alert':
return {
...baseParams,
alertId: params.getAlertId,
}
case 'rootly_update_alert':
return {
...baseParams,
alertId: params.updateAlertId,
summary: params.updateAlertSummary,
description: params.updateAlertDescription,
source: params.updateAlertSource,
serviceIds: params.updateAlertServiceIds,
groupIds: params.updateAlertGroupIds,
environmentIds: params.updateAlertEnvironmentIds,
externalId: params.updateAlertExternalId,
externalUrl: params.updateAlertExternalUrl,
deduplicationKey: params.updateAlertDeduplicationKey,
}
case 'rootly_acknowledge_alert':
return {
...baseParams,
alertId: params.ackAlertId,
}
case 'rootly_resolve_alert':
return {
...baseParams,
alertId: params.resolveAlertId,
resolutionMessage: params.resolveResolutionMessage,
resolveRelatedIncidents: params.resolveRelatedIncidents
? params.resolveRelatedIncidents === 'true'
: undefined,
}
case 'rootly_create_action_item':
return {
...baseParams,
incidentId: params.actionItemIncidentId,
summary: params.actionItemSummary,
description: params.actionItemDescription,
kind: params.actionItemKind,
priority: params.actionItemPriority,
status: params.actionItemStatus,
assignedToUserId: params.actionItemAssignedToUserId,
dueDate: params.actionItemDueDate,
}
case 'rootly_list_action_items':
return {
...baseParams,
incidentId: params.listActionItemsIncidentId,
pageSize: params.listActionItemsPageSize
? Number(params.listActionItemsPageSize)
: undefined,
pageNumber: params.listActionItemsPageNumber
? Number(params.listActionItemsPageNumber)
: undefined,
}
case 'rootly_list_users':
return {
...baseParams,
search: params.usersSearch,
email: params.usersEmail,
pageSize: params.usersPageSize ? Number(params.usersPageSize) : undefined,
pageNumber: params.usersPageNumber ? Number(params.usersPageNumber) : undefined,
}
case 'rootly_list_on_calls':
return {
...baseParams,
scheduleIds: params.onCallsScheduleIds,
escalationPolicyIds: params.onCallsEscalationPolicyIds,
userIds: params.onCallsUserIds,
serviceIds: params.onCallsServiceIds,
}
case 'rootly_list_schedules':
return {
...baseParams,
search: params.schedulesSearch,
pageSize: params.schedulesPageSize ? Number(params.schedulesPageSize) : undefined,
pageNumber: params.schedulesPageNumber
? Number(params.schedulesPageNumber)
: undefined,
}
case 'rootly_list_escalation_policies':
return {
...baseParams,
search: params.escalationPoliciesSearch,
pageSize: params.escalationPoliciesPageSize
? Number(params.escalationPoliciesPageSize)
: undefined,
pageNumber: params.escalationPoliciesPageNumber
? Number(params.escalationPoliciesPageNumber)
: undefined,
}
case 'rootly_list_causes':
return {
...baseParams,
search: params.causesSearch,
pageSize: params.causesPageSize ? Number(params.causesPageSize) : undefined,
pageNumber: params.causesPageNumber ? Number(params.causesPageNumber) : undefined,
}
case 'rootly_list_playbooks':
return {
...baseParams,
pageSize: params.playbooksPageSize ? Number(params.playbooksPageSize) : undefined,
pageNumber: params.playbooksPageNumber
? Number(params.playbooksPageNumber)
: undefined,
}
default:
return baseParams
}
@@ -1101,6 +1635,58 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
retrospectivesSearch: { type: 'string', description: 'Search retrospectives' },
retrospectivesPageSize: { type: 'string', description: 'Retrospectives page size' },
retrospectivesPageNumber: { type: 'string', description: 'Retrospectives page number' },
deleteIncidentId: { type: 'string', description: 'Incident ID to delete' },
getAlertId: { type: 'string', description: 'Alert ID to retrieve' },
updateAlertId: { type: 'string', description: 'Alert ID to update' },
updateAlertSummary: { type: 'string', description: 'Updated alert summary' },
updateAlertDescription: { type: 'string', description: 'Updated alert description' },
updateAlertSource: { type: 'string', description: 'Updated alert source' },
updateAlertServiceIds: { type: 'string', description: 'Updated alert service IDs' },
updateAlertGroupIds: { type: 'string', description: 'Updated alert team IDs' },
updateAlertEnvironmentIds: { type: 'string', description: 'Updated alert environment IDs' },
updateAlertExternalId: { type: 'string', description: 'Updated external alert ID' },
updateAlertExternalUrl: { type: 'string', description: 'Updated external URL' },
updateAlertDeduplicationKey: { type: 'string', description: 'Updated deduplication key' },
ackAlertId: { type: 'string', description: 'Alert ID to acknowledge' },
resolveAlertId: { type: 'string', description: 'Alert ID to resolve' },
resolveResolutionMessage: { type: 'string', description: 'Resolution message' },
resolveRelatedIncidents: { type: 'string', description: 'Resolve related incidents' },
actionItemIncidentId: { type: 'string', description: 'Incident ID for action item' },
actionItemSummary: { type: 'string', description: 'Action item summary' },
actionItemDescription: { type: 'string', description: 'Action item description' },
actionItemKind: { type: 'string', description: 'Action item kind' },
actionItemPriority: { type: 'string', description: 'Action item priority' },
actionItemStatus: { type: 'string', description: 'Action item status' },
actionItemAssignedToUserId: { type: 'string', description: 'Assigned user ID' },
actionItemDueDate: { type: 'string', description: 'Action item due date' },
listActionItemsIncidentId: { type: 'string', description: 'Incident ID for action items' },
listActionItemsPageSize: { type: 'string', description: 'Action items page size' },
listActionItemsPageNumber: { type: 'string', description: 'Action items page number' },
usersSearch: { type: 'string', description: 'Search users' },
usersEmail: { type: 'string', description: 'Filter users by email' },
usersPageSize: { type: 'string', description: 'Users page size' },
usersPageNumber: { type: 'string', description: 'Users page number' },
onCallsScheduleIds: { type: 'string', description: 'Filter on-calls by schedule IDs' },
onCallsEscalationPolicyIds: {
type: 'string',
description: 'Filter on-calls by escalation policy IDs',
},
onCallsUserIds: { type: 'string', description: 'Filter on-calls by user IDs' },
onCallsServiceIds: { type: 'string', description: 'Filter on-calls by service IDs' },
schedulesSearch: { type: 'string', description: 'Search schedules' },
schedulesPageSize: { type: 'string', description: 'Schedules page size' },
schedulesPageNumber: { type: 'string', description: 'Schedules page number' },
escalationPoliciesSearch: { type: 'string', description: 'Search escalation policies' },
escalationPoliciesPageSize: { type: 'string', description: 'Escalation policies page size' },
escalationPoliciesPageNumber: {
type: 'string',
description: 'Escalation policies page number',
},
causesSearch: { type: 'string', description: 'Search causes' },
causesPageSize: { type: 'string', description: 'Causes page size' },
causesPageNumber: { type: 'string', description: 'Causes page number' },
playbooksPageSize: { type: 'string', description: 'Playbooks page size' },
playbooksPageNumber: { type: 'string', description: 'Playbooks page number' },
},
outputs: {
incident: {
@@ -1150,6 +1736,42 @@ export const RootlyBlock: BlockConfig<RootlyResponse> = {
type: 'json',
description: 'List of retrospectives (id, title, status, url, timestamps)',
},
users: {
type: 'json',
description: 'List of users (id, name, email)',
},
onCalls: {
type: 'json',
description:
'List of on-call entries (userId, userName, scheduleId, scheduleName, escalationPolicyId)',
},
schedules: {
type: 'json',
description: 'List of schedules (id, name, description)',
},
escalationPolicies: {
type: 'json',
description: 'List of escalation policies (id, name, description)',
},
causes: {
type: 'json',
description: 'List of causes (id, name, slug, description)',
},
playbooks: {
type: 'json',
description: 'List of playbooks (id, title, summary)',
},
actionItem: {
type: 'json',
description: 'Action item data (id, summary, description, kind, priority, status, dueDate)',
},
actionItems: {
type: 'json',
description:
'List of action items (id, summary, description, kind, priority, status, dueDate)',
},
success: { type: 'boolean', description: 'Whether the operation succeeded' },
message: { type: 'string', description: 'Operation result message' },
totalCount: { type: 'number', description: 'Total count of items returned' },
},
}
+26
View File
@@ -2009,19 +2009,32 @@ import {
ripplingUpdateWorkLocationTool,
} from '@/tools/rippling'
import {
rootlyAcknowledgeAlertTool,
rootlyAddIncidentEventTool,
rootlyCreateActionItemTool,
rootlyCreateAlertTool,
rootlyCreateIncidentTool,
rootlyDeleteIncidentTool,
rootlyGetAlertTool,
rootlyGetIncidentTool,
rootlyListActionItemsTool,
rootlyListAlertsTool,
rootlyListCausesTool,
rootlyListEnvironmentsTool,
rootlyListEscalationPoliciesTool,
rootlyListFunctionalitiesTool,
rootlyListIncidentsTool,
rootlyListIncidentTypesTool,
rootlyListOnCallsTool,
rootlyListPlaybooksTool,
rootlyListRetrospectivesTool,
rootlyListSchedulesTool,
rootlyListServicesTool,
rootlyListSeveritiesTool,
rootlyListTeamsTool,
rootlyListUsersTool,
rootlyResolveAlertTool,
rootlyUpdateAlertTool,
rootlyUpdateIncidentTool,
} from '@/tools/rootly'
import {
@@ -3834,19 +3847,32 @@ export const tools: Record<string, ToolConfig> = {
rippling_update_supergroup_inclusion_members: ripplingUpdateSupergroupInclusionMembersTool,
rippling_update_title: ripplingUpdateTitleTool,
rippling_update_work_location: ripplingUpdateWorkLocationTool,
rootly_acknowledge_alert: rootlyAcknowledgeAlertTool,
rootly_add_incident_event: rootlyAddIncidentEventTool,
rootly_create_action_item: rootlyCreateActionItemTool,
rootly_create_alert: rootlyCreateAlertTool,
rootly_create_incident: rootlyCreateIncidentTool,
rootly_delete_incident: rootlyDeleteIncidentTool,
rootly_get_alert: rootlyGetAlertTool,
rootly_get_incident: rootlyGetIncidentTool,
rootly_list_action_items: rootlyListActionItemsTool,
rootly_list_alerts: rootlyListAlertsTool,
rootly_list_causes: rootlyListCausesTool,
rootly_list_environments: rootlyListEnvironmentsTool,
rootly_list_escalation_policies: rootlyListEscalationPoliciesTool,
rootly_list_functionalities: rootlyListFunctionalitiesTool,
rootly_list_incident_types: rootlyListIncidentTypesTool,
rootly_list_incidents: rootlyListIncidentsTool,
rootly_list_on_calls: rootlyListOnCallsTool,
rootly_list_playbooks: rootlyListPlaybooksTool,
rootly_list_retrospectives: rootlyListRetrospectivesTool,
rootly_list_schedules: rootlyListSchedulesTool,
rootly_list_services: rootlyListServicesTool,
rootly_list_severities: rootlyListSeveritiesTool,
rootly_list_teams: rootlyListTeamsTool,
rootly_list_users: rootlyListUsersTool,
rootly_resolve_alert: rootlyResolveAlertTool,
rootly_update_alert: rootlyUpdateAlertTool,
rootly_update_incident: rootlyUpdateIncidentTool,
google_drive_copy: googleDriveCopyTool,
google_drive_create_folder: googleDriveCreateFolderTool,
@@ -0,0 +1,96 @@
import type {
RootlyAcknowledgeAlertParams,
RootlyAcknowledgeAlertResponse,
} from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyAcknowledgeAlertTool: ToolConfig<
RootlyAcknowledgeAlertParams,
RootlyAcknowledgeAlertResponse
> = {
id: 'rootly_acknowledge_alert',
name: 'Rootly Acknowledge Alert',
description: 'Acknowledge an alert in Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
alertId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the alert to acknowledge',
},
},
request: {
url: (params) => `https://api.rootly.com/v1/alerts/${params.alertId.trim()}/acknowledge`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: () => ({ data: {} }),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { alert: {} as RootlyAcknowledgeAlertResponse['output']['alert'] },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const attrs = data.data?.attributes || {}
return {
success: true,
output: {
alert: {
id: data.data?.id ?? null,
shortId: attrs.short_id ?? null,
summary: attrs.summary ?? '',
description: attrs.description ?? null,
source: attrs.source ?? null,
status: attrs.status ?? null,
externalId: attrs.external_id ?? null,
externalUrl: attrs.external_url ?? null,
deduplicationKey: attrs.deduplication_key ?? null,
createdAt: attrs.created_at ?? '',
updatedAt: attrs.updated_at ?? '',
startedAt: attrs.started_at ?? null,
endedAt: attrs.ended_at ?? null,
},
},
}
},
outputs: {
alert: {
type: 'object',
description: 'The acknowledged alert',
properties: {
id: { type: 'string', description: 'Unique alert ID' },
shortId: { type: 'string', description: 'Short alert ID' },
summary: { type: 'string', description: 'Alert summary' },
description: { type: 'string', description: 'Alert description' },
source: { type: 'string', description: 'Alert source' },
status: { type: 'string', description: 'Alert status' },
externalId: { type: 'string', description: 'External ID' },
externalUrl: { type: 'string', description: 'External URL' },
deduplicationKey: { type: 'string', description: 'Deduplication key' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
startedAt: { type: 'string', description: 'Start date' },
endedAt: { type: 'string', description: 'End date' },
},
},
},
}
+144
View File
@@ -0,0 +1,144 @@
import type {
RootlyCreateActionItemParams,
RootlyCreateActionItemResponse,
} from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyCreateActionItemTool: ToolConfig<
RootlyCreateActionItemParams,
RootlyCreateActionItemResponse
> = {
id: 'rootly_create_action_item',
name: 'Rootly Create Action Item',
description: 'Create a new action item for an incident in Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
incidentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the incident to add the action item to',
},
summary: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The title of the action item',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'A detailed description of the action item',
},
kind: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The kind of action item (task, follow_up)',
},
priority: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Priority level (high, medium, low)',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Action item status (open, in_progress, cancelled, done)',
},
assignedToUserId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'The user ID to assign the action item to',
},
dueDate: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Due date for the action item',
},
},
request: {
url: (params) => `https://api.rootly.com/v1/incidents/${params.incidentId.trim()}/action_items`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const attributes: Record<string, unknown> = {
summary: params.summary,
}
if (params.description) attributes.description = params.description
if (params.kind) attributes.kind = params.kind
if (params.priority) attributes.priority = params.priority
if (params.status) attributes.status = params.status
if (params.assignedToUserId) {
const numericId = Number.parseInt(params.assignedToUserId, 10)
if (!Number.isNaN(numericId)) attributes.assigned_to_user_id = numericId
}
if (params.dueDate) attributes.due_date = params.dueDate
return { data: { type: 'incident_action_items', attributes } }
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { actionItem: {} as RootlyCreateActionItemResponse['output']['actionItem'] },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const attrs = data.data?.attributes || {}
return {
success: true,
output: {
actionItem: {
id: data.data?.id ?? null,
summary: attrs.summary ?? '',
description: attrs.description ?? null,
kind: attrs.kind ?? null,
priority: attrs.priority ?? null,
status: attrs.status ?? null,
dueDate: attrs.due_date ?? null,
createdAt: attrs.created_at ?? '',
updatedAt: attrs.updated_at ?? '',
},
},
}
},
outputs: {
actionItem: {
type: 'object',
description: 'The created action item',
properties: {
id: { type: 'string', description: 'Unique action item ID' },
summary: { type: 'string', description: 'Action item title' },
description: { type: 'string', description: 'Action item description' },
kind: { type: 'string', description: 'Action item kind (task, follow_up)' },
priority: { type: 'string', description: 'Priority level' },
status: { type: 'string', description: 'Action item status' },
dueDate: { type: 'string', description: 'Due date' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
}
+6
View File
@@ -124,6 +124,7 @@ export const rootlyCreateAlertTool: ToolConfig<RootlyCreateAlertParams, RootlyCr
output: {
alert: {
id: data.data?.id ?? null,
shortId: attrs.short_id ?? null,
summary: attrs.summary ?? '',
description: attrs.description ?? null,
source: attrs.source ?? null,
@@ -133,6 +134,8 @@ export const rootlyCreateAlertTool: ToolConfig<RootlyCreateAlertParams, RootlyCr
deduplicationKey: attrs.deduplication_key ?? null,
createdAt: attrs.created_at ?? '',
updatedAt: attrs.updated_at ?? '',
startedAt: attrs.started_at ?? null,
endedAt: attrs.ended_at ?? null,
},
},
}
@@ -144,6 +147,7 @@ export const rootlyCreateAlertTool: ToolConfig<RootlyCreateAlertParams, RootlyCr
description: 'The created alert',
properties: {
id: { type: 'string', description: 'Unique alert ID' },
shortId: { type: 'string', description: 'Short alert ID' },
summary: { type: 'string', description: 'Alert summary' },
description: { type: 'string', description: 'Alert description' },
source: { type: 'string', description: 'Alert source' },
@@ -153,6 +157,8 @@ export const rootlyCreateAlertTool: ToolConfig<RootlyCreateAlertParams, RootlyCr
deduplicationKey: { type: 'string', description: 'Deduplication key' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
startedAt: { type: 'string', description: 'Start date' },
endedAt: { type: 'string', description: 'End date' },
},
},
},
+64
View File
@@ -0,0 +1,64 @@
import type { RootlyDeleteIncidentParams, RootlyDeleteIncidentResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyDeleteIncidentTool: ToolConfig<
RootlyDeleteIncidentParams,
RootlyDeleteIncidentResponse
> = {
id: 'rootly_delete_incident',
name: 'Rootly Delete Incident',
description: 'Delete an incident by ID from Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
incidentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the incident to delete',
},
},
request: {
url: (params) => `https://api.rootly.com/v1/incidents/${params.incidentId.trim()}`,
method: 'DELETE',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: {
success: false,
message:
errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
},
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
return {
success: true,
output: {
success: true,
message: 'Incident deleted successfully',
},
}
},
outputs: {
success: { type: 'boolean', description: 'Whether the deletion succeeded' },
message: { type: 'string', description: 'Result message' },
},
}
+89
View File
@@ -0,0 +1,89 @@
import type { RootlyGetAlertParams, RootlyGetAlertResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyGetAlertTool: ToolConfig<RootlyGetAlertParams, RootlyGetAlertResponse> = {
id: 'rootly_get_alert',
name: 'Rootly Get Alert',
description: 'Retrieve a single alert by ID from Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
alertId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the alert to retrieve',
},
},
request: {
url: (params) => `https://api.rootly.com/v1/alerts/${params.alertId.trim()}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { alert: {} as RootlyGetAlertResponse['output']['alert'] },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const attrs = data.data?.attributes || {}
return {
success: true,
output: {
alert: {
id: data.data?.id ?? null,
shortId: attrs.short_id ?? null,
summary: attrs.summary ?? '',
description: attrs.description ?? null,
source: attrs.source ?? null,
status: attrs.status ?? null,
externalId: attrs.external_id ?? null,
externalUrl: attrs.external_url ?? null,
deduplicationKey: attrs.deduplication_key ?? null,
createdAt: attrs.created_at ?? '',
updatedAt: attrs.updated_at ?? '',
startedAt: attrs.started_at ?? null,
endedAt: attrs.ended_at ?? null,
},
},
}
},
outputs: {
alert: {
type: 'object',
description: 'The alert details',
properties: {
id: { type: 'string', description: 'Unique alert ID' },
shortId: { type: 'string', description: 'Short alert ID' },
summary: { type: 'string', description: 'Alert summary' },
description: { type: 'string', description: 'Alert description' },
source: { type: 'string', description: 'Alert source' },
status: { type: 'string', description: 'Alert status' },
externalId: { type: 'string', description: 'External ID' },
externalUrl: { type: 'string', description: 'External URL' },
deduplicationKey: { type: 'string', description: 'Deduplication key' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
startedAt: { type: 'string', description: 'Start date' },
endedAt: { type: 'string', description: 'End date' },
},
},
},
}
+13
View File
@@ -1,15 +1,28 @@
export { rootlyAcknowledgeAlertTool } from '@/tools/rootly/acknowledge_alert'
export { rootlyAddIncidentEventTool } from '@/tools/rootly/add_incident_event'
export { rootlyCreateActionItemTool } from '@/tools/rootly/create_action_item'
export { rootlyCreateAlertTool } from '@/tools/rootly/create_alert'
export { rootlyCreateIncidentTool } from '@/tools/rootly/create_incident'
export { rootlyDeleteIncidentTool } from '@/tools/rootly/delete_incident'
export { rootlyGetAlertTool } from '@/tools/rootly/get_alert'
export { rootlyGetIncidentTool } from '@/tools/rootly/get_incident'
export { rootlyListActionItemsTool } from '@/tools/rootly/list_action_items'
export { rootlyListAlertsTool } from '@/tools/rootly/list_alerts'
export { rootlyListCausesTool } from '@/tools/rootly/list_causes'
export { rootlyListEnvironmentsTool } from '@/tools/rootly/list_environments'
export { rootlyListEscalationPoliciesTool } from '@/tools/rootly/list_escalation_policies'
export { rootlyListFunctionalitiesTool } from '@/tools/rootly/list_functionalities'
export { rootlyListIncidentTypesTool } from '@/tools/rootly/list_incident_types'
export { rootlyListIncidentsTool } from '@/tools/rootly/list_incidents'
export { rootlyListOnCallsTool } from '@/tools/rootly/list_on_calls'
export { rootlyListPlaybooksTool } from '@/tools/rootly/list_playbooks'
export { rootlyListRetrospectivesTool } from '@/tools/rootly/list_retrospectives'
export { rootlyListSchedulesTool } from '@/tools/rootly/list_schedules'
export { rootlyListServicesTool } from '@/tools/rootly/list_services'
export { rootlyListSeveritiesTool } from '@/tools/rootly/list_severities'
export { rootlyListTeamsTool } from '@/tools/rootly/list_teams'
export { rootlyListUsersTool } from '@/tools/rootly/list_users'
export { rootlyResolveAlertTool } from '@/tools/rootly/resolve_alert'
export * from '@/tools/rootly/types'
export { rootlyUpdateAlertTool } from '@/tools/rootly/update_alert'
export { rootlyUpdateIncidentTool } from '@/tools/rootly/update_incident'
+117
View File
@@ -0,0 +1,117 @@
import type {
RootlyListActionItemsParams,
RootlyListActionItemsResponse,
} from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListActionItemsTool: ToolConfig<
RootlyListActionItemsParams,
RootlyListActionItemsResponse
> = {
id: 'rootly_list_action_items',
name: 'Rootly List Action Items',
description: 'List action items for an incident in Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
incidentId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the incident to list action items for',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of items per page (default: 20)',
},
pageNumber: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.pageSize) queryParams.set('page[size]', String(params.pageSize))
if (params.pageNumber) queryParams.set('page[number]', String(params.pageNumber))
const qs = queryParams.toString()
return `https://api.rootly.com/v1/incidents/${params.incidentId.trim()}/action_items${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { actionItems: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const actionItems = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
summary: (attrs.summary as string) ?? '',
description: (attrs.description as string) ?? null,
kind: (attrs.kind as string) ?? null,
priority: (attrs.priority as string) ?? null,
status: (attrs.status as string) ?? null,
dueDate: (attrs.due_date as string) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
}
})
return {
success: true,
output: {
actionItems,
totalCount: data.meta?.total_count ?? actionItems.length,
},
}
},
outputs: {
actionItems: {
type: 'array',
description: 'List of action items',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique action item ID' },
summary: { type: 'string', description: 'Action item title' },
description: { type: 'string', description: 'Action item description' },
kind: { type: 'string', description: 'Action item kind (task, follow_up)' },
priority: { type: 'string', description: 'Priority level' },
status: { type: 'string', description: 'Action item status' },
dueDate: { type: 'string', description: 'Due date' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of action items returned',
},
},
}
+6
View File
@@ -93,6 +93,7 @@ export const rootlyListAlertsTool: ToolConfig<RootlyListAlertsParams, RootlyList
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
shortId: (attrs.short_id as string) ?? null,
summary: (attrs.summary as string) ?? '',
description: (attrs.description as string) ?? null,
source: (attrs.source as string) ?? null,
@@ -102,6 +103,8 @@ export const rootlyListAlertsTool: ToolConfig<RootlyListAlertsParams, RootlyList
deduplicationKey: (attrs.deduplication_key as string) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
startedAt: (attrs.started_at as string) ?? null,
endedAt: (attrs.ended_at as string) ?? null,
}
})
@@ -122,6 +125,7 @@ export const rootlyListAlertsTool: ToolConfig<RootlyListAlertsParams, RootlyList
type: 'object',
properties: {
id: { type: 'string', description: 'Unique alert ID' },
shortId: { type: 'string', description: 'Short alert ID' },
summary: { type: 'string', description: 'Alert summary' },
description: { type: 'string', description: 'Alert description' },
source: { type: 'string', description: 'Alert source' },
@@ -131,6 +135,8 @@ export const rootlyListAlertsTool: ToolConfig<RootlyListAlertsParams, RootlyList
deduplicationKey: { type: 'string', description: 'Deduplication key' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
startedAt: { type: 'string', description: 'Start date' },
endedAt: { type: 'string', description: 'End date' },
},
},
},
+108
View File
@@ -0,0 +1,108 @@
import type { RootlyListCausesParams, RootlyListCausesResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListCausesTool: ToolConfig<RootlyListCausesParams, RootlyListCausesResponse> = {
id: 'rootly_list_causes',
name: 'Rootly List Causes',
description: 'List causes from Rootly with optional search filtering.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter causes',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of items per page (default: 20)',
},
pageNumber: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.search) queryParams.set('filter[search]', params.search)
if (params.pageSize) queryParams.set('page[size]', String(params.pageSize))
if (params.pageNumber) queryParams.set('page[number]', String(params.pageNumber))
const qs = queryParams.toString()
return `https://api.rootly.com/v1/causes${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { causes: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const causes = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
name: (attrs.name as string) ?? '',
slug: (attrs.slug as string) ?? null,
description: (attrs.description as string) ?? null,
position: (attrs.position as number) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
}
})
return {
success: true,
output: {
causes,
totalCount: data.meta?.total_count ?? causes.length,
},
}
},
outputs: {
causes: {
type: 'array',
description: 'List of causes',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique cause ID' },
name: { type: 'string', description: 'Cause name' },
slug: { type: 'string', description: 'Cause slug' },
description: { type: 'string', description: 'Cause description' },
position: { type: 'number', description: 'Cause position' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of causes returned',
},
},
}
@@ -0,0 +1,116 @@
import type {
RootlyListEscalationPoliciesParams,
RootlyListEscalationPoliciesResponse,
} from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListEscalationPoliciesTool: ToolConfig<
RootlyListEscalationPoliciesParams,
RootlyListEscalationPoliciesResponse
> = {
id: 'rootly_list_escalation_policies',
name: 'Rootly List Escalation Policies',
description: 'List escalation policies from Rootly with optional search filtering.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter escalation policies',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of items per page (default: 20)',
},
pageNumber: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.search) queryParams.set('filter[search]', params.search)
if (params.pageSize) queryParams.set('page[size]', String(params.pageSize))
if (params.pageNumber) queryParams.set('page[number]', String(params.pageNumber))
const qs = queryParams.toString()
return `https://api.rootly.com/v1/escalation_policies${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { escalationPolicies: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const escalationPolicies = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
name: (attrs.name as string) ?? '',
description: (attrs.description as string) ?? null,
repeatCount: (attrs.repeat_count as number) ?? null,
groupIds: (attrs.group_ids as string[]) ?? null,
serviceIds: (attrs.service_ids as string[]) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
}
})
return {
success: true,
output: {
escalationPolicies,
totalCount: data.meta?.total_count ?? escalationPolicies.length,
},
}
},
outputs: {
escalationPolicies: {
type: 'array',
description: 'List of escalation policies',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique escalation policy ID' },
name: { type: 'string', description: 'Escalation policy name' },
description: { type: 'string', description: 'Escalation policy description' },
repeatCount: { type: 'number', description: 'Number of times to repeat escalation' },
groupIds: { type: 'array', description: 'Associated group IDs' },
serviceIds: { type: 'array', description: 'Associated service IDs' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of escalation policies returned',
},
},
}
+143
View File
@@ -0,0 +1,143 @@
import type { RootlyListOnCallsParams, RootlyListOnCallsResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListOnCallsTool: ToolConfig<RootlyListOnCallsParams, RootlyListOnCallsResponse> =
{
id: 'rootly_list_on_calls',
name: 'Rootly List On-Calls',
description: 'List current on-call entries from Rootly with optional filtering.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
scheduleIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated schedule IDs to filter by',
},
escalationPolicyIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated escalation policy IDs to filter by',
},
userIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated user IDs to filter by',
},
serviceIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated service IDs to filter by',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.scheduleIds) queryParams.set('filter[schedule_ids]', params.scheduleIds)
if (params.escalationPolicyIds)
queryParams.set('filter[escalation_policy_ids]', params.escalationPolicyIds)
if (params.userIds) queryParams.set('filter[user_ids]', params.userIds)
if (params.serviceIds) queryParams.set('filter[service_ids]', params.serviceIds)
queryParams.set('include', 'user,schedule,escalation_policy')
return `https://api.rootly.com/v1/oncalls?${queryParams.toString()}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { onCalls: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const included = (data.included || []) as Record<string, unknown>[]
const findIncluded = (
type: string,
id: string | null
): Record<string, unknown> | undefined =>
id ? included.find((i) => i.type === type && i.id === id) : undefined
const onCalls = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
const rels = (item.relationships || {}) as Record<string, Record<string, unknown>>
const userId = ((rels.user?.data as Record<string, unknown>)?.id as string) ?? null
const scheduleId = ((rels.schedule?.data as Record<string, unknown>)?.id as string) ?? null
const escalationPolicyId =
((rels.escalation_policy?.data as Record<string, unknown>)?.id as string) ?? null
const userIncl = findIncluded('users', userId)
const scheduleIncl = findIncluded('schedules', scheduleId)
return {
id: (item.id as string) ?? null,
userId,
userName: userIncl
? (((userIncl.attributes as Record<string, unknown>)?.full_name as string) ?? null)
: null,
scheduleId,
scheduleName: scheduleIncl
? (((scheduleIncl.attributes as Record<string, unknown>)?.name as string) ?? null)
: null,
escalationPolicyId,
startTime: (attrs.start_time as string) ?? null,
endTime: (attrs.end_time as string) ?? null,
}
})
return {
success: true,
output: {
onCalls,
totalCount: data.meta?.total_count ?? onCalls.length,
},
}
},
outputs: {
onCalls: {
type: 'array',
description: 'List of on-call entries',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique on-call entry ID' },
userId: { type: 'string', description: 'ID of the on-call user' },
userName: { type: 'string', description: 'Name of the on-call user' },
scheduleId: { type: 'string', description: 'ID of the associated schedule' },
scheduleName: { type: 'string', description: 'Name of the associated schedule' },
escalationPolicyId: {
type: 'string',
description: 'ID of the associated escalation policy',
},
startTime: { type: 'string', description: 'On-call start time' },
endTime: { type: 'string', description: 'On-call end time' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of on-call entries returned',
},
},
}
+102
View File
@@ -0,0 +1,102 @@
import type { RootlyListPlaybooksParams, RootlyListPlaybooksResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListPlaybooksTool: ToolConfig<
RootlyListPlaybooksParams,
RootlyListPlaybooksResponse
> = {
id: 'rootly_list_playbooks',
name: 'Rootly List Playbooks',
description: 'List playbooks from Rootly with pagination support.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of items per page (default: 20)',
},
pageNumber: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.pageSize) queryParams.set('page[size]', String(params.pageSize))
if (params.pageNumber) queryParams.set('page[number]', String(params.pageNumber))
const qs = queryParams.toString()
return `https://api.rootly.com/v1/playbooks${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { playbooks: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const playbooks = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
title: (attrs.title as string) ?? '',
summary: (attrs.summary as string) ?? null,
externalUrl: (attrs.external_url as string) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
}
})
return {
success: true,
output: {
playbooks,
totalCount: data.meta?.total_count ?? playbooks.length,
},
}
},
outputs: {
playbooks: {
type: 'array',
description: 'List of playbooks',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique playbook ID' },
title: { type: 'string', description: 'Playbook title' },
summary: { type: 'string', description: 'Playbook summary' },
externalUrl: { type: 'string', description: 'External URL' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of playbooks returned',
},
},
}
+112
View File
@@ -0,0 +1,112 @@
import type { RootlyListSchedulesParams, RootlyListSchedulesResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListSchedulesTool: ToolConfig<
RootlyListSchedulesParams,
RootlyListSchedulesResponse
> = {
id: 'rootly_list_schedules',
name: 'Rootly List Schedules',
description: 'List on-call schedules from Rootly with optional search filtering.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter schedules',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of items per page (default: 20)',
},
pageNumber: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.search) queryParams.set('filter[search]', params.search)
if (params.pageSize) queryParams.set('page[size]', String(params.pageSize))
if (params.pageNumber) queryParams.set('page[number]', String(params.pageNumber))
const qs = queryParams.toString()
return `https://api.rootly.com/v1/schedules${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { schedules: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const schedules = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
name: (attrs.name as string) ?? '',
description: (attrs.description as string) ?? null,
allTimeCoverage: (attrs.all_time_coverage as boolean) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
}
})
return {
success: true,
output: {
schedules,
totalCount: data.meta?.total_count ?? schedules.length,
},
}
},
outputs: {
schedules: {
type: 'array',
description: 'List of schedules',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique schedule ID' },
name: { type: 'string', description: 'Schedule name' },
description: { type: 'string', description: 'Schedule description' },
allTimeCoverage: {
type: 'boolean',
description: 'Whether schedule provides 24/7 coverage',
},
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of schedules returned',
},
},
}
+117
View File
@@ -0,0 +1,117 @@
import type { RootlyListUsersParams, RootlyListUsersResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyListUsersTool: ToolConfig<RootlyListUsersParams, RootlyListUsersResponse> = {
id: 'rootly_list_users',
name: 'Rootly List Users',
description: 'List users from Rootly with optional search and email filtering.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
search: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Search term to filter users',
},
email: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter users by email address',
},
pageSize: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of items per page (default: 20)',
},
pageNumber: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Page number for pagination',
},
},
request: {
url: (params) => {
const queryParams = new URLSearchParams()
if (params.search) queryParams.set('filter[search]', params.search)
if (params.email) queryParams.set('filter[email]', params.email)
if (params.pageSize) queryParams.set('page[size]', String(params.pageSize))
if (params.pageNumber) queryParams.set('page[number]', String(params.pageNumber))
const qs = queryParams.toString()
return `https://api.rootly.com/v1/users${qs ? `?${qs}` : ''}`
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { users: [], totalCount: 0 },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const users = (data.data || []).map((item: Record<string, unknown>) => {
const attrs = (item.attributes || {}) as Record<string, unknown>
return {
id: item.id ?? null,
email: (attrs.email as string) ?? '',
firstName: (attrs.first_name as string) ?? null,
lastName: (attrs.last_name as string) ?? null,
fullName: (attrs.full_name as string) ?? null,
timeZone: (attrs.time_zone as string) ?? null,
createdAt: (attrs.created_at as string) ?? '',
updatedAt: (attrs.updated_at as string) ?? '',
}
})
return {
success: true,
output: {
users,
totalCount: data.meta?.total_count ?? users.length,
},
}
},
outputs: {
users: {
type: 'array',
description: 'List of users',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Unique user ID' },
email: { type: 'string', description: 'User email address' },
firstName: { type: 'string', description: 'User first name' },
lastName: { type: 'string', description: 'User last name' },
fullName: { type: 'string', description: 'User full name' },
timeZone: { type: 'string', description: 'User time zone' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
},
},
},
totalCount: {
type: 'number',
description: 'Total number of users returned',
},
},
}
+112
View File
@@ -0,0 +1,112 @@
import type { RootlyResolveAlertParams, RootlyResolveAlertResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyResolveAlertTool: ToolConfig<
RootlyResolveAlertParams,
RootlyResolveAlertResponse
> = {
id: 'rootly_resolve_alert',
name: 'Rootly Resolve Alert',
description: 'Resolve an alert in Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
alertId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the alert to resolve',
},
resolutionMessage: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Message describing how the alert was resolved',
},
resolveRelatedIncidents: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Whether to also resolve related incidents',
},
},
request: {
url: (params) => `https://api.rootly.com/v1/alerts/${params.alertId.trim()}/resolve`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const attributes: Record<string, unknown> = {}
if (params.resolutionMessage) attributes.resolution_message = params.resolutionMessage
if (params.resolveRelatedIncidents !== undefined)
attributes.resolve_related_incidents = params.resolveRelatedIncidents
if (Object.keys(attributes).length === 0) return { data: {} }
return { data: { type: 'alerts', attributes } }
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { alert: {} as RootlyResolveAlertResponse['output']['alert'] },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const attrs = data.data?.attributes || {}
return {
success: true,
output: {
alert: {
id: data.data?.id ?? null,
shortId: attrs.short_id ?? null,
summary: attrs.summary ?? '',
description: attrs.description ?? null,
source: attrs.source ?? null,
status: attrs.status ?? null,
externalId: attrs.external_id ?? null,
externalUrl: attrs.external_url ?? null,
deduplicationKey: attrs.deduplication_key ?? null,
createdAt: attrs.created_at ?? '',
updatedAt: attrs.updated_at ?? '',
startedAt: attrs.started_at ?? null,
endedAt: attrs.ended_at ?? null,
},
},
}
},
outputs: {
alert: {
type: 'object',
description: 'The resolved alert',
properties: {
id: { type: 'string', description: 'Unique alert ID' },
shortId: { type: 'string', description: 'Short alert ID' },
summary: { type: 'string', description: 'Alert summary' },
description: { type: 'string', description: 'Alert description' },
source: { type: 'string', description: 'Alert source' },
status: { type: 'string', description: 'Alert status' },
externalId: { type: 'string', description: 'External ID' },
externalUrl: { type: 'string', description: 'External URL' },
deduplicationKey: { type: 'string', description: 'Deduplication key' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
startedAt: { type: 'string', description: 'Start date' },
endedAt: { type: 'string', description: 'End date' },
},
},
},
}
+274
View File
@@ -121,6 +121,7 @@ export interface RootlyCreateAlertParams extends RootlyBaseParams {
export interface RootlyAlertData {
id: string | null
shortId: string | null
summary: string
description: string | null
source: string | null
@@ -130,6 +131,8 @@ export interface RootlyAlertData {
deduplicationKey: string | null
createdAt: string
updatedAt: string
startedAt: string | null
endedAt: string | null
}
export interface RootlyCreateAlertResponse extends ToolResponse {
@@ -323,6 +326,109 @@ export interface RootlyListIncidentTypesResponse extends ToolResponse {
}
}
/** List Causes */
export interface RootlyListCausesParams extends RootlyBaseParams {
search?: string
pageSize?: number
pageNumber?: number
}
export interface RootlyCauseData {
id: string | null
name: string
slug: string | null
description: string | null
position: number | null
createdAt: string
updatedAt: string
}
export interface RootlyListCausesResponse extends ToolResponse {
output: {
causes: RootlyCauseData[]
totalCount: number
}
}
/** List Playbooks */
export interface RootlyListPlaybooksParams extends RootlyBaseParams {
pageSize?: number
pageNumber?: number
}
export interface RootlyPlaybookData {
id: string | null
title: string
summary: string | null
externalUrl: string | null
createdAt: string
updatedAt: string
}
export interface RootlyListPlaybooksResponse extends ToolResponse {
output: {
playbooks: RootlyPlaybookData[]
totalCount: number
}
}
/** Delete Incident */
export interface RootlyDeleteIncidentParams extends RootlyBaseParams {
incidentId: string
}
export interface RootlyDeleteIncidentResponse extends ToolResponse {
output: {
success: boolean
message: string
}
}
/** Action Item Data */
export interface RootlyActionItemData {
id: string | null
summary: string
description: string | null
kind: string | null
priority: string | null
status: string | null
dueDate: string | null
createdAt: string
updatedAt: string
}
/** Create Action Item */
export interface RootlyCreateActionItemParams extends RootlyBaseParams {
incidentId: string
summary: string
description?: string
kind?: string
priority?: string
status?: string
assignedToUserId?: string
dueDate?: string
}
export interface RootlyCreateActionItemResponse extends ToolResponse {
output: {
actionItem: RootlyActionItemData
}
}
/** List Action Items */
export interface RootlyListActionItemsParams extends RootlyBaseParams {
incidentId: string
pageSize?: number
pageNumber?: number
}
export interface RootlyListActionItemsResponse extends ToolResponse {
output: {
actionItems: RootlyActionItemData[]
totalCount: number
}
}
/** List Functionalities */
export interface RootlyListFunctionalitiesParams extends RootlyBaseParams {
search?: string
@@ -347,15 +453,177 @@ export interface RootlyListFunctionalitiesResponse extends ToolResponse {
}
}
/** Get Alert */
export interface RootlyGetAlertParams extends RootlyBaseParams {
alertId: string
}
export interface RootlyGetAlertResponse extends ToolResponse {
output: {
alert: RootlyAlertData
}
}
/** Update Alert */
export interface RootlyUpdateAlertParams extends RootlyBaseParams {
alertId: string
summary?: string
description?: string
source?: string
serviceIds?: string
groupIds?: string
environmentIds?: string
externalId?: string
externalUrl?: string
deduplicationKey?: string
}
export interface RootlyUpdateAlertResponse extends ToolResponse {
output: {
alert: RootlyAlertData
}
}
/** Acknowledge Alert */
export interface RootlyAcknowledgeAlertParams extends RootlyBaseParams {
alertId: string
}
export interface RootlyAcknowledgeAlertResponse extends ToolResponse {
output: {
alert: RootlyAlertData
}
}
/** Resolve Alert */
export interface RootlyResolveAlertParams extends RootlyBaseParams {
alertId: string
resolutionMessage?: string
resolveRelatedIncidents?: boolean
}
export interface RootlyResolveAlertResponse extends ToolResponse {
output: {
alert: RootlyAlertData
}
}
/** List Users */
export interface RootlyListUsersParams extends RootlyBaseParams {
search?: string
email?: string
pageSize?: number
pageNumber?: number
}
export interface RootlyUserData {
id: string | null
email: string
firstName: string | null
lastName: string | null
fullName: string | null
timeZone: string | null
createdAt: string
updatedAt: string
}
export interface RootlyListUsersResponse extends ToolResponse {
output: {
users: RootlyUserData[]
totalCount: number
}
}
/** List On-Calls */
export interface RootlyListOnCallsParams extends RootlyBaseParams {
scheduleIds?: string
escalationPolicyIds?: string
userIds?: string
serviceIds?: string
}
export interface RootlyOnCallData {
id: string | null
userId: string | null
userName: string | null
scheduleId: string | null
scheduleName: string | null
escalationPolicyId: string | null
startTime: string | null
endTime: string | null
}
export interface RootlyListOnCallsResponse extends ToolResponse {
output: {
onCalls: RootlyOnCallData[]
totalCount: number
}
}
/** List Schedules */
export interface RootlyListSchedulesParams extends RootlyBaseParams {
search?: string
pageSize?: number
pageNumber?: number
}
export interface RootlyScheduleData {
id: string | null
name: string
description: string | null
allTimeCoverage: boolean | null
createdAt: string
updatedAt: string
}
export interface RootlyListSchedulesResponse extends ToolResponse {
output: {
schedules: RootlyScheduleData[]
totalCount: number
}
}
/** List Escalation Policies */
export interface RootlyListEscalationPoliciesParams extends RootlyBaseParams {
search?: string
pageSize?: number
pageNumber?: number
}
export interface RootlyEscalationPolicyData {
id: string | null
name: string
description: string | null
repeatCount: number | null
groupIds: string[] | null
serviceIds: string[] | null
createdAt: string
updatedAt: string
}
export interface RootlyListEscalationPoliciesResponse extends ToolResponse {
output: {
escalationPolicies: RootlyEscalationPolicyData[]
totalCount: number
}
}
/** Union of all responses */
export type RootlyResponse =
| RootlyCreateIncidentResponse
| RootlyGetIncidentResponse
| RootlyUpdateIncidentResponse
| RootlyDeleteIncidentResponse
| RootlyListIncidentsResponse
| RootlyCreateAlertResponse
| RootlyGetAlertResponse
| RootlyUpdateAlertResponse
| RootlyAcknowledgeAlertResponse
| RootlyResolveAlertResponse
| RootlyListAlertsResponse
| RootlyAddIncidentEventResponse
| RootlyCreateActionItemResponse
| RootlyListActionItemsResponse
| RootlyListServicesResponse
| RootlyListSeveritiesResponse
| RootlyListRetrospectivesResponse
@@ -363,3 +631,9 @@ export type RootlyResponse =
| RootlyListEnvironmentsResponse
| RootlyListIncidentTypesResponse
| RootlyListFunctionalitiesResponse
| RootlyListCausesResponse
| RootlyListPlaybooksResponse
| RootlyListUsersResponse
| RootlyListOnCallsResponse
| RootlyListSchedulesResponse
| RootlyListEscalationPoliciesResponse
+163
View File
@@ -0,0 +1,163 @@
import type { RootlyUpdateAlertParams, RootlyUpdateAlertResponse } from '@/tools/rootly/types'
import type { ToolConfig } from '@/tools/types'
export const rootlyUpdateAlertTool: ToolConfig<RootlyUpdateAlertParams, RootlyUpdateAlertResponse> =
{
id: 'rootly_update_alert',
name: 'Rootly Update Alert',
description: 'Update an existing alert in Rootly.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'Rootly API key',
},
alertId: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the alert to update',
},
summary: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated alert summary',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated alert description',
},
source: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated alert source',
},
serviceIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated service IDs to attach',
},
groupIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated team/group IDs to attach',
},
environmentIds: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated environment IDs to attach',
},
externalId: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated external ID',
},
externalUrl: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated external URL',
},
deduplicationKey: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Updated deduplication key',
},
},
request: {
url: (params) => `https://api.rootly.com/v1/alerts/${params.alertId.trim()}`,
method: 'PATCH',
headers: (params) => ({
'Content-Type': 'application/vnd.api+json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const attributes: Record<string, unknown> = {}
if (params.summary) attributes.summary = params.summary
if (params.description) attributes.description = params.description
if (params.source) attributes.source = params.source
if (params.externalId) attributes.external_id = params.externalId
if (params.externalUrl) attributes.external_url = params.externalUrl
if (params.deduplicationKey) attributes.deduplication_key = params.deduplicationKey
if (params.serviceIds) {
attributes.service_ids = params.serviceIds.split(',').map((s: string) => s.trim())
}
if (params.groupIds) {
attributes.group_ids = params.groupIds.split(',').map((s: string) => s.trim())
}
if (params.environmentIds) {
attributes.environment_ids = params.environmentIds.split(',').map((s: string) => s.trim())
}
return { data: { type: 'alerts', id: params.alertId.trim(), attributes } }
},
},
transformResponse: async (response: Response) => {
if (!response.ok) {
const errorData = await response.json().catch(() => ({}))
return {
success: false,
output: { alert: {} as RootlyUpdateAlertResponse['output']['alert'] },
error: errorData.errors?.[0]?.detail || `HTTP ${response.status}: ${response.statusText}`,
}
}
const data = await response.json()
const attrs = data.data?.attributes || {}
return {
success: true,
output: {
alert: {
id: data.data?.id ?? null,
shortId: attrs.short_id ?? null,
summary: attrs.summary ?? '',
description: attrs.description ?? null,
source: attrs.source ?? null,
status: attrs.status ?? null,
externalId: attrs.external_id ?? null,
externalUrl: attrs.external_url ?? null,
deduplicationKey: attrs.deduplication_key ?? null,
createdAt: attrs.created_at ?? '',
updatedAt: attrs.updated_at ?? '',
startedAt: attrs.started_at ?? null,
endedAt: attrs.ended_at ?? null,
},
},
}
},
outputs: {
alert: {
type: 'object',
description: 'The updated alert',
properties: {
id: { type: 'string', description: 'Unique alert ID' },
shortId: { type: 'string', description: 'Short alert ID' },
summary: { type: 'string', description: 'Alert summary' },
description: { type: 'string', description: 'Alert description' },
source: { type: 'string', description: 'Alert source' },
status: { type: 'string', description: 'Alert status' },
externalId: { type: 'string', description: 'External ID' },
externalUrl: { type: 'string', description: 'External URL' },
deduplicationKey: { type: 'string', description: 'Deduplication key' },
createdAt: { type: 'string', description: 'Creation date' },
updatedAt: { type: 'string', description: 'Last update date' },
startedAt: { type: 'string', description: 'Start date' },
endedAt: { type: 'string', description: 'End date' },
},
},
},
}