feat(incidentio): add on-call, alert, catalog, and team tools (#6529)

* feat(incidentio): add on-call, alert, catalog, and team tools

Adds 19 tools to the incident.io block, taking it from 46 to 65
operations. Every endpoint, param, and response field is taken from the
official OpenAPI spec at api.incident.io/v1/openapiV3.json.

Who is on call had no reachable answer before: the data lives in
ScheduleV2.current_shifts, and both schedules_list and schedules_show
returned it but never declared it. The new incidentio_on_call_now tool
flattens current and upcoming shifts to one row per person, and the two
existing schedule tools now declare the fields they were already
returning.

Also fixes two pre-existing wiring bugs: the block declared an output
named schedule_override while the tool emits override, and the on-call
handoff skill described a lookup the integration could not perform.

* fix(incidentio): stop the alert filter sentinel reaching the API

The has_notes and include_maintenance_window dropdowns default to the
string "any", meaning "do not filter". The params transform skipped the
key in that case, but the executor merges its output over the raw inputs
(`{ ...inputs, ...transformedParams }`), so the sentinel survived and the
tool sent has_notes[is]=any, which incident.io rejects.

The transform now always assigns the key, mapping "any" to undefined so
it overwrites the sentinel instead of leaving it in place. The tool also
only serializes these filters when it actually has a boolean.

Adds tests covering the sentinel, both real boolean values, and the
documented bracket-operator filter syntax.
This commit is contained in:
Waleed
2026-08-10 22:02:50 -07:00
committed by GitHub
parent 1a39e29cfe
commit a64ce49af9
31 changed files with 4454 additions and 18 deletions
@@ -643,6 +643,22 @@ List all schedules in incident.io
| ↳ `timezone` | string | The schedule timezone |
| ↳ `created_at` | string | When the schedule was created |
| ↳ `updated_at` | string | When the schedule was last updated |
| ↳ `current_shifts` | array | Shifts that are ongoing right now, naming who is on call |
| ↳ `start_at` | string | When the shift starts |
| ↳ `end_at` | string | When the shift ends |
| ↳ `entry_id` | string | Schedule entry ID |
| ↳ `rotation_id` | string | Rotation ID |
| ↳ `layer_id` | string | Layer ID |
| ↳ `user` | object | The on-call user |
| ↳ `next_shifts` | array | Shifts that take over at the next changeover. Only returned when the page size is 25 or lower |
| ↳ `start_at` | string | When the shift starts |
| ↳ `end_at` | string | When the shift ends |
| ↳ `entry_id` | string | Schedule entry ID |
| ↳ `rotation_id` | string | Rotation ID |
| ↳ `layer_id` | string | Layer ID |
| ↳ `user` | object | The on-call user |
| ↳ `permalink` | string | Link to the schedule in the incident.io dashboard |
| ↳ `team_ids` | array | IDs of teams that own this schedule |
| `pagination_meta` | object | Pagination metadata |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
@@ -692,6 +708,22 @@ Get details of a specific schedule in incident.io
| ↳ `timezone` | string | The schedule timezone |
| ↳ `created_at` | string | When the schedule was created |
| ↳ `updated_at` | string | When the schedule was last updated |
| ↳ `current_shifts` | array | Shifts that are ongoing right now, naming who is on call |
| ↳ `start_at` | string | When the shift starts |
| ↳ `end_at` | string | When the shift ends |
| ↳ `entry_id` | string | Schedule entry ID |
| ↳ `rotation_id` | string | Rotation ID |
| ↳ `layer_id` | string | Layer ID |
| ↳ `user` | object | The on-call user |
| ↳ `next_shifts` | array | Shifts that take over at the next changeover. Only returned when the page size is 25 or lower |
| ↳ `start_at` | string | When the shift starts |
| ↳ `end_at` | string | When the shift ends |
| ↳ `entry_id` | string | Schedule entry ID |
| ↳ `rotation_id` | string | Rotation ID |
| ↳ `layer_id` | string | Layer ID |
| ↳ `user` | object | The on-call user |
| ↳ `permalink` | string | Link to the schedule in the incident.io dashboard |
| ↳ `team_ids` | array | IDs of teams that own this schedule |
### Update Schedule
@@ -1387,6 +1419,614 @@ Delete an escalation path in incident.io
| --------- | ---- | ----------- |
| `message` | string | Success message |
### Get Who Is On Call
Get who is currently on call in incident.io, as one row per ongoing shift across every schedule (or a single schedule). Also returns the shifts that take over at the next changeover.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `schedule_id` | string | No | Limit the result to a single schedule by ID \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\). Leave empty to return who is on call across every schedule. |
| `page_size` | number | No | Number of schedules to scan per page when no schedule ID is given \(e.g., 10, 25\). Defaults to 25; upcoming shifts are only returned at 25 or lower. |
| `after` | string | No | Pagination cursor to fetch the next page of schedules \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `on_call` | array | Shifts that are ongoing right now, one row per on-call person per schedule |
| `next_on_call` | array | Shifts that take over at the next changeover. Only populated when the page size is 25 or lower |
| `pagination_meta` | object | Pagination metadata, returned when scanning every schedule |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
| ↳ `total_record_count` | number | Total number of schedules |
### List Schedule Overrides
List the one-off overrides layered on top of a schedule in incident.io, such as someone covering a colleague’s shift
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `schedule_id` | string | Yes | The ID of the schedule to get overrides for \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `rotation_id` | string | No | Only return overrides on this rotation |
| `layer_id` | string | No | Only return overrides on this layer |
| `page_size` | number | No | Number of results per page \(e.g., 10, 25, 50\) |
| `after` | string | No | Pagination cursor to fetch the next page of results \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `overrides` | array | List of schedule overrides |
| ↳ `id` | string | Override ID |
| ↳ `schedule_id` | string | Schedule the override applies to |
| ↳ `rotation_id` | string | Rotation the override applies to |
| ↳ `layer_id` | string | Layer the override applies to |
| ↳ `start_at` | string | Start of the override |
| ↳ `end_at` | string | End of the override |
| ↳ `created_at` | string | When the override was created |
| ↳ `updated_at` | string | When the override was last updated |
| ↳ `user` | object | The user covering the override |
| ↳ `id` | string | User ID |
| ↳ `name` | string | User display name |
| ↳ `email` | string | User email address |
| ↳ `role` | string | User role |
| ↳ `slack_user_id` | string | Slack user ID |
| `pagination_meta` | object | Pagination metadata |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
### List Alerts
List alerts in incident.io, optionally filtered by status, source, or created date
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `page_size` | number | No | Number of results per page \(e.g., 10, 25, 50\). Default: 25 |
| `after` | string | No | Pagination cursor to fetch the next page of results \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `status` | string | No | Filter by alert status: "firing" or "resolved" |
| `status_operator` | string | No | How to apply the status filter: "one_of" to match it, "not_in" to exclude it. Default: one_of |
| `alert_source_id` | string | No | Filter by alert source ID \(e.g., "01GBSQF3FHF7FWZQNWGHAVQ804"\) |
| `alert_source_operator` | string | No | How to apply the alert source filter: "one_of" to match it, "not_in" to exclude it. Default: one_of |
| `deduplication_key` | string | No | Filter to the single alert with this deduplication key |
| `created_at_gte` | string | No | Only return alerts created on or after this date \(e.g., "2025-01-01"\) |
| `created_at_lte` | string | No | Only return alerts created on or before this date \(e.g., "2025-02-01"\) |
| `has_notes` | boolean | No | Filter to alerts that do \(true\) or do not \(false\) have notes attached |
| `include_maintenance_window` | boolean | No | Whether to include alerts held by a maintenance window. Defaults to true on the API |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alerts` | array | List of alerts |
| ↳ `id` | string | Alert ID |
| ↳ `title` | string | Alert title, parsed from the alert payload |
| ↳ `status` | string | Alert status \(firing, resolved\) |
| ↳ `alert_source_id` | string | ID of the alert source this alert fired on |
| ↳ `deduplication_key` | string | Key that uniquely references this alert from its source |
| ↳ `description` | string | Alert description |
| ↳ `source_url` | string | Link to the alert in the upstream system |
| ↳ `resolved_at` | string | When this alert was resolved |
| ↳ `created_at` | string | When this alert was created |
| ↳ `updated_at` | string | When this alert was last updated |
| ↳ `alert_group_ids` | array | IDs of every alert group this alert belongs to |
| ↳ `attributes` | array | Attribute values parsed from the alert payload |
| `pagination_meta` | object | Pagination metadata |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
### Show Alert
Get a single alert by ID from incident.io
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `id` | string | Yes | The ID of the alert to fetch \(e.g., "01GW2G3V0S59R238FAHPDS1R66"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alert` | object | The alert details |
| ↳ `id` | string | Alert ID |
| ↳ `title` | string | Alert title, parsed from the alert payload |
| ↳ `status` | string | Alert status \(firing, resolved\) |
| ↳ `alert_source_id` | string | ID of the alert source this alert fired on |
| ↳ `deduplication_key` | string | Key that uniquely references this alert from its source |
| ↳ `description` | string | Alert description |
| ↳ `source_url` | string | Link to the alert in the upstream system |
| ↳ `resolved_at` | string | When this alert was resolved |
| ↳ `created_at` | string | When this alert was created |
| ↳ `updated_at` | string | When this alert was last updated |
| ↳ `alert_group_ids` | array | IDs of every alert group this alert belongs to |
| ↳ `attributes` | array | Attribute values parsed from the alert payload |
### Resolve Alert
Resolve a currently firing alert in incident.io. Resolving an already-resolved alert is a no-op and returns it unchanged.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `id` | string | Yes | The ID of the alert to resolve \(e.g., "01GW2G3V0S59R238FAHPDS1R66"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `alert` | object | The resolved alert |
| ↳ `id` | string | Alert ID |
| ↳ `title` | string | Alert title, parsed from the alert payload |
| ↳ `status` | string | Alert status \(firing, resolved\) |
| ↳ `alert_source_id` | string | ID of the alert source this alert fired on |
| ↳ `deduplication_key` | string | Key that uniquely references this alert from its source |
| ↳ `description` | string | Alert description |
| ↳ `source_url` | string | Link to the alert in the upstream system |
| ↳ `resolved_at` | string | When this alert was resolved |
| ↳ `created_at` | string | When this alert was created |
| ↳ `updated_at` | string | When this alert was last updated |
| ↳ `alert_group_ids` | array | IDs of every alert group this alert belongs to |
| ↳ `attributes` | array | Attribute values parsed from the alert payload |
### Create Alert Event
Fire an alert into incident.io through an HTTP alert source. Send the same deduplication key with status "resolved" to close the alert you opened.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `alert_source_config_id` | string | Yes | The ID of the HTTP alert source config to fire into \(e.g., "01GW2G3V0S59R238FAHPDS1R66"\) |
| `alert_source_token` | string | Yes | The token generated when configuring the HTTP alert source. This is not the incident.io API key. |
| `title` | string | Yes | Title of the alert \(e.g., "Payments service error rate above 5%"\) |
| `status` | string | Yes | Current status of the alert: "firing" or "resolved" |
| `description` | string | No | Detail to add below the title. Supports Markdown. |
| `deduplication_key` | string | No | Key that uniquely identifies this alert. Reuse it to update or resolve the same alert instead of creating a new one. |
| `source_url` | string | No | Link back to the alert in the upstream system |
| `metadata` | string | No | Additional metadata as a JSON object, parsed according to the alert source config \(e.g., \{"service": "payments"\}\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `deduplication_key` | string | The deduplication key the event was processed with |
| `message` | string | Human readable message giving detail about the event |
| `status` | string | Status of the event |
### List Incident Alerts
List the connections between incidents and alerts in incident.io — which alerts triggered an incident, or which incident an alert was attached to
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `page_size` | number | No | Number of results per page \(e.g., 10, 25, 50\). Default: 25 |
| `after` | string | No | Pagination cursor to fetch the next page of results \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `incident_id` | string | No | Only return alerts attached to this incident \(e.g., "01FDAG4SAP5TYPT98WGR2N7W91"\) |
| `alert_id` | string | No | Only return connections for this alert \(e.g., "01GW2G3V0S59R238FAHPDS1R66"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `incident_alerts` | array | List of incident-to-alert connections |
| ↳ `id` | string | ID of this incident alert connection |
| ↳ `alert_route_id` | string | ID of the alert route that created this connection |
| ↳ `alert` | object | The connected alert |
| ↳ `id` | string | Alert ID |
| ↳ `title` | string | Alert title |
| ↳ `status` | string | Alert status \(firing, resolved\) |
| ↳ `alert_source_id` | string | ID of the alert source this alert fired on |
| ↳ `deduplication_key` | string | Key that uniquely references this alert from its source |
| ↳ `description` | string | Alert description |
| ↳ `source_url` | string | Link to the alert in the upstream system |
| ↳ `resolved_at` | string | When this alert was resolved |
| ↳ `created_at` | string | When this alert was created |
| ↳ `updated_at` | string | When this alert was last updated |
| ↳ `incident` | object | The incident the alert is attached to |
| ↳ `id` | string | Incident ID |
| ↳ `name` | string | Incident name |
| ↳ `reference` | string | Incident reference \(e.g., INC-123\) |
| ↳ `external_id` | number | External incident identifier |
| ↳ `status_category` | string | Category of the incident status |
| ↳ `visibility` | string | Incident visibility \(public, private\) |
| ↳ `summary` | string | Incident summary |
| `pagination_meta` | object | Pagination metadata |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
### Cancel Escalation
Cancel an escalation in incident.io. Notifications stop, and the escalation will not advance to further levels or repeat.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `id` | string | Yes | The ID of the escalation to cancel \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `message` | string | Success message |
### List Catalog Types
List all catalog types in incident.io, including those synced from external resources. Use this to find the catalog type ID needed to list entries.
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `catalog_types` | array | List of catalog types |
| ↳ `id` | string | Catalog type ID |
| ↳ `name` | string | Human readable name of this type |
| ↳ `description` | string | Human readable description of this type |
| ↳ `type_name` | string | Type name used when defining attributes \(e.g., Custom\["Service"\]\) |
| ↳ `engine_resource_type` | string | How this resource type is referenced in the incident.io engine |
| ↳ `categories` | array | Categories this type is considered part of |
| ↳ `color` | string | Display color of this type in the dashboard |
| ↳ `icon` | string | Display icon of this type in the dashboard |
| ↳ `ranked` | boolean | Whether entries of this type are ranked |
| ↳ `is_editable` | boolean | Whether this type can be edited \(types synced externally cannot\) |
| ↳ `use_name_as_identifier` | boolean | Whether entries can be referenced by name as well as external ID |
| ↳ `estimated_count` | number | Estimated number of entries for this type |
| ↳ `is_team_type` | boolean | Whether this is the designated team type in team settings |
| ↳ `registry_type` | string | The registry resource this type is synced from, if any |
| ↳ `last_synced_at` | string | When this type was last synced |
| ↳ `owning_team_ids` | array | IDs of the teams that own this catalog type |
| ↳ `schema` | object | Attribute schema for this catalog type |
| ↳ `version` | number | Version number of this schema |
| ↳ `attributes` | array | Attributes of this catalog type |
| ↳ `annotations` | json | Metadata annotations tracked about this type |
| ↳ `created_at` | string | When this type was created |
| ↳ `updated_at` | string | When this type was last updated |
### List Catalog Entries
List the entries of a catalog type in incident.io — for example every service, team, or customer recorded in the catalog
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `catalog_type_id` | string | Yes | The ID of the catalog type to list entries for \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `page_size` | number | No | Number of results per page \(e.g., 10, 25, 50\). Default: 25 |
| `after` | string | No | Pagination cursor to fetch the next page of results \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `identifier` | string | No | Only return entries matching this identifier. Searches by ID, external ID, and alias. |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `catalog_entries` | array | List of catalog entries |
| ↳ `id` | string | Catalog entry ID |
| ↳ `name` | string | Human readable name of this entry |
| ↳ `catalog_type_id` | string | ID of the catalog type |
| ↳ `external_id` | string | Alternative ID for this entry, unique within the type |
| ↳ `aliases` | array | Alternative names this entry can be referenced by |
| ↳ `rank` | number | Ordering rank, used when the type is ranked |
| ↳ `attribute_values` | json | Attribute values of this entry |
| ↳ `archived_at` | string | When this entry was archived |
| ↳ `created_at` | string | When this entry was created |
| ↳ `updated_at` | string | When this entry was last updated |
| `catalog_type` | object | The catalog type these entries belong to |
| ↳ `id` | string | Catalog type ID |
| ↳ `name` | string | Human readable name of this type |
| ↳ `description` | string | Human readable description of this type |
| ↳ `type_name` | string | Type name used when defining attributes \(e.g., Custom\["Service"\]\) |
| ↳ `engine_resource_type` | string | How this resource type is referenced in the incident.io engine |
| ↳ `categories` | array | Categories this type is considered part of |
| ↳ `color` | string | Display color of this type in the dashboard |
| ↳ `icon` | string | Display icon of this type in the dashboard |
| ↳ `ranked` | boolean | Whether entries of this type are ranked |
| ↳ `is_editable` | boolean | Whether this type can be edited \(types synced externally cannot\) |
| ↳ `use_name_as_identifier` | boolean | Whether entries can be referenced by name as well as external ID |
| ↳ `estimated_count` | number | Estimated number of entries for this type |
| ↳ `is_team_type` | boolean | Whether this is the designated team type in team settings |
| ↳ `registry_type` | string | The registry resource this type is synced from, if any |
| ↳ `last_synced_at` | string | When this type was last synced |
| ↳ `owning_team_ids` | array | IDs of the teams that own this catalog type |
| ↳ `schema` | object | Attribute schema for this catalog type |
| ↳ `version` | number | Version number of this schema |
| ↳ `attributes` | array | Attributes of this catalog type |
| ↳ `annotations` | json | Metadata annotations tracked about this type |
| ↳ `created_at` | string | When this type was created |
| ↳ `updated_at` | string | When this type was last updated |
| `pagination_meta` | object | Pagination metadata |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
| ↳ `total_record_count` | number | Total number of entries |
### List Teams
List all teams in the incident.io organisation, along with their members
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `page_size` | number | No | Number of results per page \(e.g., 10, 25, 50\) |
| `after` | string | No | Pagination cursor to fetch the next page of results \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `teams` | array | List of teams |
| ↳ `id` | string | Team ID |
| ↳ `name` | string | Team name |
| ↳ `members` | array | Members of the team |
| ↳ `id` | string | User ID |
| ↳ `name` | string | User display name |
| ↳ `email` | string | User email address |
| ↳ `slack_user_id` | string | Slack user ID |
| ↳ `catalog_entry` | object | The catalog entry backing this team |
| ↳ `id` | string | Catalog entry ID |
| ↳ `name` | string | Catalog entry name |
| ↳ `external_id` | string | Alternative ID for this entry, unique within the type |
| `pagination_meta` | object | Pagination metadata |
| ↳ `after` | string | Cursor for next page |
| ↳ `page_size` | number | Number of results per page |
### Show Team
Get a single team by ID from incident.io, along with its members
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `id` | string | Yes | The ID of the team to fetch \(e.g., "01JPQA75EPNEES4479P16P4XAB"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `team` | object | The team details |
| ↳ `id` | string | Team ID |
| ↳ `name` | string | Team name |
| ↳ `members` | array | Members of the team |
| ↳ `id` | string | User ID |
| ↳ `name` | string | User display name |
| ↳ `email` | string | User email address |
| ↳ `slack_user_id` | string | Slack user ID |
| ↳ `catalog_entry` | object | The catalog entry backing this team |
| ↳ `id` | string | Catalog entry ID |
| ↳ `name` | string | Catalog entry name |
| ↳ `external_id` | string | Alternative ID for this entry, unique within the type |
### Create Follow-up
Create a new follow-up on an incident in incident.io
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `incident_id` | string | Yes | The ID of the incident the follow-up belongs to \(e.g., "01FDAG4SAP5TYPT98WGR2N7W91"\) |
| `title` | string | Yes | Title of the follow-up \(e.g., "Add alerting on connection pool saturation"\) |
| `description` | string | No | Description of the follow-up. Supports Markdown. |
| `assignee_id` | string | No | ID of the user to assign this follow-up to |
| `assignee_team_id` | string | No | ID of the team to assign this follow-up to |
| `follow_up_category_id` | string | No | ID of the category for this follow-up |
| `follow_up_priority_option_id` | string | No | ID of the priority for this follow-up |
| `external_issue_reference_id` | string | No | ID of the external issue this follow-up relates to |
| `labels` | string | No | Comma-separated list of labels \(e.g., "bug,urgent"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `follow_up` | object | The created follow-up |
| ↳ `id` | string | Follow-up ID |
| ↳ `incident_id` | string | ID of the incident the follow-up belongs to |
| ↳ `title` | string | Follow-up title |
| ↳ `status` | string | Follow-up status \(outstanding, completed, deleted, not_doing\) |
| ↳ `description` | string | Follow-up description |
| ↳ `labels` | array | Labels associated with this follow-up |
| ↳ `assignee_team` | object | The team the follow-up is assigned to |
| ↳ `id` | string | Team ID |
| ↳ `name` | string | Team name |
| ↳ `priority` | object | Follow-up priority |
| ↳ `id` | string | Priority ID |
| ↳ `name` | string | Priority name |
| ↳ `rank` | number | Priority rank |
| ↳ `description` | string | Priority description |
| ↳ `creator` | object | Who created the follow-up |
| ↳ `completed_at` | string | When the follow-up was completed |
| ↳ `created_at` | string | When the follow-up was created |
| ↳ `updated_at` | string | When the follow-up was last updated |
### Update Follow-up
Update an existing follow-up in incident.io, for example to mark it completed or reassign it
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `id` | string | Yes | The ID of the follow-up to update \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `title` | string | Yes | Title of the follow-up. This endpoint replaces the title, so always send it. |
| `status` | string | Yes | Status of the follow-up: "outstanding", "completed", or "not_doing". Deleting is not supported here. |
| `description` | string | No | Description of the follow-up. Supports Markdown. |
| `assignee_id` | string | No | ID of the user to assign this follow-up to |
| `assignee_team_id` | string | No | ID of the team to assign this follow-up to |
| `follow_up_category_id` | string | No | ID of the category for this follow-up |
| `follow_up_priority_option_id` | string | No | ID of the priority for this follow-up |
| `labels` | string | No | Comma-separated list of labels \(e.g., "bug,urgent"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `follow_up` | object | The updated follow-up |
| ↳ `id` | string | Follow-up ID |
| ↳ `incident_id` | string | ID of the incident the follow-up belongs to |
| ↳ `title` | string | Follow-up title |
| ↳ `status` | string | Follow-up status \(outstanding, completed, deleted, not_doing\) |
| ↳ `description` | string | Follow-up description |
| ↳ `labels` | array | Labels associated with this follow-up |
| ↳ `assignee_team` | object | The team the follow-up is assigned to |
| ↳ `id` | string | Team ID |
| ↳ `name` | string | Team name |
| ↳ `priority` | object | Follow-up priority |
| ↳ `id` | string | Priority ID |
| ↳ `name` | string | Priority name |
| ↳ `rank` | number | Priority rank |
| ↳ `description` | string | Priority description |
| ↳ `creator` | object | Who created the follow-up |
| ↳ `completed_at` | string | When the follow-up was completed |
| ↳ `created_at` | string | When the follow-up was created |
| ↳ `updated_at` | string | When the follow-up was last updated |
### Create Action
Create a new action on an incident in incident.io
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `incident_id` | string | Yes | The ID of the incident the action belongs to \(e.g., "01FDAG4SAP5TYPT98WGR2N7W91"\) |
| `description` | string | Yes | Description of the action. Supports Markdown. |
| `assignee_id` | string | No | ID of the user to assign this action to |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `action` | object | The created action |
| ↳ `id` | string | Action ID |
| ↳ `incident_id` | string | ID of the incident the action belongs to |
| ↳ `description` | string | Action description |
| ↳ `status` | string | Action status \(outstanding, completed, deleted, not_doing\) |
| ↳ `creator` | object | Who created the action |
| ↳ `completed_at` | string | When the action was completed |
| ↳ `created_at` | string | When the action was created |
| ↳ `updated_at` | string | When the action was last updated |
### Update Action
Update an existing action in incident.io, for example to mark it completed or reassign it
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `id` | string | Yes | The ID of the action to update \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
| `description` | string | Yes | Description of the action. This endpoint replaces the description, so always send it. |
| `status` | string | Yes | Status of the action: "outstanding", "completed", or "not_doing". Deleting is not supported here. |
| `assignee_id` | string | No | ID of the user to assign this action to |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `action` | object | The updated action |
| ↳ `id` | string | Action ID |
| ↳ `incident_id` | string | ID of the incident the action belongs to |
| ↳ `description` | string | Action description |
| ↳ `status` | string | Action status \(outstanding, completed, deleted, not_doing\) |
| ↳ `creator` | object | Who created the action |
| ↳ `completed_at` | string | When the action was completed |
| ↳ `created_at` | string | When the action was created |
| ↳ `updated_at` | string | When the action was last updated |
### List Incident Participants
List the participants of an incident in incident.io, split into those actively helping and those just observing
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `incident_id` | string | Yes | The ID of the incident to find participants of \(e.g., "01FDAG4SAP5TYPT98WGR2N7W91"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `active` | array | Participants who are actively helping with the incident |
| `passive` | array | Participants who are just observing the incident |
### Grant Incident Membership
Make a user a member of a private incident in incident.io
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `incident_id` | string | Yes | The ID of the private incident \(e.g., "01FCNDV6P870EA6S7TK1DSYD5H"\) |
| `user_id` | string | Yes | The ID of the user to grant access to \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `incident_membership` | object | The created incident membership |
| ↳ `id` | string | Incident membership ID |
| ↳ `incident_id` | string | ID of the incident |
| ↳ `created_at` | string | When the membership was created |
| ↳ `updated_at` | string | When the membership was last updated |
| ↳ `user` | object | The user who was granted access |
| ↳ `id` | string | User ID |
| ↳ `name` | string | User display name |
| ↳ `email` | string | User email address |
| ↳ `role` | string | User role |
| ↳ `slack_user_id` | string | Slack user ID |
### Revoke Incident Membership
Revoke a user's membership of a private incident in incident.io
#### Input
| Parameter | Type | Required | Description |
| --------- | ---- | -------- | ----------- |
| `apiKey` | string | Yes | incident.io API Key |
| `incident_id` | string | Yes | The ID of the private incident \(e.g., "01FCNDV6P870EA6S7TK1DSYD5H"\) |
| `user_id` | string | Yes | The ID of the user to revoke access from \(e.g., "01FCNDV6P870EA6S7TK1DSYDG0"\) |
#### Output
| Parameter | Type | Description |
| --------- | ---- | ----------- |
| `message` | string | Success message |
## Triggers
+674 -12
View File
@@ -13,6 +13,19 @@ const OVERRIDE_USER_FIELD = ['user_id', 'user_email', 'user_slack_id'] as const
/** An escalation pages either a path or an explicit user list, never both. */
const ESCALATION_TARGET_FIELD = ['escalation_path_id', 'user_ids'] as const
/**
* Maps an optional-filter dropdown onto a real boolean, or `undefined` for the "Any" sentinel.
*
* The executor merges the transform output over the raw inputs, so a key this returns
* `undefined` for still overwrites the sentinel string rather than letting it reach the tool.
* Skipping the assignment instead would leak `has_notes[is]=any` to the API.
*/
function toTriState(value: unknown): boolean | undefined {
if (value === true || value === 'true') return true
if (value === false || value === 'false') return false
return undefined
}
export const IncidentioBlock: BlockConfig<IncidentioResponse> = {
type: 'incidentio',
name: 'incident.io',
@@ -141,6 +154,63 @@ export const IncidentioBlock: BlockConfig<IncidentioResponse> = {
incidentio_escalation_paths_delete: [
{ text: 'Delete escalation path', field: 'id', core: true },
],
incidentio_on_call_now: [
'Get who is on call',
{ text: 'on schedule', field: 'schedule_id' },
],
incidentio_schedule_overrides_list: [
{ text: 'List overrides on schedule', field: 'schedule_id', core: true },
],
incidentio_alerts_list: [
'List alerts',
{ text: ', with status', field: 'alert_status' },
{ text: ', from source', field: 'alert_source_id' },
],
incidentio_alerts_show: [{ text: 'Fetch alert', field: 'id', core: true }],
incidentio_alerts_resolve: [{ text: 'Resolve alert', field: 'id', core: true }],
incidentio_alert_events_create: [
{ text: 'Fire alert', field: 'alert_title', core: true },
{ text: ', into source', field: 'alert_source_config_id' },
],
incidentio_incident_alerts_list: [
'List incident alerts',
{ text: ', on incident', field: 'incident_id' },
{ text: ', for alert', field: 'alert_id' },
],
incidentio_escalations_cancel: [{ text: 'Cancel escalation', field: 'id', core: true }],
incidentio_catalog_types_list: ['List catalog types'],
incidentio_catalog_entries_list: [
{ text: 'List entries of catalog type', field: 'catalog_type_id', core: true },
],
incidentio_teams_list: ['List teams'],
incidentio_teams_show: [{ text: 'Fetch team', field: 'id', core: true }],
incidentio_follow_ups_create: [
{ text: 'Create follow-up', field: 'follow_up_title', core: true },
{ text: ', on incident', field: 'incident_id' },
],
incidentio_follow_ups_update: [
{ text: 'Update follow-up', field: 'id', core: true },
{ text: ', to status', field: 'item_status' },
],
incidentio_actions_create: [
{ text: 'Create action', field: 'action_description', core: true },
{ text: ', on incident', field: 'incident_id' },
],
incidentio_actions_update: [
{ text: 'Update action', field: 'id', core: true },
{ text: ', to status', field: 'item_status' },
],
incidentio_incident_participants_list: [
{ text: 'List participants of incident', field: 'incident_id', core: true },
],
incidentio_incident_memberships_create: [
{ text: 'Grant', field: 'user_id', core: true },
{ text: 'access to incident', field: 'incident_id', core: true },
],
incidentio_incident_memberships_revoke: [
{ text: 'Revoke', field: 'user_id', core: true },
{ text: 'access to incident', field: 'incident_id', core: true },
],
},
},
},
@@ -220,6 +290,33 @@ export const IncidentioBlock: BlockConfig<IncidentioResponse> = {
{ label: 'Show Escalation Path', id: 'incidentio_escalation_paths_show' },
{ label: 'Update Escalation Path', id: 'incidentio_escalation_paths_update' },
{ label: 'Delete Escalation Path', id: 'incidentio_escalation_paths_delete' },
// On-call
{ label: 'Get Who Is On Call', id: 'incidentio_on_call_now' },
{ label: 'List Schedule Overrides', id: 'incidentio_schedule_overrides_list' },
// Alerts
{ label: 'List Alerts', id: 'incidentio_alerts_list' },
{ label: 'Show Alert', id: 'incidentio_alerts_show' },
{ label: 'Resolve Alert', id: 'incidentio_alerts_resolve' },
{ label: 'Create Alert Event', id: 'incidentio_alert_events_create' },
{ label: 'List Incident Alerts', id: 'incidentio_incident_alerts_list' },
// Escalations
{ label: 'Cancel Escalation', id: 'incidentio_escalations_cancel' },
// Catalog
{ label: 'List Catalog Types', id: 'incidentio_catalog_types_list' },
{ label: 'List Catalog Entries', id: 'incidentio_catalog_entries_list' },
// Teams
{ label: 'List Teams', id: 'incidentio_teams_list' },
{ label: 'Show Team', id: 'incidentio_teams_show' },
// Follow-ups
{ label: 'Create Follow-up', id: 'incidentio_follow_ups_create' },
{ label: 'Update Follow-up', id: 'incidentio_follow_ups_update' },
// Actions
{ label: 'Create Action', id: 'incidentio_actions_create' },
{ label: 'Update Action', id: 'incidentio_actions_update' },
// Incident people
{ label: 'List Incident Participants', id: 'incidentio_incident_participants_list' },
{ label: 'Grant Incident Membership', id: 'incidentio_incident_memberships_create' },
{ label: 'Revoke Incident Membership', id: 'incidentio_incident_memberships_revoke' },
],
value: () => 'incidentio_incidents_list',
},
@@ -238,6 +335,12 @@ export const IncidentioBlock: BlockConfig<IncidentioResponse> = {
'incidentio_escalations_list',
'incidentio_incident_updates_list',
'incidentio_escalation_paths_list',
'incidentio_on_call_now',
'incidentio_schedule_overrides_list',
'incidentio_alerts_list',
'incidentio_incident_alerts_list',
'incidentio_catalog_entries_list',
'incidentio_teams_list',
],
},
mode: 'advanced',
@@ -257,6 +360,12 @@ export const IncidentioBlock: BlockConfig<IncidentioResponse> = {
'incidentio_escalations_list',
'incidentio_incident_updates_list',
'incidentio_escalation_paths_list',
'incidentio_on_call_now',
'incidentio_schedule_overrides_list',
'incidentio_alerts_list',
'incidentio_incident_alerts_list',
'incidentio_catalog_entries_list',
'incidentio_teams_list',
],
},
mode: 'advanced',
@@ -389,6 +498,12 @@ Return ONLY the summary text - no explanations.`,
'incidentio_escalation_paths_show',
'incidentio_escalation_paths_update',
'incidentio_escalation_paths_delete',
'incidentio_alerts_show',
'incidentio_alerts_resolve',
'incidentio_escalations_cancel',
'incidentio_teams_show',
'incidentio_follow_ups_update',
'incidentio_actions_update',
],
},
required: true,
@@ -494,13 +609,29 @@ Return ONLY the title - no explanations.`,
id: 'incident_id',
title: 'Incident ID',
type: 'short-input',
placeholder: 'Filter by incident ID...',
placeholder: 'Enter incident ID...',
condition: {
field: 'operation',
value: [
'incidentio_actions_list',
'incidentio_follow_ups_list',
'incidentio_incident_updates_list',
'incidentio_incident_alerts_list',
'incidentio_incident_participants_list',
'incidentio_incident_memberships_create',
'incidentio_incident_memberships_revoke',
'incidentio_follow_ups_create',
'incidentio_actions_create',
],
},
required: {
field: 'operation',
value: [
'incidentio_incident_participants_list',
'incidentio_incident_memberships_create',
'incidentio_incident_memberships_revoke',
'incidentio_follow_ups_create',
'incidentio_actions_create',
],
},
},
@@ -871,9 +1002,21 @@ Return ONLY the instructions text - no explanations.`,
placeholder: 'Enter schedule ID...',
condition: {
field: 'operation',
value: ['incidentio_schedule_entries_list', 'incidentio_schedule_overrides_create'],
value: [
'incidentio_schedule_entries_list',
'incidentio_schedule_overrides_create',
'incidentio_schedule_overrides_list',
'incidentio_on_call_now',
],
},
required: {
field: 'operation',
value: [
'incidentio_schedule_entries_list',
'incidentio_schedule_overrides_create',
'incidentio_schedule_overrides_list',
],
},
required: true,
},
{
id: 'entry_window_start',
@@ -921,24 +1064,40 @@ Return ONLY the timestamp string - no explanations, no quotes, no extra text.`,
title: 'Rotation ID',
type: 'short-input',
placeholder: 'Enter rotation ID...',
condition: { field: 'operation', value: 'incidentio_schedule_overrides_create' },
required: true,
condition: {
field: 'operation',
value: ['incidentio_schedule_overrides_create', 'incidentio_schedule_overrides_list'],
},
required: { field: 'operation', value: 'incidentio_schedule_overrides_create' },
},
{
id: 'layer_id',
title: 'Layer ID',
type: 'short-input',
placeholder: 'Enter layer ID...',
condition: { field: 'operation', value: 'incidentio_schedule_overrides_create' },
required: true,
condition: {
field: 'operation',
value: ['incidentio_schedule_overrides_create', 'incidentio_schedule_overrides_list'],
},
required: { field: 'operation', value: 'incidentio_schedule_overrides_create' },
},
{
id: 'user_id',
title: 'User ID',
type: 'short-input',
placeholder: 'Enter user ID (provide one of: user_id, user_email, or user_slack_id)...',
condition: { field: 'operation', value: 'incidentio_schedule_overrides_create' },
required: false,
placeholder: 'Enter user ID...',
condition: {
field: 'operation',
value: [
'incidentio_schedule_overrides_create',
'incidentio_incident_memberships_create',
'incidentio_incident_memberships_revoke',
],
},
required: {
field: 'operation',
value: ['incidentio_incident_memberships_create', 'incidentio_incident_memberships_revoke'],
},
},
{
id: 'user_email',
@@ -1058,6 +1217,351 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
generationType: 'json-object',
},
},
// Alerts inputs
{
id: 'alert_status',
title: 'Alert Status',
type: 'dropdown',
options: [
{ label: 'Firing', id: 'firing' },
{ label: 'Resolved', id: 'resolved' },
],
condition: {
field: 'operation',
value: ['incidentio_alerts_list', 'incidentio_alert_events_create'],
},
required: { field: 'operation', value: 'incidentio_alert_events_create' },
},
{
id: 'status_operator',
title: 'Alert Status Match',
type: 'dropdown',
options: [
{ label: 'Is One Of', id: 'one_of' },
{ label: 'Is Not', id: 'not_in' },
],
value: () => 'one_of',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
},
{
id: 'alert_source_id',
title: 'Alert Source ID',
type: 'short-input',
placeholder: 'Filter by alert source ID...',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
},
{
id: 'alert_source_operator',
title: 'Alert Source Match',
type: 'dropdown',
options: [
{ label: 'Is One Of', id: 'one_of' },
{ label: 'Is Not', id: 'not_in' },
],
value: () => 'one_of',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
},
{
id: 'deduplication_key',
title: 'Deduplication Key',
type: 'short-input',
placeholder: 'Reuse this key to update or resolve the same alert...',
condition: {
field: 'operation',
value: ['incidentio_alerts_list', 'incidentio_alert_events_create'],
},
},
{
id: 'created_at_gte',
title: 'Created On Or After',
type: 'short-input',
placeholder: 'YYYY-MM-DD (e.g., 2025-01-01)...',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: `Generate a date based on the user's description.
The date should be in the format: YYYY-MM-DD.
Return ONLY the date string - no explanations, no quotes, no extra text.`,
placeholder: 'Describe the earliest date (e.g., "start of last month")...',
generationType: 'timestamp',
},
},
{
id: 'created_at_lte',
title: 'Created On Or Before',
type: 'short-input',
placeholder: 'YYYY-MM-DD (e.g., 2025-02-01)...',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: `Generate a date based on the user's description.
The date should be in the format: YYYY-MM-DD.
Return ONLY the date string - no explanations, no quotes, no extra text.`,
placeholder: 'Describe the latest date (e.g., "end of last month")...',
generationType: 'timestamp',
},
},
{
id: 'has_notes',
title: 'Has Notes',
type: 'dropdown',
options: [
{ label: 'Any', id: 'any' },
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'any',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
},
{
id: 'include_maintenance_window',
title: 'Include Maintenance Window Alerts',
type: 'dropdown',
options: [
{ label: 'Any', id: 'any' },
{ label: 'Yes', id: 'true' },
{ label: 'No', id: 'false' },
],
value: () => 'any',
condition: { field: 'operation', value: 'incidentio_alerts_list' },
mode: 'advanced',
},
{
id: 'alert_id',
title: 'Alert ID',
type: 'short-input',
placeholder: 'Filter by alert ID...',
condition: { field: 'operation', value: 'incidentio_incident_alerts_list' },
},
{
id: 'alert_source_config_id',
title: 'Alert Source Config ID',
type: 'short-input',
placeholder: 'Enter HTTP alert source config ID...',
condition: { field: 'operation', value: 'incidentio_alert_events_create' },
required: true,
},
{
id: 'alert_source_token',
title: 'Alert Source Token',
type: 'short-input',
placeholder: 'Enter the token from the HTTP alert source setup...',
password: true,
condition: { field: 'operation', value: 'incidentio_alert_events_create' },
required: true,
},
{
id: 'alert_title',
title: 'Alert Title',
type: 'short-input',
placeholder: 'Enter alert title...',
condition: { field: 'operation', value: 'incidentio_alert_events_create' },
required: true,
wandConfig: {
enabled: true,
prompt: `Generate an alert title based on the user's description.
The title should:
- Name the affected system and the symptom
- Be short enough to read in a page notification
Return ONLY the title - no explanations.`,
placeholder: 'Describe the alert (e.g., "checkout latency above 2s")...',
},
},
{
id: 'alert_description',
title: 'Alert Description',
type: 'long-input',
placeholder: 'Enter alert description (supports Markdown)...',
condition: { field: 'operation', value: 'incidentio_alert_events_create' },
},
{
id: 'source_url',
title: 'Source URL',
type: 'short-input',
placeholder: 'Link back to the alert in the upstream system...',
condition: { field: 'operation', value: 'incidentio_alert_events_create' },
mode: 'advanced',
},
{
id: 'metadata',
title: 'Metadata',
type: 'long-input',
placeholder: '{"service": "payments"}',
condition: { field: 'operation', value: 'incidentio_alert_events_create' },
mode: 'advanced',
wandConfig: {
enabled: true,
prompt: `Generate a JSON object of alert metadata based on the user's description.
Return ONLY the JSON object - no explanations, no markdown fences.`,
placeholder:
'Describe the metadata to attach (e.g., "service payments, region eu-west-1")...',
generationType: 'json-object',
},
},
// Catalog inputs
{
id: 'catalog_type_id',
title: 'Catalog Type ID',
type: 'short-input',
placeholder: 'Enter catalog type ID...',
condition: { field: 'operation', value: 'incidentio_catalog_entries_list' },
required: true,
},
{
id: 'identifier',
title: 'Identifier',
type: 'short-input',
placeholder: 'Match entries by ID, external ID, or alias...',
condition: { field: 'operation', value: 'incidentio_catalog_entries_list' },
mode: 'advanced',
},
// Follow-up and Action inputs
{
id: 'follow_up_title',
title: 'Follow-up Title',
type: 'short-input',
placeholder: 'Enter follow-up title...',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_create', 'incidentio_follow_ups_update'],
},
required: true,
wandConfig: {
enabled: true,
prompt: `Generate a follow-up title based on the user's description.
The title should:
- Name the concrete piece of work to be done after the incident
- Start with a verb
Return ONLY the title - no explanations.`,
placeholder:
'Describe the follow-up (e.g., "add alerting on connection pool saturation")...',
},
},
{
id: 'follow_up_description',
title: 'Follow-up Description',
type: 'long-input',
placeholder: 'Enter follow-up description (supports Markdown)...',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_create', 'incidentio_follow_ups_update'],
},
},
{
id: 'action_description',
title: 'Action Description',
type: 'long-input',
placeholder: 'Enter action description (supports Markdown)...',
condition: {
field: 'operation',
value: ['incidentio_actions_create', 'incidentio_actions_update'],
},
required: true,
wandConfig: {
enabled: true,
prompt: `Generate an incident action description based on the user's description.
The description should:
- Name the concrete step someone needs to take during the incident
- Start with a verb
Return ONLY the description - no explanations.`,
placeholder: 'Describe the action (e.g., "fail over the primary database")...',
},
},
{
id: 'item_status',
title: 'Status',
type: 'dropdown',
options: [
{ label: 'Outstanding', id: 'outstanding' },
{ label: 'Completed', id: 'completed' },
{ label: 'Not Doing', id: 'not_doing' },
],
value: () => 'outstanding',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_update', 'incidentio_actions_update'],
},
required: true,
},
{
id: 'assignee_id',
title: 'Assignee ID',
type: 'short-input',
placeholder: 'Enter user ID to assign to...',
condition: {
field: 'operation',
value: [
'incidentio_follow_ups_create',
'incidentio_follow_ups_update',
'incidentio_actions_create',
'incidentio_actions_update',
],
},
},
{
id: 'assignee_team_id',
title: 'Assignee Team ID',
type: 'short-input',
placeholder: 'Enter team ID to assign to...',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_create', 'incidentio_follow_ups_update'],
},
mode: 'advanced',
},
{
id: 'follow_up_category_id',
title: 'Follow-up Category ID',
type: 'short-input',
placeholder: 'Enter follow-up category ID...',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_create', 'incidentio_follow_ups_update'],
},
mode: 'advanced',
},
{
id: 'follow_up_priority_option_id',
title: 'Follow-up Priority ID',
type: 'short-input',
placeholder: 'Enter follow-up priority option ID...',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_create', 'incidentio_follow_ups_update'],
},
mode: 'advanced',
},
{
id: 'external_issue_reference_id',
title: 'External Issue Reference ID',
type: 'short-input',
placeholder: 'Enter external issue ID...',
condition: { field: 'operation', value: 'incidentio_follow_ups_create' },
mode: 'advanced',
},
{
id: 'labels',
title: 'Labels',
type: 'short-input',
placeholder: 'Comma-separated labels (e.g., bug,urgent)...',
condition: {
field: 'operation',
value: ['incidentio_follow_ups_create', 'incidentio_follow_ups_update'],
},
mode: 'advanced',
},
// API Key (common)
{
id: 'apiKey',
@@ -1121,6 +1625,25 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
'incidentio_escalation_paths_show',
'incidentio_escalation_paths_update',
'incidentio_escalation_paths_delete',
'incidentio_on_call_now',
'incidentio_schedule_overrides_list',
'incidentio_alerts_list',
'incidentio_alerts_show',
'incidentio_alerts_resolve',
'incidentio_alert_events_create',
'incidentio_incident_alerts_list',
'incidentio_escalations_cancel',
'incidentio_catalog_types_list',
'incidentio_catalog_entries_list',
'incidentio_teams_list',
'incidentio_teams_show',
'incidentio_follow_ups_create',
'incidentio_follow_ups_update',
'incidentio_actions_create',
'incidentio_actions_update',
'incidentio_incident_participants_list',
'incidentio_incident_memberships_create',
'incidentio_incident_memberships_revoke',
],
config: {
tool: (params) => {
@@ -1217,6 +1740,44 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
return 'incidentio_escalation_paths_update'
case 'incidentio_escalation_paths_delete':
return 'incidentio_escalation_paths_delete'
case 'incidentio_on_call_now':
return 'incidentio_on_call_now'
case 'incidentio_schedule_overrides_list':
return 'incidentio_schedule_overrides_list'
case 'incidentio_alerts_list':
return 'incidentio_alerts_list'
case 'incidentio_alerts_show':
return 'incidentio_alerts_show'
case 'incidentio_alerts_resolve':
return 'incidentio_alerts_resolve'
case 'incidentio_alert_events_create':
return 'incidentio_alert_events_create'
case 'incidentio_incident_alerts_list':
return 'incidentio_incident_alerts_list'
case 'incidentio_escalations_cancel':
return 'incidentio_escalations_cancel'
case 'incidentio_catalog_types_list':
return 'incidentio_catalog_types_list'
case 'incidentio_catalog_entries_list':
return 'incidentio_catalog_entries_list'
case 'incidentio_teams_list':
return 'incidentio_teams_list'
case 'incidentio_teams_show':
return 'incidentio_teams_show'
case 'incidentio_follow_ups_create':
return 'incidentio_follow_ups_create'
case 'incidentio_follow_ups_update':
return 'incidentio_follow_ups_update'
case 'incidentio_actions_create':
return 'incidentio_actions_create'
case 'incidentio_actions_update':
return 'incidentio_actions_update'
case 'incidentio_incident_participants_list':
return 'incidentio_incident_participants_list'
case 'incidentio_incident_memberships_create':
return 'incidentio_incident_memberships_create'
case 'incidentio_incident_memberships_revoke':
return 'incidentio_incident_memberships_revoke'
default:
return 'incidentio_incidents_list'
}
@@ -1241,6 +1802,35 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
if (params.user_email) result.email = params.user_email
if (params.user_slack_id) result.slack_user_id = params.user_slack_id
}
if (params.operation === 'incidentio_alerts_list') {
if (params.alert_status) result.status = params.alert_status
result.has_notes = toTriState(params.has_notes)
result.include_maintenance_window = toTriState(params.include_maintenance_window)
}
if (params.operation === 'incidentio_alert_events_create') {
if (params.alert_status) result.status = params.alert_status
if (params.alert_title) result.title = params.alert_title
if (params.alert_description) result.description = params.alert_description
}
if (
params.operation === 'incidentio_follow_ups_create' ||
params.operation === 'incidentio_follow_ups_update'
) {
if (params.follow_up_title) result.title = params.follow_up_title
if (params.follow_up_description) result.description = params.follow_up_description
}
if (
params.operation === 'incidentio_actions_create' ||
params.operation === 'incidentio_actions_update'
) {
if (params.action_description) result.description = params.action_description
}
if (
params.operation === 'incidentio_follow_ups_update' ||
params.operation === 'incidentio_actions_update'
) {
if (params.item_status) result.status = params.item_status
}
return result
},
},
@@ -1316,6 +1906,43 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
// Escalation Paths fields
path: { type: 'json', description: 'Escalation path configuration' },
working_hours: { type: 'json', description: 'Working hours configuration' },
// Alert fields
alert_id: { type: 'string', description: 'Alert ID' },
alert_status: { type: 'string', description: 'Alert status (firing, resolved)' },
status_operator: { type: 'string', description: 'How to match the alert status filter' },
alert_source_id: { type: 'string', description: 'Alert source ID' },
alert_source_operator: {
type: 'string',
description: 'How to match the alert source filter',
},
deduplication_key: { type: 'string', description: 'Alert deduplication key' },
created_at_gte: { type: 'string', description: 'Earliest alert creation date' },
created_at_lte: { type: 'string', description: 'Latest alert creation date' },
has_notes: { type: 'string', description: 'Whether to filter on alerts having notes' },
include_maintenance_window: {
type: 'string',
description: 'Whether to include alerts held by a maintenance window',
},
alert_source_config_id: { type: 'string', description: 'HTTP alert source config ID' },
alert_source_token: { type: 'string', description: 'HTTP alert source token' },
alert_title: { type: 'string', description: 'Alert title' },
alert_description: { type: 'string', description: 'Alert description' },
source_url: { type: 'string', description: 'Link to the alert in the upstream system' },
metadata: { type: 'string', description: 'Alert metadata JSON' },
// Catalog fields
catalog_type_id: { type: 'string', description: 'Catalog type ID' },
identifier: { type: 'string', description: 'Catalog entry identifier to match' },
// Follow-up and Action fields
follow_up_title: { type: 'string', description: 'Follow-up title' },
follow_up_description: { type: 'string', description: 'Follow-up description' },
action_description: { type: 'string', description: 'Action description' },
item_status: { type: 'string', description: 'Follow-up or action status' },
assignee_id: { type: 'string', description: 'ID of the user to assign to' },
assignee_team_id: { type: 'string', description: 'ID of the team to assign to' },
follow_up_category_id: { type: 'string', description: 'Follow-up category ID' },
follow_up_priority_option_id: { type: 'string', description: 'Follow-up priority option ID' },
external_issue_reference_id: { type: 'string', description: 'External issue reference ID' },
labels: { type: 'string', description: 'Comma-separated follow-up labels' },
},
outputs: {
// Incidents
@@ -1358,10 +1985,32 @@ Return ONLY the JSON array - no explanations or markdown formatting.`,
// Schedule Entries
schedule_entries: { type: 'json', description: 'List of schedule entries' },
// Schedule Overrides
schedule_override: { type: 'json', description: 'Schedule override details' },
override: { type: 'json', description: 'Schedule override details' },
// Escalation Paths
escalation_paths: { type: 'json', description: 'List of escalation paths' },
escalation_path: { type: 'json', description: 'Escalation path details' },
// On-call
on_call: { type: 'json', description: 'Shifts that are ongoing right now' },
next_on_call: { type: 'json', description: 'Shifts that take over at the next changeover' },
// Schedule Overrides
overrides: { type: 'json', description: 'List of schedule overrides' },
// Alerts
alerts: { type: 'json', description: 'List of alerts' },
alert: { type: 'json', description: 'Alert details' },
incident_alerts: { type: 'json', description: 'List of incident-to-alert connections' },
deduplication_key: { type: 'string', description: 'Deduplication key of the alert event' },
status: { type: 'string', description: 'Status of the alert event' },
// Catalog
catalog_types: { type: 'json', description: 'List of catalog types' },
catalog_entries: { type: 'json', description: 'List of catalog entries' },
catalog_type: { type: 'json', description: 'The catalog type the entries belong to' },
// Teams
teams: { type: 'json', description: 'List of teams' },
team: { type: 'json', description: 'Team details' },
// Incident people
active: { type: 'json', description: 'Participants actively helping with the incident' },
passive: { type: 'json', description: 'Participants observing the incident' },
incident_membership: { type: 'json', description: 'Incident membership details' },
// General
message: { type: 'string', description: 'Operation result message' },
pagination_meta: { type: 'json', description: 'Pagination metadata' },
@@ -1460,7 +2109,20 @@ export const IncidentioBlockMeta = {
name: 'on-call-handoff-report',
description: 'Summarize who is on call and recent open incidents for an on-call handoff.',
content:
'# On-Call Handoff Report\n\nBuild a clean handoff so the next on-call engineer knows the state of the world.\n\n## Steps\n1. List current schedules and active escalation paths to determine who is on call.\n2. List recent incidents and filter to those that are open or recently resolved.\n3. For each open incident, capture severity, status, and outstanding follow-ups.\n\n## Output\nReturn a handoff brief: who is on call now, open incidents with severity and status, and follow-ups that still need owners.',
'# On-Call Handoff Report\n\nBuild a clean handoff so the next on-call engineer knows the state of the world.\n\n## Steps\n1. Get who is on call to read the ongoing shifts, and note the shifts that take over at the next changeover.\n2. List schedule overrides so any shift cover is reflected in the handoff.\n3. List recent incidents and filter to those that are open or recently resolved.\n4. For each open incident, capture severity, status, and outstanding follow-ups.\n\n## Output\nReturn a handoff brief: who is on call now and who takes over next, open incidents with severity and status, and follow-ups that still need owners.',
},
{
name: 'triage-firing-alerts',
description:
'Review firing alerts, link them to incidents, and resolve the ones that are stale.',
content:
'# Triage Firing Alerts\n\nWork the firing alert queue so real problems get an incident and noise gets closed out.\n\n## Steps\n1. List alerts filtered to status firing, oldest first, and capture title, source, and when each started.\n2. For each alert, list incident alerts to see whether it is already attached to an incident.\n3. Group the unattached alerts by source and by the attributes they share.\n4. Resolve alerts that are clearly stale or already handled, and flag the rest for an incident.\n\n## Output\nReturn three lists: alerts already attached to an incident, alerts resolved as stale, and alerts that still need a human decision with the reason why.',
},
{
name: 'page-the-on-call-for-a-service',
description: 'Find who is on call for a service and raise an escalation to them.',
content:
'# Page the On-Call for a Service\n\nRoute an urgent problem to whoever is actually holding the pager right now.\n\n## Steps\n1. List catalog entries for the service catalog type to resolve the service and its owning team.\n2. Get who is on call and pick the shift covering that team’s schedule.\n3. List escalation paths and choose the one matching the service, falling back to the on-call user IDs.\n4. Create the escalation with a title naming the service and the symptom, using a unique idempotency key so a retry does not double-page.\n\n## Output\nReturn who was paged, the escalation ID, and the schedule the on-call shift came from. If nobody is on call for that schedule, say so instead of paging a fallback silently.',
},
{
name: 'export-incident-followups',
+78 -2
View File
@@ -1,5 +1,5 @@
{
"updatedAt": "2026-08-09",
"updatedAt": "2026-08-11",
"integrations": [
{
"type": "onepassword",
@@ -9835,9 +9835,85 @@
{
"name": "Delete Escalation Path",
"description": "Delete an escalation path in incident.io"
},
{
"name": "Get Who Is On Call",
"description": "Get who is currently on call in incident.io, as one row per ongoing shift across every schedule (or a single schedule). Also returns the shifts that take over at the next changeover."
},
{
"name": "List Schedule Overrides",
"description": "List the one-off overrides layered on top of a schedule in incident.io, such as someone covering a colleague’s shift"
},
{
"name": "List Alerts",
"description": "List alerts in incident.io, optionally filtered by status, source, or created date"
},
{
"name": "Show Alert",
"description": "Get a single alert by ID from incident.io"
},
{
"name": "Resolve Alert",
"description": "Resolve a currently firing alert in incident.io. Resolving an already-resolved alert is a no-op and returns it unchanged."
},
{
"name": "Create Alert Event",
"description": "Fire an alert into incident.io through an HTTP alert source. Send the same deduplication key with status \"resolved\" to close the alert you opened."
},
{
"name": "List Incident Alerts",
"description": "List the connections between incidents and alerts in incident.io — which alerts triggered an incident, or which incident an alert was attached to"
},
{
"name": "Cancel Escalation",
"description": "Cancel an escalation in incident.io. Notifications stop, and the escalation will not advance to further levels or repeat."
},
{
"name": "List Catalog Types",
"description": "List all catalog types in incident.io, including those synced from external resources. Use this to find the catalog type ID needed to list entries."
},
{
"name": "List Catalog Entries",
"description": "List the entries of a catalog type in incident.io — for example every service, team, or customer recorded in the catalog"
},
{
"name": "List Teams",
"description": "List all teams in the incident.io organisation, along with their members"
},
{
"name": "Show Team",
"description": "Get a single team by ID from incident.io, along with its members"
},
{
"name": "Create Follow-up",
"description": "Create a new follow-up on an incident in incident.io"
},
{
"name": "Update Follow-up",
"description": "Update an existing follow-up in incident.io, for example to mark it completed or reassign it"
},
{
"name": "Create Action",
"description": "Create a new action on an incident in incident.io"
},
{
"name": "Update Action",
"description": "Update an existing action in incident.io, for example to mark it completed or reassign it"
},
{
"name": "List Incident Participants",
"description": "List the participants of an incident in incident.io, split into those actively helping and those just observing"
},
{
"name": "Grant Incident Membership",
"description": "Make a user a member of a private incident in incident.io"
},
{
"name": "Revoke Incident Membership",
"description": "Revoke a user's membership of a private incident in incident.io"
}
],
"operationCount": 46,
"operationCount": 65,
"triggers": [
{
"id": "incidentio_incident_created",
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,82 @@
import {
INCIDENTIO_ACTION_RECORD_OUTPUT_PROPERTIES,
type IncidentioActionsCreateParams,
type IncidentioActionsCreateResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const actionsCreateTool: ToolConfig<
IncidentioActionsCreateParams,
IncidentioActionsCreateResponse
> = {
id: 'incidentio_actions_create',
name: 'Create Action',
description: 'Create a new action on an incident in incident.io',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
incident_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The ID of the incident the action belongs to (e.g., "01FDAG4SAP5TYPT98WGR2N7W91")',
},
description: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Description of the action. Supports Markdown.',
},
assignee_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the user to assign this action to',
},
},
request: {
url: 'https://api.incident.io/v2/actions',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, unknown> = {
incident_id: params.incident_id.trim(),
description: params.description,
}
if (params.assignee_id) body.assignee_id = params.assignee_id.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
action: data.action,
},
}
},
outputs: {
action: {
type: 'object',
description: 'The created action',
properties: INCIDENTIO_ACTION_RECORD_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,90 @@
import {
INCIDENTIO_ACTION_RECORD_OUTPUT_PROPERTIES,
type IncidentioActionsUpdateParams,
type IncidentioActionsUpdateResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const actionsUpdateTool: ToolConfig<
IncidentioActionsUpdateParams,
IncidentioActionsUpdateResponse
> = {
id: 'incidentio_actions_update',
name: 'Update Action',
description:
'Update an existing action in incident.io, for example to mark it completed or reassign it',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the action to update (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
description: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Description of the action. This endpoint replaces the description, so always send it.',
},
status: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Status of the action: "outstanding", "completed", or "not_doing". Deleting is not supported here.',
},
assignee_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the user to assign this action to',
},
},
request: {
url: (params) => `https://api.incident.io/v2/actions/${encodeURIComponent(params.id.trim())}`,
method: 'PUT',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, unknown> = {
description: params.description,
status: params.status,
}
if (params.assignee_id) body.assignee_id = params.assignee_id.trim()
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
action: data.action,
},
}
},
outputs: {
action: {
type: 'object',
description: 'The updated action',
properties: INCIDENTIO_ACTION_RECORD_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,127 @@
import type {
IncidentioAlertEventsCreateParams,
IncidentioAlertEventsCreateResponse,
} from '@/tools/incidentio/types'
import { parseIncidentioJsonParam } from '@/tools/incidentio/utils'
import type { ToolConfig } from '@/tools/types'
export const alertEventsCreateTool: ToolConfig<
IncidentioAlertEventsCreateParams,
IncidentioAlertEventsCreateResponse
> = {
id: 'incidentio_alert_events_create',
name: 'Create Alert Event',
description:
'Fire an alert into incident.io through an HTTP alert source. Send the same deduplication key with status "resolved" to close the alert you opened.',
version: '1.0.0',
params: {
alert_source_config_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The ID of the HTTP alert source config to fire into (e.g., "01GW2G3V0S59R238FAHPDS1R66")',
},
alert_source_token: {
type: 'string',
required: true,
visibility: 'user-only',
description:
'The token generated when configuring the HTTP alert source. This is not the incident.io API key.',
},
title: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Title of the alert (e.g., "Payments service error rate above 5%")',
},
status: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Current status of the alert: "firing" or "resolved"',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Detail to add below the title. Supports Markdown.',
},
deduplication_key: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Key that uniquely identifies this alert. Reuse it to update or resolve the same alert instead of creating a new one.',
},
source_url: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Link back to the alert in the upstream system',
},
metadata: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Additional metadata as a JSON object, parsed according to the alert source config (e.g., {"service": "payments"})',
},
},
request: {
url: (params) =>
`https://api.incident.io/v2/alert_events/http/${encodeURIComponent(
params.alert_source_config_id.trim()
)}`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.alert_source_token}`,
}),
body: (params) => {
const body: Record<string, unknown> = {
title: params.title,
status: params.status,
}
if (params.description) body.description = params.description
if (params.deduplication_key) body.deduplication_key = params.deduplication_key
if (params.source_url) body.source_url = params.source_url
if (params.metadata) {
body.metadata = parseIncidentioJsonParam(params.metadata, 'metadata', undefined)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
deduplication_key: data.deduplication_key,
message: data.message,
status: data.status,
},
}
},
outputs: {
deduplication_key: {
type: 'string',
description: 'The deduplication key the event was processed with',
},
message: {
type: 'string',
description: 'Human readable message giving detail about the event',
},
status: {
type: 'string',
description: 'Status of the event',
},
},
}
@@ -0,0 +1,81 @@
/**
* @vitest-environment node
*/
import { describe, expect, it } from 'vitest'
import { IncidentioBlock } from '@/blocks/blocks/incidentio'
import { alertsListTool } from '@/tools/incidentio/alerts_list'
/**
* The executor merges the block's param transform over the raw inputs
* (`{ ...inputs, ...transformedParams }`), so any subblock the transform leaves alone keeps its
* raw editor value. The tri-state filter dropdowns default to the string 'any', which the
* incident.io API rejects — these cover the whole path from editor value to query string.
*/
function resolveInputs(inputs: Record<string, unknown>): Record<string, unknown> {
const transform = IncidentioBlock.tools.config!.params!
return { ...inputs, ...transform(inputs as never) }
}
function buildUrl(params: Record<string, unknown>): URL {
const url = alertsListTool.request.url
return new URL(typeof url === 'function' ? url(params as never) : url)
}
describe('incidentio_alerts_list filters', () => {
it('omits the tri-state filters when left on "Any"', () => {
const resolved = resolveInputs({
operation: 'incidentio_alerts_list',
apiKey: 'k',
has_notes: 'any',
include_maintenance_window: 'any',
})
expect(resolved.has_notes).toBeUndefined()
expect(resolved.include_maintenance_window).toBeUndefined()
const url = buildUrl(resolved)
expect(url.searchParams.has('has_notes[is]')).toBe(false)
expect(url.searchParams.has('include_maintenance_window[is]')).toBe(false)
})
it('sends the tri-state filters as booleans when set', () => {
const url = buildUrl(
resolveInputs({
operation: 'incidentio_alerts_list',
apiKey: 'k',
has_notes: 'true',
include_maintenance_window: 'false',
})
)
expect(url.searchParams.get('has_notes[is]')).toBe('true')
expect(url.searchParams.get('include_maintenance_window[is]')).toBe('false')
})
it('never forwards a non-boolean filter value to the query string', () => {
const url = buildUrl({ apiKey: 'k', has_notes: 'any', include_maintenance_window: 'any' })
expect(url.searchParams.has('has_notes[is]')).toBe(false)
expect(url.searchParams.has('include_maintenance_window[is]')).toBe(false)
})
it('applies the documented bracket-operator filter syntax', () => {
const url = buildUrl(
resolveInputs({
operation: 'incidentio_alerts_list',
apiKey: 'k',
alert_status: 'firing',
status_operator: 'not_in',
alert_source_id: '01GBSQF3FHF7FWZQNWGHAVQ804',
deduplication_key: 'ABC',
created_at_gte: '2025-01-01',
})
)
expect(url.searchParams.get('status[not_in]')).toBe('firing')
expect(url.searchParams.get('alert_source[one_of]')).toBe('01GBSQF3FHF7FWZQNWGHAVQ804')
expect(url.searchParams.get('deduplication_key[is]')).toBe('ABC')
expect(url.searchParams.get('created_at[gte]')).toBe('2025-01-01')
expect(url.searchParams.get('page_size')).toBe('25')
})
})
+180
View File
@@ -0,0 +1,180 @@
import {
INCIDENTIO_ALERT_OUTPUT_PROPERTIES,
type IncidentioAlertsListParams,
type IncidentioAlertsListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
/** incident.io requires a page size on this endpoint, so fall back to its documented default. */
const DEFAULT_PAGE_SIZE = 25
export const alertsListTool: ToolConfig<IncidentioAlertsListParams, IncidentioAlertsListResponse> =
{
id: 'incidentio_alerts_list',
name: 'List Alerts',
description:
'List alerts in incident.io, optionally filtered by status, source, or created date',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
page_size: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (e.g., 10, 25, 50). Default: 25',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor to fetch the next page of results (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
status: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by alert status: "firing" or "resolved"',
},
status_operator: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'How to apply the status filter: "one_of" to match it, "not_in" to exclude it. Default: one_of',
},
alert_source_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter by alert source ID (e.g., "01GBSQF3FHF7FWZQNWGHAVQ804")',
},
alert_source_operator: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'How to apply the alert source filter: "one_of" to match it, "not_in" to exclude it. Default: one_of',
},
deduplication_key: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Filter to the single alert with this deduplication key',
},
created_at_gte: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only return alerts created on or after this date (e.g., "2025-01-01")',
},
created_at_lte: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only return alerts created on or before this date (e.g., "2025-02-01")',
},
has_notes: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description: 'Filter to alerts that do (true) or do not (false) have notes attached',
},
include_maintenance_window: {
type: 'boolean',
required: false,
visibility: 'user-or-llm',
description:
'Whether to include alerts held by a maintenance window. Defaults to true on the API',
},
},
request: {
url: (params) => {
const url = new URL('https://api.incident.io/v2/alerts')
url.searchParams.set(
'page_size',
String(params.page_size && params.page_size > 0 ? params.page_size : DEFAULT_PAGE_SIZE)
)
if (params.after) {
url.searchParams.set('after', params.after)
}
if (params.status) {
url.searchParams.set(
`status[${params.status_operator ?? 'one_of'}]`,
params.status.trim()
)
}
if (params.alert_source_id) {
url.searchParams.set(
`alert_source[${params.alert_source_operator ?? 'one_of'}]`,
params.alert_source_id.trim()
)
}
if (params.deduplication_key) {
url.searchParams.set('deduplication_key[is]', params.deduplication_key.trim())
}
if (params.created_at_gte) {
url.searchParams.set('created_at[gte]', params.created_at_gte.trim())
}
if (params.created_at_lte) {
url.searchParams.set('created_at[lte]', params.created_at_lte.trim())
}
if (typeof params.has_notes === 'boolean') {
url.searchParams.set('has_notes[is]', String(params.has_notes))
}
if (typeof params.include_maintenance_window === 'boolean') {
url.searchParams.set(
'include_maintenance_window[is]',
String(params.include_maintenance_window)
)
}
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
alerts: data.alerts ?? [],
pagination_meta: data.pagination_meta,
},
}
},
outputs: {
alerts: {
type: 'array',
description: 'List of alerts',
items: {
type: 'object',
properties: INCIDENTIO_ALERT_OUTPUT_PROPERTIES,
},
},
pagination_meta: {
type: 'object',
description: 'Pagination metadata',
optional: true,
properties: {
after: { type: 'string', description: 'Cursor for next page', optional: true },
page_size: { type: 'number', description: 'Number of results per page' },
},
},
},
}
@@ -0,0 +1,61 @@
import {
INCIDENTIO_ALERT_OUTPUT_PROPERTIES,
type IncidentioAlertsResolveParams,
type IncidentioAlertsResolveResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const alertsResolveTool: ToolConfig<
IncidentioAlertsResolveParams,
IncidentioAlertsResolveResponse
> = {
id: 'incidentio_alerts_resolve',
name: 'Resolve Alert',
description:
'Resolve a currently firing alert in incident.io. Resolving an already-resolved alert is a no-op and returns it unchanged.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the alert to resolve (e.g., "01GW2G3V0S59R238FAHPDS1R66")',
},
},
request: {
url: (params) =>
`https://api.incident.io/v2/alerts/${encodeURIComponent(params.id.trim())}/actions/resolve`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
alert: data.alert,
},
}
},
outputs: {
alert: {
type: 'object',
description: 'The resolved alert',
properties: INCIDENTIO_ALERT_OUTPUT_PROPERTIES,
},
},
}
+57
View File
@@ -0,0 +1,57 @@
import {
INCIDENTIO_ALERT_OUTPUT_PROPERTIES,
type IncidentioAlertsShowParams,
type IncidentioAlertsShowResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const alertsShowTool: ToolConfig<IncidentioAlertsShowParams, IncidentioAlertsShowResponse> =
{
id: 'incidentio_alerts_show',
name: 'Show Alert',
description: 'Get a single alert by ID from incident.io',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the alert to fetch (e.g., "01GW2G3V0S59R238FAHPDS1R66")',
},
},
request: {
url: (params) => `https://api.incident.io/v2/alerts/${encodeURIComponent(params.id.trim())}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
alert: data.alert,
},
}
},
outputs: {
alert: {
type: 'object',
description: 'The alert details',
properties: INCIDENTIO_ALERT_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,144 @@
import {
INCIDENTIO_CATALOG_TYPE_OUTPUT_PROPERTIES,
type IncidentioCatalogEntriesListParams,
type IncidentioCatalogEntriesListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
/** incident.io requires a page size on this endpoint, so fall back to its documented default. */
const DEFAULT_PAGE_SIZE = 25
export const catalogEntriesListTool: ToolConfig<
IncidentioCatalogEntriesListParams,
IncidentioCatalogEntriesListResponse
> = {
id: 'incidentio_catalog_entries_list',
name: 'List Catalog Entries',
description:
'List the entries of a catalog type in incident.io — for example every service, team, or customer recorded in the catalog',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
catalog_type_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The ID of the catalog type to list entries for (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
page_size: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (e.g., 10, 25, 50). Default: 25',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor to fetch the next page of results (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
identifier: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Only return entries matching this identifier. Searches by ID, external ID, and alias.',
},
},
request: {
url: (params) => {
const url = new URL('https://api.incident.io/v3/catalog_entries')
url.searchParams.set('catalog_type_id', params.catalog_type_id.trim())
url.searchParams.set(
'page_size',
String(params.page_size && params.page_size > 0 ? params.page_size : DEFAULT_PAGE_SIZE)
)
if (params.after) url.searchParams.set('after', params.after)
if (params.identifier) url.searchParams.set('identifier', params.identifier.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
catalog_entries: data.catalog_entries ?? [],
catalog_type: data.catalog_type ?? null,
pagination_meta: data.pagination_meta,
},
}
},
outputs: {
catalog_entries: {
type: 'array',
description: 'List of catalog entries',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Catalog entry ID' },
name: { type: 'string', description: 'Human readable name of this entry' },
catalog_type_id: { type: 'string', description: 'ID of the catalog type' },
external_id: {
type: 'string',
description: 'Alternative ID for this entry, unique within the type',
optional: true,
},
aliases: {
type: 'array',
description: 'Alternative names this entry can be referenced by',
items: { type: 'string' },
},
rank: { type: 'number', description: 'Ordering rank, used when the type is ranked' },
attribute_values: { type: 'json', description: 'Attribute values of this entry' },
archived_at: {
type: 'string',
description: 'When this entry was archived',
optional: true,
},
created_at: { type: 'string', description: 'When this entry was created' },
updated_at: { type: 'string', description: 'When this entry was last updated' },
},
},
},
catalog_type: {
type: 'object',
description: 'The catalog type these entries belong to',
nullable: true,
properties: INCIDENTIO_CATALOG_TYPE_OUTPUT_PROPERTIES,
},
pagination_meta: {
type: 'object',
description: 'Pagination metadata',
optional: true,
properties: {
after: { type: 'string', description: 'Cursor for next page', optional: true },
page_size: { type: 'number', description: 'Number of results per page' },
total_record_count: {
type: 'number',
description: 'Total number of entries',
optional: true,
},
},
},
},
}
@@ -0,0 +1,57 @@
import {
INCIDENTIO_CATALOG_TYPE_OUTPUT_PROPERTIES,
type IncidentioCatalogTypesListParams,
type IncidentioCatalogTypesListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const catalogTypesListTool: ToolConfig<
IncidentioCatalogTypesListParams,
IncidentioCatalogTypesListResponse
> = {
id: 'incidentio_catalog_types_list',
name: 'List Catalog Types',
description:
'List all catalog types in incident.io, including those synced from external resources. Use this to find the catalog type ID needed to list entries.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
},
request: {
url: 'https://api.incident.io/v3/catalog_types',
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
catalog_types: data.catalog_types ?? [],
},
}
},
outputs: {
catalog_types: {
type: 'array',
description: 'List of catalog types',
items: {
type: 'object',
properties: INCIDENTIO_CATALOG_TYPE_OUTPUT_PROPERTIES,
},
},
},
}
@@ -0,0 +1,57 @@
import type {
IncidentioEscalationsCancelParams,
IncidentioEscalationsCancelResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const escalationsCancelTool: ToolConfig<
IncidentioEscalationsCancelParams,
IncidentioEscalationsCancelResponse
> = {
id: 'incidentio_escalations_cancel',
name: 'Cancel Escalation',
description:
'Cancel an escalation in incident.io. Notifications stop, and the escalation will not advance to further levels or repeat.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the escalation to cancel (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
},
request: {
url: (params) =>
`https://api.incident.io/v2/escalations/${encodeURIComponent(params.id.trim())}/actions/cancel`,
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async () => {
return {
success: true,
output: {
message: 'Escalation cancelled successfully',
},
}
},
outputs: {
message: {
type: 'string',
description: 'Success message',
},
},
}
@@ -0,0 +1,135 @@
import {
INCIDENTIO_FOLLOW_UP_RECORD_OUTPUT_PROPERTIES,
type IncidentioFollowUpsCreateParams,
type IncidentioFollowUpsCreateResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const followUpsCreateTool: ToolConfig<
IncidentioFollowUpsCreateParams,
IncidentioFollowUpsCreateResponse
> = {
id: 'incidentio_follow_ups_create',
name: 'Create Follow-up',
description: 'Create a new follow-up on an incident in incident.io',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
incident_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The ID of the incident the follow-up belongs to (e.g., "01FDAG4SAP5TYPT98WGR2N7W91")',
},
title: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Title of the follow-up (e.g., "Add alerting on connection pool saturation")',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the follow-up. Supports Markdown.',
},
assignee_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the user to assign this follow-up to',
},
assignee_team_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the team to assign this follow-up to',
},
follow_up_category_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the category for this follow-up',
},
follow_up_priority_option_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the priority for this follow-up',
},
external_issue_reference_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the external issue this follow-up relates to',
},
labels: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of labels (e.g., "bug,urgent")',
},
},
request: {
url: 'https://api.incident.io/v2/follow_ups',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, unknown> = {
incident_id: params.incident_id.trim(),
title: params.title,
}
if (params.description) body.description = params.description
if (params.assignee_id) body.assignee_id = params.assignee_id.trim()
if (params.assignee_team_id) body.assignee_team_id = params.assignee_team_id.trim()
if (params.follow_up_category_id) {
body.follow_up_category_id = params.follow_up_category_id.trim()
}
if (params.follow_up_priority_option_id) {
body.follow_up_priority_option_id = params.follow_up_priority_option_id.trim()
}
if (params.external_issue_reference_id) {
body.external_issue_reference_id = params.external_issue_reference_id.trim()
}
if (params.labels) {
body.labels = params.labels
.split(',')
.map((label) => label.trim())
.filter(Boolean)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
follow_up: data.follow_up,
},
}
},
outputs: {
follow_up: {
type: 'object',
description: 'The created follow-up',
properties: INCIDENTIO_FOLLOW_UP_RECORD_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,134 @@
import {
INCIDENTIO_FOLLOW_UP_RECORD_OUTPUT_PROPERTIES,
type IncidentioFollowUpsUpdateParams,
type IncidentioFollowUpsUpdateResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const followUpsUpdateTool: ToolConfig<
IncidentioFollowUpsUpdateParams,
IncidentioFollowUpsUpdateResponse
> = {
id: 'incidentio_follow_ups_update',
name: 'Update Follow-up',
description:
'Update an existing follow-up in incident.io, for example to mark it completed or reassign it',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the follow-up to update (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
title: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'Title of the follow-up. This endpoint replaces the title, so always send it.',
},
status: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'Status of the follow-up: "outstanding", "completed", or "not_doing". Deleting is not supported here.',
},
description: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Description of the follow-up. Supports Markdown.',
},
assignee_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the user to assign this follow-up to',
},
assignee_team_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the team to assign this follow-up to',
},
follow_up_category_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the category for this follow-up',
},
follow_up_priority_option_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'ID of the priority for this follow-up',
},
labels: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Comma-separated list of labels (e.g., "bug,urgent")',
},
},
request: {
url: (params) =>
`https://api.incident.io/v2/follow_ups/${encodeURIComponent(params.id.trim())}`,
method: 'PUT',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => {
const body: Record<string, unknown> = {
title: params.title,
status: params.status,
}
if (params.description) body.description = params.description
if (params.assignee_id) body.assignee_id = params.assignee_id.trim()
if (params.assignee_team_id) body.assignee_team_id = params.assignee_team_id.trim()
if (params.follow_up_category_id) {
body.follow_up_category_id = params.follow_up_category_id.trim()
}
if (params.follow_up_priority_option_id) {
body.follow_up_priority_option_id = params.follow_up_priority_option_id.trim()
}
if (params.labels) {
body.labels = params.labels
.split(',')
.map((label) => label.trim())
.filter(Boolean)
}
return body
},
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
follow_up: data.follow_up,
},
}
},
outputs: {
follow_up: {
type: 'object',
description: 'The updated follow-up',
properties: INCIDENTIO_FOLLOW_UP_RECORD_OUTPUT_PROPERTIES,
},
},
}
@@ -0,0 +1,157 @@
import type {
IncidentioIncidentAlertsListParams,
IncidentioIncidentAlertsListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
/** incident.io requires a page size on this endpoint, so fall back to its documented default. */
const DEFAULT_PAGE_SIZE = 25
export const incidentAlertsListTool: ToolConfig<
IncidentioIncidentAlertsListParams,
IncidentioIncidentAlertsListResponse
> = {
id: 'incidentio_incident_alerts_list',
name: 'List Incident Alerts',
description:
'List the connections between incidents and alerts in incident.io — which alerts triggered an incident, or which incident an alert was attached to',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
page_size: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (e.g., 10, 25, 50). Default: 25',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor to fetch the next page of results (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
incident_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Only return alerts attached to this incident (e.g., "01FDAG4SAP5TYPT98WGR2N7W91")',
},
alert_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only return connections for this alert (e.g., "01GW2G3V0S59R238FAHPDS1R66")',
},
},
request: {
url: (params) => {
const url = new URL('https://api.incident.io/v2/incident_alerts')
url.searchParams.set(
'page_size',
String(params.page_size && params.page_size > 0 ? params.page_size : DEFAULT_PAGE_SIZE)
)
if (params.after) url.searchParams.set('after', params.after)
if (params.incident_id) url.searchParams.set('incident_id', params.incident_id.trim())
if (params.alert_id) url.searchParams.set('alert_id', params.alert_id.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
incident_alerts: data.incident_alerts ?? [],
pagination_meta: data.pagination_meta,
},
}
},
outputs: {
incident_alerts: {
type: 'array',
description: 'List of incident-to-alert connections',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'ID of this incident alert connection' },
alert_route_id: {
type: 'string',
description: 'ID of the alert route that created this connection',
optional: true,
},
alert: {
type: 'object',
description: 'The connected alert',
properties: {
id: { type: 'string', description: 'Alert ID' },
title: { type: 'string', description: 'Alert title' },
status: { type: 'string', description: 'Alert status (firing, resolved)' },
alert_source_id: {
type: 'string',
description: 'ID of the alert source this alert fired on',
},
deduplication_key: {
type: 'string',
description: 'Key that uniquely references this alert from its source',
},
description: { type: 'string', description: 'Alert description', optional: true },
source_url: {
type: 'string',
description: 'Link to the alert in the upstream system',
optional: true,
},
resolved_at: {
type: 'string',
description: 'When this alert was resolved',
optional: true,
},
created_at: { type: 'string', description: 'When this alert was created' },
updated_at: { type: 'string', description: 'When this alert was last updated' },
},
},
incident: {
type: 'object',
description: 'The incident the alert is attached to',
properties: {
id: { type: 'string', description: 'Incident ID' },
name: { type: 'string', description: 'Incident name' },
reference: { type: 'string', description: 'Incident reference (e.g., INC-123)' },
external_id: { type: 'number', description: 'External incident identifier' },
status_category: { type: 'string', description: 'Category of the incident status' },
visibility: { type: 'string', description: 'Incident visibility (public, private)' },
summary: { type: 'string', description: 'Incident summary', optional: true },
},
},
},
},
},
pagination_meta: {
type: 'object',
description: 'Pagination metadata',
optional: true,
properties: {
after: { type: 'string', description: 'Cursor for next page', optional: true },
page_size: { type: 'number', description: 'Number of results per page' },
},
},
},
}
@@ -0,0 +1,84 @@
import type {
IncidentioIncidentMembershipsCreateParams,
IncidentioIncidentMembershipsCreateResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const incidentMembershipsCreateTool: ToolConfig<
IncidentioIncidentMembershipsCreateParams,
IncidentioIncidentMembershipsCreateResponse
> = {
id: 'incidentio_incident_memberships_create',
name: 'Grant Incident Membership',
description: 'Make a user a member of a private incident in incident.io',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
incident_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the private incident (e.g., "01FCNDV6P870EA6S7TK1DSYD5H")',
},
user_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the user to grant access to (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
},
request: {
url: 'https://api.incident.io/v1/incident_memberships',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => ({
incident_id: params.incident_id.trim(),
user_id: params.user_id.trim(),
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
incident_membership: data.incident_membership,
},
}
},
outputs: {
incident_membership: {
type: 'object',
description: 'The created incident membership',
properties: {
id: { type: 'string', description: 'Incident membership ID' },
incident_id: { type: 'string', description: 'ID of the incident' },
created_at: { type: 'string', description: 'When the membership was created' },
updated_at: { type: 'string', description: 'When the membership was last updated' },
user: {
type: 'object',
description: 'The user who was granted access',
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User display name' },
email: { type: 'string', description: 'User email address', optional: true },
role: { type: 'string', description: 'User role', optional: true },
slack_user_id: { type: 'string', description: 'Slack user ID', optional: true },
},
},
},
},
},
}
@@ -0,0 +1,65 @@
import type {
IncidentioIncidentMembershipsRevokeParams,
IncidentioIncidentMembershipsRevokeResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const incidentMembershipsRevokeTool: ToolConfig<
IncidentioIncidentMembershipsRevokeParams,
IncidentioIncidentMembershipsRevokeResponse
> = {
id: 'incidentio_incident_memberships_revoke',
name: 'Revoke Incident Membership',
description: "Revoke a user's membership of a private incident in incident.io",
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
incident_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the private incident (e.g., "01FCNDV6P870EA6S7TK1DSYD5H")',
},
user_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the user to revoke access from (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
},
request: {
url: 'https://api.incident.io/v1/incident_memberships/actions/revoke',
method: 'POST',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
body: (params) => ({
incident_id: params.incident_id.trim(),
user_id: params.user_id.trim(),
}),
},
transformResponse: async () => {
return {
success: true,
output: {
message: 'Incident membership revoked successfully',
},
}
},
outputs: {
message: {
type: 'string',
description: 'Success message',
},
},
}
@@ -0,0 +1,91 @@
import type {
IncidentioIncidentParticipantsListParams,
IncidentioIncidentParticipantsListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
const PARTICIPANT_ITEMS = {
type: 'object',
properties: {
participant_type: {
type: 'string',
description: 'The role they took in the incident (observer, collaborator, responder)',
},
user: {
type: 'object',
description: 'The participating user',
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User display name' },
email: { type: 'string', description: 'User email address', optional: true },
role: { type: 'string', description: 'User role', optional: true },
slack_user_id: { type: 'string', description: 'Slack user ID', optional: true },
},
},
},
} as const
export const incidentParticipantsListTool: ToolConfig<
IncidentioIncidentParticipantsListParams,
IncidentioIncidentParticipantsListResponse
> = {
id: 'incidentio_incident_participants_list',
name: 'List Incident Participants',
description:
'List the participants of an incident in incident.io, split into those actively helping and those just observing',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
incident_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The ID of the incident to find participants of (e.g., "01FDAG4SAP5TYPT98WGR2N7W91")',
},
},
request: {
url: (params) => {
const url = new URL('https://api.incident.io/v2/incident_participants')
url.searchParams.set('incident_id', params.incident_id.trim())
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
active: data.incident_participants?.active ?? [],
passive: data.incident_participants?.passive ?? [],
},
}
},
outputs: {
active: {
type: 'array',
description: 'Participants who are actively helping with the incident',
items: PARTICIPANT_ITEMS,
},
passive: {
type: 'array',
description: 'Participants who are just observing the incident',
items: PARTICIPANT_ITEMS,
},
},
}
+39
View File
@@ -1,5 +1,13 @@
import { actionsCreateTool } from '@/tools/incidentio/actions_create'
import { actionsListTool } from '@/tools/incidentio/actions_list'
import { actionsShowTool } from '@/tools/incidentio/actions_show'
import { actionsUpdateTool } from '@/tools/incidentio/actions_update'
import { alertEventsCreateTool } from '@/tools/incidentio/alert_events_create'
import { alertsListTool } from '@/tools/incidentio/alerts_list'
import { alertsResolveTool } from '@/tools/incidentio/alerts_resolve'
import { alertsShowTool } from '@/tools/incidentio/alerts_show'
import { catalogEntriesListTool } from '@/tools/incidentio/catalog_entries_list'
import { catalogTypesListTool } from '@/tools/incidentio/catalog_types_list'
import { customFieldsCreateTool } from '@/tools/incidentio/custom_fields_create'
import { customFieldsDeleteTool } from '@/tools/incidentio/custom_fields_delete'
import { customFieldsListTool } from '@/tools/incidentio/custom_fields_list'
@@ -10,11 +18,18 @@ import { escalationPathsDeleteTool } from '@/tools/incidentio/escalation_paths_d
import { escalationPathsListTool } from '@/tools/incidentio/escalation_paths_list'
import { escalationPathsShowTool } from '@/tools/incidentio/escalation_paths_show'
import { escalationPathsUpdateTool } from '@/tools/incidentio/escalation_paths_update'
import { escalationsCancelTool } from '@/tools/incidentio/escalations_cancel'
import { escalationsCreateTool } from '@/tools/incidentio/escalations_create'
import { escalationsListTool } from '@/tools/incidentio/escalations_list'
import { escalationsShowTool } from '@/tools/incidentio/escalations_show'
import { followUpsCreateTool } from '@/tools/incidentio/follow_ups_create'
import { followUpsListTool } from '@/tools/incidentio/follow_ups_list'
import { followUpsShowTool } from '@/tools/incidentio/follow_ups_show'
import { followUpsUpdateTool } from '@/tools/incidentio/follow_ups_update'
import { incidentAlertsListTool } from '@/tools/incidentio/incident_alerts_list'
import { incidentMembershipsCreateTool } from '@/tools/incidentio/incident_memberships_create'
import { incidentMembershipsRevokeTool } from '@/tools/incidentio/incident_memberships_revoke'
import { incidentParticipantsListTool } from '@/tools/incidentio/incident_participants_list'
import { incidentRolesCreateTool } from '@/tools/incidentio/incident_roles_create'
import { incidentRolesDeleteTool } from '@/tools/incidentio/incident_roles_delete'
import { incidentRolesListTool } from '@/tools/incidentio/incident_roles_list'
@@ -29,14 +44,18 @@ import { incidentsCreateTool } from '@/tools/incidentio/incidents_create'
import { incidentsListTool } from '@/tools/incidentio/incidents_list'
import { incidentsShowTool } from '@/tools/incidentio/incidents_show'
import { incidentsUpdateTool } from '@/tools/incidentio/incidents_update'
import { onCallNowTool } from '@/tools/incidentio/on_call_now'
import { scheduleEntriesListTool } from '@/tools/incidentio/schedule_entries_list'
import { scheduleOverridesCreateTool } from '@/tools/incidentio/schedule_overrides_create'
import { scheduleOverridesListTool } from '@/tools/incidentio/schedule_overrides_list'
import { schedulesCreateTool } from '@/tools/incidentio/schedules_create'
import { schedulesDeleteTool } from '@/tools/incidentio/schedules_delete'
import { schedulesListTool } from '@/tools/incidentio/schedules_list'
import { schedulesShowTool } from '@/tools/incidentio/schedules_show'
import { schedulesUpdateTool } from '@/tools/incidentio/schedules_update'
import { severitiesListTool } from '@/tools/incidentio/severities_list'
import { teamsListTool } from '@/tools/incidentio/teams_list'
import { teamsShowTool } from '@/tools/incidentio/teams_show'
import { usersListTool } from '@/tools/incidentio/users_list'
import { usersShowTool } from '@/tools/incidentio/users_show'
import { workflowsCreateTool } from '@/tools/incidentio/workflows_create'
@@ -92,4 +111,24 @@ export const incidentioEscalationPathsShowTool = escalationPathsShowTool
export const incidentioEscalationPathsUpdateTool = escalationPathsUpdateTool
export const incidentioEscalationPathsDeleteTool = escalationPathsDeleteTool
export const incidentioOnCallNowTool = onCallNowTool
export const incidentioScheduleOverridesListTool = scheduleOverridesListTool
export const incidentioAlertsListTool = alertsListTool
export const incidentioAlertsShowTool = alertsShowTool
export const incidentioAlertsResolveTool = alertsResolveTool
export const incidentioAlertEventsCreateTool = alertEventsCreateTool
export const incidentioIncidentAlertsListTool = incidentAlertsListTool
export const incidentioEscalationsCancelTool = escalationsCancelTool
export const incidentioCatalogTypesListTool = catalogTypesListTool
export const incidentioCatalogEntriesListTool = catalogEntriesListTool
export const incidentioTeamsListTool = teamsListTool
export const incidentioTeamsShowTool = teamsShowTool
export const incidentioFollowUpsCreateTool = followUpsCreateTool
export const incidentioFollowUpsUpdateTool = followUpsUpdateTool
export const incidentioActionsCreateTool = actionsCreateTool
export const incidentioActionsUpdateTool = actionsUpdateTool
export const incidentioIncidentParticipantsListTool = incidentParticipantsListTool
export const incidentioIncidentMembershipsCreateTool = incidentMembershipsCreateTool
export const incidentioIncidentMembershipsRevokeTool = incidentMembershipsRevokeTool
export * from '@/tools/incidentio/types'
+220
View File
@@ -0,0 +1,220 @@
import type {
IncidentioOnCallNowParams,
IncidentioOnCallNowResponse,
IncidentioOnCallShift,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
/** The largest page size for which incident.io still populates `next_shifts`. */
const NEXT_SHIFTS_MAX_PAGE_SIZE = 25
const ON_CALL_SHIFT_OUTPUT_PROPERTIES = {
schedule_id: { type: 'string', description: 'ID of the schedule the shift belongs to' },
schedule_name: { type: 'string', description: 'Name of the schedule the shift belongs to' },
schedule_timezone: { type: 'string', description: 'Timezone the schedule is interpreted in' },
schedule_permalink: {
type: 'string',
description: 'Link to the schedule in the incident.io dashboard',
optional: true,
},
entry_id: {
type: 'string',
description:
'ID of the stored schedule entry. Absent for shifts projected from rotation rules rather than stored',
optional: true,
},
rotation_id: {
type: 'string',
description: 'ID of the rotation this shift belongs to',
optional: true,
},
layer_id: {
type: 'string',
description: 'ID of the layer this shift belongs to',
optional: true,
},
start_at: { type: 'string', description: 'When the shift starts' },
end_at: { type: 'string', description: 'When the shift ends' },
user_id: { type: 'string', description: 'ID of the on-call user', optional: true },
user_name: { type: 'string', description: 'Name of the on-call user', optional: true },
user_email: { type: 'string', description: 'Email of the on-call user', optional: true },
user_slack_user_id: {
type: 'string',
description: 'Slack ID of the on-call user',
optional: true,
},
} as const
/** The subset of the schedule payload this tool reads. */
interface RawScheduleEntry {
entry_id?: string
rotation_id?: string
layer_id?: string
start_at?: string
end_at?: string
user?: { id?: string; name?: string; email?: string; slack_user_id?: string }
}
interface RawSchedule {
id?: string
name?: string
timezone?: string
permalink?: string
current_shifts?: RawScheduleEntry[]
next_shifts?: RawScheduleEntry[]
}
/**
* Flattens a schedule's `current_shifts` / `next_shifts` into one row per shift, carrying the
* owning schedule's identity down onto each row so the caller does not have to join them back up.
*/
function flattenShifts(schedule: RawSchedule): {
current: IncidentioOnCallShift[]
next: IncidentioOnCallShift[]
} {
const toShift = (entry: RawScheduleEntry): IncidentioOnCallShift => ({
schedule_id: schedule.id ?? '',
schedule_name: schedule.name ?? '',
schedule_timezone: schedule.timezone ?? '',
schedule_permalink: schedule.permalink ?? null,
entry_id: entry.entry_id ?? null,
rotation_id: entry.rotation_id ?? null,
layer_id: entry.layer_id ?? null,
start_at: entry.start_at ?? null,
end_at: entry.end_at ?? null,
user_id: entry.user?.id ?? null,
user_name: entry.user?.name ?? null,
user_email: entry.user?.email ?? null,
user_slack_user_id: entry.user?.slack_user_id ?? null,
})
return {
current: (Array.isArray(schedule.current_shifts) ? schedule.current_shifts : []).map(toShift),
next: (Array.isArray(schedule.next_shifts) ? schedule.next_shifts : []).map(toShift),
}
}
export const onCallNowTool: ToolConfig<IncidentioOnCallNowParams, IncidentioOnCallNowResponse> = {
id: 'incidentio_on_call_now',
name: 'Get Who Is On Call',
description:
'Get who is currently on call in incident.io, as one row per ongoing shift across every schedule (or a single schedule). Also returns the shifts that take over at the next changeover.',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
schedule_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Limit the result to a single schedule by ID (e.g., "01FCNDV6P870EA6S7TK1DSYDG0"). Leave empty to return who is on call across every schedule.',
},
page_size: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description:
'Number of schedules to scan per page when no schedule ID is given (e.g., 10, 25). Defaults to 25; upcoming shifts are only returned at 25 or lower.',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor to fetch the next page of schedules (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
},
request: {
url: (params) => {
const scheduleId = params.schedule_id?.trim()
if (scheduleId) {
return `https://api.incident.io/v2/schedules/${encodeURIComponent(scheduleId)}`
}
const url = new URL('https://api.incident.io/v2/schedules')
url.searchParams.set(
'page_size',
String(
params.page_size && params.page_size > 0 ? params.page_size : NEXT_SHIFTS_MAX_PAGE_SIZE
)
)
if (params.after) {
url.searchParams.set('after', params.after)
}
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
const schedules: RawSchedule[] = Array.isArray(data.schedules)
? data.schedules
: data.schedule
? [data.schedule]
: []
const onCall: IncidentioOnCallShift[] = []
const nextOnCall: IncidentioOnCallShift[] = []
for (const schedule of schedules) {
const { current, next } = flattenShifts(schedule)
onCall.push(...current)
nextOnCall.push(...next)
}
return {
success: true,
output: {
on_call: onCall,
next_on_call: nextOnCall,
pagination_meta: data.pagination_meta,
},
}
},
outputs: {
on_call: {
type: 'array',
description: 'Shifts that are ongoing right now, one row per on-call person per schedule',
items: {
type: 'object',
properties: ON_CALL_SHIFT_OUTPUT_PROPERTIES,
},
},
next_on_call: {
type: 'array',
description:
'Shifts that take over at the next changeover. Only populated when the page size is 25 or lower',
items: {
type: 'object',
properties: ON_CALL_SHIFT_OUTPUT_PROPERTIES,
},
},
pagination_meta: {
type: 'object',
description: 'Pagination metadata, returned when scanning every schedule',
optional: true,
properties: {
after: { type: 'string', description: 'Cursor for next page', optional: true },
page_size: { type: 'number', description: 'Number of results per page' },
total_record_count: {
type: 'number',
description: 'Total number of schedules',
optional: true,
},
},
},
},
}
@@ -0,0 +1,129 @@
import type {
IncidentioScheduleOverridesListParams,
IncidentioScheduleOverridesListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const scheduleOverridesListTool: ToolConfig<
IncidentioScheduleOverridesListParams,
IncidentioScheduleOverridesListResponse
> = {
id: 'incidentio_schedule_overrides_list',
name: 'List Schedule Overrides',
description:
'List the one-off overrides layered on top of a schedule in incident.io, such as someone covering a colleague’s shift',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
schedule_id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description:
'The ID of the schedule to get overrides for (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
rotation_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only return overrides on this rotation',
},
layer_id: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description: 'Only return overrides on this layer',
},
page_size: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (e.g., 10, 25, 50)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor to fetch the next page of results (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
},
request: {
url: (params) => {
const url = new URL('https://api.incident.io/v2/schedule_overrides')
url.searchParams.set('schedule_id', params.schedule_id.trim())
if (params.rotation_id) url.searchParams.set('rotation_id', params.rotation_id.trim())
if (params.layer_id) url.searchParams.set('layer_id', params.layer_id.trim())
if (params.page_size) url.searchParams.set('page_size', String(params.page_size))
if (params.after) url.searchParams.set('after', params.after)
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
overrides: data.overrides ?? [],
pagination_meta: data.pagination_meta,
},
}
},
outputs: {
overrides: {
type: 'array',
description: 'List of schedule overrides',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'Override ID' },
schedule_id: { type: 'string', description: 'Schedule the override applies to' },
rotation_id: { type: 'string', description: 'Rotation the override applies to' },
layer_id: { type: 'string', description: 'Layer the override applies to' },
start_at: { type: 'string', description: 'Start of the override' },
end_at: { type: 'string', description: 'End of the override' },
created_at: { type: 'string', description: 'When the override was created' },
updated_at: { type: 'string', description: 'When the override was last updated' },
user: {
type: 'object',
description: 'The user covering the override',
optional: true,
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User display name' },
email: { type: 'string', description: 'User email address', optional: true },
role: { type: 'string', description: 'User role', optional: true },
slack_user_id: { type: 'string', description: 'Slack user ID', optional: true },
},
},
},
},
},
pagination_meta: {
type: 'object',
description: 'Pagination metadata',
optional: true,
properties: {
after: { type: 'string', description: 'Cursor for next page', optional: true },
page_size: { type: 'number', description: 'Number of results per page' },
},
},
},
}
@@ -82,6 +82,50 @@ export const schedulesListTool: ToolConfig<
timezone: { type: 'string', description: 'The schedule timezone' },
created_at: { type: 'string', description: 'When the schedule was created' },
updated_at: { type: 'string', description: 'When the schedule was last updated' },
current_shifts: {
type: 'array',
description: 'Shifts that are ongoing right now, naming who is on call',
optional: true,
items: {
type: 'object',
properties: {
start_at: { type: 'string', description: 'When the shift starts' },
end_at: { type: 'string', description: 'When the shift ends' },
entry_id: { type: 'string', description: 'Schedule entry ID', optional: true },
rotation_id: { type: 'string', description: 'Rotation ID', optional: true },
layer_id: { type: 'string', description: 'Layer ID', optional: true },
user: { type: 'object', description: 'The on-call user', optional: true },
},
},
},
next_shifts: {
type: 'array',
description:
'Shifts that take over at the next changeover. Only returned when the page size is 25 or lower',
optional: true,
items: {
type: 'object',
properties: {
start_at: { type: 'string', description: 'When the shift starts' },
end_at: { type: 'string', description: 'When the shift ends' },
entry_id: { type: 'string', description: 'Schedule entry ID', optional: true },
rotation_id: { type: 'string', description: 'Rotation ID', optional: true },
layer_id: { type: 'string', description: 'Layer ID', optional: true },
user: { type: 'object', description: 'The on-call user', optional: true },
},
},
},
permalink: {
type: 'string',
description: 'Link to the schedule in the incident.io dashboard',
optional: true,
},
team_ids: {
type: 'array',
description: 'IDs of teams that own this schedule',
optional: true,
items: { type: 'string' },
},
},
},
},
@@ -58,6 +58,50 @@ export const schedulesShowTool: ToolConfig<
timezone: { type: 'string', description: 'The schedule timezone' },
created_at: { type: 'string', description: 'When the schedule was created' },
updated_at: { type: 'string', description: 'When the schedule was last updated' },
current_shifts: {
type: 'array',
description: 'Shifts that are ongoing right now, naming who is on call',
optional: true,
items: {
type: 'object',
properties: {
start_at: { type: 'string', description: 'When the shift starts' },
end_at: { type: 'string', description: 'When the shift ends' },
entry_id: { type: 'string', description: 'Schedule entry ID', optional: true },
rotation_id: { type: 'string', description: 'Rotation ID', optional: true },
layer_id: { type: 'string', description: 'Layer ID', optional: true },
user: { type: 'object', description: 'The on-call user', optional: true },
},
},
},
next_shifts: {
type: 'array',
description:
'Shifts that take over at the next changeover. Only returned when the page size is 25 or lower',
optional: true,
items: {
type: 'object',
properties: {
start_at: { type: 'string', description: 'When the shift starts' },
end_at: { type: 'string', description: 'When the shift ends' },
entry_id: { type: 'string', description: 'Schedule entry ID', optional: true },
rotation_id: { type: 'string', description: 'Rotation ID', optional: true },
layer_id: { type: 'string', description: 'Layer ID', optional: true },
user: { type: 'object', description: 'The on-call user', optional: true },
},
},
},
permalink: {
type: 'string',
description: 'Link to the schedule in the incident.io dashboard',
optional: true,
},
team_ids: {
type: 'array',
description: 'IDs of teams that own this schedule',
optional: true,
items: { type: 'string' },
},
},
},
},
+81
View File
@@ -0,0 +1,81 @@
import {
INCIDENTIO_TEAM_OUTPUT_PROPERTIES,
type IncidentioTeamsListParams,
type IncidentioTeamsListResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const teamsListTool: ToolConfig<IncidentioTeamsListParams, IncidentioTeamsListResponse> = {
id: 'incidentio_teams_list',
name: 'List Teams',
description: 'List all teams in the incident.io organisation, along with their members',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
page_size: {
type: 'number',
required: false,
visibility: 'user-or-llm',
description: 'Number of results per page (e.g., 10, 25, 50)',
},
after: {
type: 'string',
required: false,
visibility: 'user-or-llm',
description:
'Pagination cursor to fetch the next page of results (e.g., "01FCNDV6P870EA6S7TK1DSYDG0")',
},
},
request: {
url: (params) => {
const url = new URL('https://api.incident.io/v3/teams')
if (params.page_size) url.searchParams.set('page_size', String(params.page_size))
if (params.after) url.searchParams.set('after', params.after)
return url.toString()
},
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
teams: data.teams ?? [],
pagination_meta: data.pagination_meta,
},
}
},
outputs: {
teams: {
type: 'array',
description: 'List of teams',
items: {
type: 'object',
properties: INCIDENTIO_TEAM_OUTPUT_PROPERTIES,
},
},
pagination_meta: {
type: 'object',
description: 'Pagination metadata',
optional: true,
properties: {
after: { type: 'string', description: 'Cursor for next page', optional: true },
page_size: { type: 'number', description: 'Number of results per page' },
},
},
},
}
+56
View File
@@ -0,0 +1,56 @@
import {
INCIDENTIO_TEAM_OUTPUT_PROPERTIES,
type IncidentioTeamsShowParams,
type IncidentioTeamsShowResponse,
} from '@/tools/incidentio/types'
import type { ToolConfig } from '@/tools/types'
export const teamsShowTool: ToolConfig<IncidentioTeamsShowParams, IncidentioTeamsShowResponse> = {
id: 'incidentio_teams_show',
name: 'Show Team',
description: 'Get a single team by ID from incident.io, along with its members',
version: '1.0.0',
params: {
apiKey: {
type: 'string',
required: true,
visibility: 'user-only',
description: 'incident.io API Key',
},
id: {
type: 'string',
required: true,
visibility: 'user-or-llm',
description: 'The ID of the team to fetch (e.g., "01JPQA75EPNEES4479P16P4XAB")',
},
},
request: {
url: (params) => `https://api.incident.io/v3/teams/${encodeURIComponent(params.id.trim())}`,
method: 'GET',
headers: (params) => ({
'Content-Type': 'application/json',
Authorization: `Bearer ${params.apiKey}`,
}),
},
transformResponse: async (response: Response) => {
const data = await response.json()
return {
success: true,
output: {
team: data.team,
},
}
},
outputs: {
team: {
type: 'object',
description: 'The team details',
properties: INCIDENTIO_TEAM_OUTPUT_PROPERTIES,
},
},
}
+806 -1
View File
@@ -291,8 +291,150 @@ export const INCIDENTIO_PAGINATION_OUTPUT_PROPERTIES = {
total_record_count: { type: 'number', description: 'Total number of records', optional: true },
} as const satisfies Record<string, OutputProperty>
/**
* Output definition for alert objects.
* @see https://docs.incident.io/api-reference
*/
export const INCIDENTIO_ALERT_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Alert ID' },
title: { type: 'string', description: 'Alert title, parsed from the alert payload' },
status: { type: 'string', description: 'Alert status (firing, resolved)' },
alert_source_id: { type: 'string', description: 'ID of the alert source this alert fired on' },
deduplication_key: {
type: 'string',
description: 'Key that uniquely references this alert from its source',
},
description: { type: 'string', description: 'Alert description', optional: true },
source_url: {
type: 'string',
description: 'Link to the alert in the upstream system',
optional: true,
},
resolved_at: { type: 'string', description: 'When this alert was resolved', optional: true },
created_at: { type: 'string', description: 'When this alert was created' },
updated_at: { type: 'string', description: 'When this alert was last updated' },
alert_group_ids: {
type: 'array',
description: 'IDs of every alert group this alert belongs to',
optional: true,
items: { type: 'string' },
},
attributes: {
type: 'array',
description: 'Attribute values parsed from the alert payload',
optional: true,
items: { type: 'object' },
},
} as const satisfies Record<string, OutputProperty>
/**
* Output definition for catalog type objects.
* @see https://docs.incident.io/api-reference
*/
export const INCIDENTIO_CATALOG_TYPE_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Catalog type ID' },
name: { type: 'string', description: 'Human readable name of this type' },
description: { type: 'string', description: 'Human readable description of this type' },
type_name: {
type: 'string',
description: 'Type name used when defining attributes (e.g., Custom["Service"])',
},
engine_resource_type: {
type: 'string',
description: 'How this resource type is referenced in the incident.io engine',
},
categories: {
type: 'array',
description: 'Categories this type is considered part of',
items: { type: 'string' },
},
color: { type: 'string', description: 'Display color of this type in the dashboard' },
icon: { type: 'string', description: 'Display icon of this type in the dashboard' },
ranked: { type: 'boolean', description: 'Whether entries of this type are ranked' },
is_editable: {
type: 'boolean',
description: 'Whether this type can be edited (types synced externally cannot)',
},
use_name_as_identifier: {
type: 'boolean',
description: 'Whether entries can be referenced by name as well as external ID',
},
estimated_count: {
type: 'number',
description: 'Estimated number of entries for this type',
optional: true,
},
is_team_type: {
type: 'boolean',
description: 'Whether this is the designated team type in team settings',
optional: true,
},
registry_type: {
type: 'string',
description: 'The registry resource this type is synced from, if any',
optional: true,
},
last_synced_at: { type: 'string', description: 'When this type was last synced', optional: true },
owning_team_ids: {
type: 'array',
description: 'IDs of the teams that own this catalog type',
optional: true,
items: { type: 'string' },
},
schema: {
type: 'object',
description: 'Attribute schema for this catalog type',
properties: {
version: { type: 'number', description: 'Version number of this schema' },
attributes: {
type: 'array',
description: 'Attributes of this catalog type',
items: { type: 'object' },
},
},
},
annotations: { type: 'json', description: 'Metadata annotations tracked about this type' },
created_at: { type: 'string', description: 'When this type was created' },
updated_at: { type: 'string', description: 'When this type was last updated' },
} as const satisfies Record<string, OutputProperty>
/**
* Output definition for team objects.
* @see https://docs.incident.io/api-reference
*/
export const INCIDENTIO_TEAM_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Team ID' },
name: { type: 'string', description: 'Team name' },
members: {
type: 'array',
description: 'Members of the team',
items: {
type: 'object',
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User display name' },
email: { type: 'string', description: 'User email address', optional: true },
slack_user_id: { type: 'string', description: 'Slack user ID', optional: true },
},
},
},
catalog_entry: {
type: 'object',
description: 'The catalog entry backing this team',
properties: {
id: { type: 'string', description: 'Catalog entry ID' },
name: { type: 'string', description: 'Catalog entry name' },
external_id: {
type: 'string',
description: 'Alternative ID for this entry, unique within the type',
optional: true,
},
},
},
} as const satisfies Record<string, OutputProperty>
// Common parameters for all incident.io tools
interface IncidentioBaseParams {
export interface IncidentioBaseParams {
apiKey: string
}
@@ -834,6 +976,25 @@ export type IncidentioResponse =
| IncidentioEscalationPathsShowResponse
| IncidentioEscalationPathsUpdateResponse
| IncidentioEscalationPathsDeleteResponse
| IncidentioOnCallNowResponse
| IncidentioScheduleOverridesListResponse
| IncidentioAlertsListResponse
| IncidentioAlertsShowResponse
| IncidentioAlertsResolveResponse
| IncidentioAlertEventsCreateResponse
| IncidentioIncidentAlertsListResponse
| IncidentioEscalationsCancelResponse
| IncidentioCatalogTypesListResponse
| IncidentioCatalogEntriesListResponse
| IncidentioTeamsListResponse
| IncidentioTeamsShowResponse
| IncidentioFollowUpsCreateResponse
| IncidentioFollowUpsUpdateResponse
| IncidentioActionsCreateResponse
| IncidentioActionsUpdateResponse
| IncidentioIncidentParticipantsListResponse
| IncidentioIncidentMembershipsCreateResponse
| IncidentioIncidentMembershipsRevokeResponse
// Escalations types
export interface IncidentioEscalationsListParams extends IncidentioBaseParams {
@@ -1264,3 +1425,647 @@ export interface IncidentioEscalationPathsDeleteResponse extends ToolResponse {
message: string
}
}
/**
* A user as returned on alerting, on-call, catalog, and team payloads, where the API
* documents `email`, `role`, and `slack_user_id` as optional.
* @see https://docs.incident.io/api-reference
*/
export interface IncidentioSlimUser {
id: string
name: string
email?: string
role?: string
slack_user_id?: string
}
/** Pagination envelope returned by incident.io list endpoints. */
export interface IncidentioPaginationMeta {
after?: string
page_size: number
total_record_count?: number
}
/**
* A single on-call shift, flattened from a schedule's `current_shifts` or `next_shifts`.
* @see https://docs.incident.io/api-reference
*/
export interface IncidentioOnCallShift {
schedule_id: string
schedule_name: string
schedule_timezone: string
schedule_permalink: string | null
entry_id: string | null
rotation_id: string | null
layer_id: string | null
start_at: string | null
end_at: string | null
user_id: string | null
user_name: string | null
user_email: string | null
user_slack_user_id: string | null
}
export interface IncidentioOnCallNowParams extends IncidentioBaseParams {
schedule_id?: string
page_size?: number
after?: string
}
export interface IncidentioOnCallNowResponse extends ToolResponse {
output: {
on_call: IncidentioOnCallShift[]
next_on_call: IncidentioOnCallShift[]
pagination_meta?: IncidentioPaginationMeta
}
}
/** A one-off change layered over a schedule's rotations, as the list endpoint returns it. */
export interface IncidentioScheduleOverrideRecord {
id: string
schedule_id: string
rotation_id: string
layer_id: string
start_at: string
end_at: string
created_at: string
updated_at: string
user?: IncidentioSlimUser
}
export interface IncidentioScheduleOverridesListParams extends IncidentioBaseParams {
schedule_id: string
rotation_id?: string
layer_id?: string
page_size?: number
after?: string
}
export interface IncidentioScheduleOverridesListResponse extends ToolResponse {
output: {
overrides: IncidentioScheduleOverrideRecord[]
pagination_meta?: IncidentioPaginationMeta
}
}
/** A single value on an alert attribute, either a literal or a catalog entry reference. */
export interface IncidentioAlertAttributeValue {
literal?: string
label?: string
catalog_entry?: {
id: string
name: string
catalog_type_id: string
}
}
/** An attribute value parsed from an alert's payload by its alert source config. */
export interface IncidentioAlertAttributeEntry {
attribute: {
id: string
name: string
type: string
array: boolean
required: boolean
emoji?: string
}
value?: IncidentioAlertAttributeValue
array_value?: IncidentioAlertAttributeValue[]
}
export interface IncidentioAlert {
id: string
title: string
status: string
alert_source_id: string
deduplication_key: string
created_at: string
updated_at: string
attributes: IncidentioAlertAttributeEntry[]
alert_group_ids?: string[]
description?: string
resolved_at?: string
source_url?: string
}
/** The alert shape returned on incident-alert connections, which omits `attributes`. */
export type IncidentioAlertSlim = Omit<IncidentioAlert, 'attributes'>
export interface IncidentioAlertsListParams extends IncidentioBaseParams {
page_size?: number
after?: string
status?: string
status_operator?: 'one_of' | 'not_in'
alert_source_id?: string
alert_source_operator?: 'one_of' | 'not_in'
deduplication_key?: string
created_at_gte?: string
created_at_lte?: string
has_notes?: boolean
include_maintenance_window?: boolean
}
export interface IncidentioAlertsListResponse extends ToolResponse {
output: {
alerts: IncidentioAlert[]
pagination_meta?: IncidentioPaginationMeta
}
}
export interface IncidentioAlertsShowParams extends IncidentioBaseParams {
id: string
}
export interface IncidentioAlertsShowResponse extends ToolResponse {
output: {
alert: IncidentioAlert
}
}
export interface IncidentioAlertsResolveParams extends IncidentioBaseParams {
id: string
}
export interface IncidentioAlertsResolveResponse extends ToolResponse {
output: {
alert: IncidentioAlert
}
}
/**
* Alert events authenticate with the token generated when configuring the HTTP alert source,
* not with the organisation API key, so these params deliberately do not extend the base params.
*/
export interface IncidentioAlertEventsCreateParams {
alert_source_config_id: string
alert_source_token: string
title: string
status: 'firing' | 'resolved'
description?: string
deduplication_key?: string
source_url?: string
metadata?: string
}
export interface IncidentioAlertEventsCreateResponse extends ToolResponse {
output: {
deduplication_key: string
message: string
status: string
}
}
/** The connection between an alert and the incident it was attached to. */
export interface IncidentioIncidentAlert {
id: string
alert: IncidentioAlertSlim
incident: {
id: string
name: string
reference: string
external_id: number
status_category: string
visibility: string
summary?: string
}
alert_route_id?: string
}
export interface IncidentioIncidentAlertsListParams extends IncidentioBaseParams {
page_size?: number
after?: string
alert_id?: string
incident_id?: string
}
export interface IncidentioIncidentAlertsListResponse extends ToolResponse {
output: {
incident_alerts: IncidentioIncidentAlert[]
pagination_meta?: IncidentioPaginationMeta
}
}
export interface IncidentioEscalationsCancelParams extends IncidentioBaseParams {
id: string
}
export interface IncidentioEscalationsCancelResponse extends ToolResponse {
output: {
message: string
}
}
/** A catalog type, describing the schema shared by all entries of that type. */
export interface IncidentioCatalogType {
id: string
name: string
description: string
type_name: string
engine_resource_type: string
categories: string[]
color: string
icon: string
ranked: boolean
is_editable: boolean
use_name_as_identifier: boolean
created_at: string
updated_at: string
annotations: Record<string, string>
schema: {
version: number
attributes: Array<{
id: string
name: string
type: string
array: boolean
mode: string
}>
}
estimated_count?: number
is_team_type?: boolean
last_synced_at?: string
owning_team_ids?: string[]
registry_type?: string
required_integrations?: string[]
source_repo_url?: string
dynamic_resource_parameter?: string
}
export interface IncidentioCatalogTypesListParams extends IncidentioBaseParams {}
export interface IncidentioCatalogTypesListResponse extends ToolResponse {
output: {
catalog_types: IncidentioCatalogType[]
}
}
/** A single entry of a catalog type, such as one service or one team. */
export interface IncidentioCatalogEntry {
id: string
name: string
catalog_type_id: string
aliases: string[]
rank: number
attribute_values: Record<string, unknown>
created_at: string
updated_at: string
external_id?: string
archived_at?: string
}
export interface IncidentioCatalogEntriesListParams extends IncidentioBaseParams {
catalog_type_id: string
page_size?: number
after?: string
identifier?: string
}
export interface IncidentioCatalogEntriesListResponse extends ToolResponse {
output: {
catalog_entries: IncidentioCatalogEntry[]
catalog_type: IncidentioCatalogType | null
pagination_meta?: IncidentioPaginationMeta
}
}
export interface IncidentioTeam {
id: string
name: string
members: IncidentioSlimUser[]
catalog_entry: {
id: string
name: string
external_id?: string
}
}
export interface IncidentioTeamsListParams extends IncidentioBaseParams {
page_size?: number
after?: string
}
export interface IncidentioTeamsListResponse extends ToolResponse {
output: {
teams: IncidentioTeam[]
pagination_meta?: IncidentioPaginationMeta
}
}
export interface IncidentioTeamsShowParams extends IncidentioBaseParams {
id: string
}
export interface IncidentioTeamsShowResponse extends ToolResponse {
output: {
team: IncidentioTeam
}
}
/**
* Output definition for the actor envelope. Unlike a plain user, exactly one of these keys is
* populated depending on what caused the change.
*/
const INCIDENTIO_ACTOR_OUTPUT_PROPERTIES = {
user: {
type: 'object',
description: 'The user who caused this, if a person did',
optional: true,
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User display name' },
email: { type: 'string', description: 'User email address', optional: true },
role: { type: 'string', description: 'User role', optional: true },
slack_user_id: { type: 'string', description: 'Slack user ID', optional: true },
},
},
api_key: {
type: 'object',
description: 'The API key that caused this, if an integration did',
optional: true,
properties: {
id: { type: 'string', description: 'API key ID' },
name: { type: 'string', description: 'API key name' },
},
},
workflow: {
type: 'object',
description: 'The incident.io workflow that caused this, if automation did',
optional: true,
properties: {
id: { type: 'string', description: 'Workflow ID' },
name: { type: 'string', description: 'Workflow name' },
},
},
alert: {
type: 'object',
description: 'The alert that caused this, if an alert did',
optional: true,
properties: {
id: { type: 'string', description: 'Alert ID' },
title: { type: 'string', description: 'Alert title' },
},
},
} as const satisfies Record<string, OutputProperty>
const INCIDENTIO_EXTERNAL_ISSUE_REFERENCE_OUTPUT: OutputProperty = {
type: 'object',
description: 'The external issue this was exported to',
optional: true,
properties: {
provider: { type: 'string', description: 'Issue tracker provider' },
issue_name: { type: 'string', description: 'Human readable issue ID' },
issue_permalink: { type: 'string', description: 'Link to the issue in the tracker' },
},
}
const INCIDENTIO_ASSIGNEE_OUTPUT: OutputProperty = {
type: 'object',
description: 'The assigned user',
optional: true,
properties: {
id: { type: 'string', description: 'User ID' },
name: { type: 'string', description: 'User display name' },
email: { type: 'string', description: 'User email address', optional: true },
role: { type: 'string', description: 'User role', optional: true },
slack_user_id: { type: 'string', description: 'Slack user ID', optional: true },
},
}
/**
* Output definition for a follow-up exactly as the API returns it, including the fields the
* legacy list/show tools drop.
*/
export const INCIDENTIO_FOLLOW_UP_RECORD_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Follow-up ID' },
incident_id: { type: 'string', description: 'ID of the incident the follow-up belongs to' },
title: { type: 'string', description: 'Follow-up title' },
status: {
type: 'string',
description: 'Follow-up status (outstanding, completed, deleted, not_doing)',
},
description: { type: 'string', description: 'Follow-up description', optional: true },
labels: {
type: 'array',
description: 'Labels associated with this follow-up',
items: { type: 'string' },
},
assignee: INCIDENTIO_ASSIGNEE_OUTPUT,
assignee_team: {
type: 'object',
description: 'The team the follow-up is assigned to',
optional: true,
properties: {
id: { type: 'string', description: 'Team ID' },
name: { type: 'string', description: 'Team name' },
},
},
priority: {
type: 'object',
description: 'Follow-up priority',
optional: true,
properties: {
id: { type: 'string', description: 'Priority ID' },
name: { type: 'string', description: 'Priority name' },
rank: { type: 'number', description: 'Priority rank' },
description: { type: 'string', description: 'Priority description', optional: true },
},
},
external_issue_reference: INCIDENTIO_EXTERNAL_ISSUE_REFERENCE_OUTPUT,
creator: {
type: 'object',
description: 'Who created the follow-up',
properties: INCIDENTIO_ACTOR_OUTPUT_PROPERTIES,
},
completed_at: {
type: 'string',
description: 'When the follow-up was completed',
optional: true,
},
created_at: { type: 'string', description: 'When the follow-up was created' },
updated_at: { type: 'string', description: 'When the follow-up was last updated' },
} as const satisfies Record<string, OutputProperty>
/**
* Output definition for an action exactly as the API returns it, including the fields the legacy
* list/show tools drop.
*/
export const INCIDENTIO_ACTION_RECORD_OUTPUT_PROPERTIES = {
id: { type: 'string', description: 'Action ID' },
incident_id: { type: 'string', description: 'ID of the incident the action belongs to' },
description: { type: 'string', description: 'Action description' },
status: {
type: 'string',
description: 'Action status (outstanding, completed, deleted, not_doing)',
},
assignee: INCIDENTIO_ASSIGNEE_OUTPUT,
external_issue_reference: INCIDENTIO_EXTERNAL_ISSUE_REFERENCE_OUTPUT,
creator: {
type: 'object',
description: 'Who created the action',
properties: INCIDENTIO_ACTOR_OUTPUT_PROPERTIES,
},
completed_at: { type: 'string', description: 'When the action was completed', optional: true },
created_at: { type: 'string', description: 'When the action was created' },
updated_at: { type: 'string', description: 'When the action was last updated' },
} as const satisfies Record<string, OutputProperty>
/**
* Whoever caused something to happen. Exactly one of these is populated, so consumers should
* check each in turn rather than assuming a user.
*/
export interface IncidentioActor {
user?: IncidentioSlimUser
api_key?: { id: string; name: string }
workflow?: { id: string; name: string }
alert?: { id: string; title: string }
}
/** A reference to the issue an action or follow-up was exported to. */
export interface IncidentioExternalIssueReference {
provider: string
issue_name: string
issue_permalink: string
}
/** A follow-up exactly as the incident.io API returns it. */
export interface IncidentioFollowUpRecord {
id: string
incident_id: string
title: string
status: string
labels: string[]
creator: IncidentioActor
created_at: string
updated_at: string
description?: string
completed_at?: string
assignee?: IncidentioSlimUser
assignee_team?: { id: string; name: string }
priority?: {
id: string
name: string
rank: number
description?: string
}
external_issue_reference?: IncidentioExternalIssueReference
}
/** An action exactly as the incident.io API returns it. */
export interface IncidentioActionRecord {
id: string
incident_id: string
description: string
status: string
creator: IncidentioActor
created_at: string
updated_at: string
completed_at?: string
assignee?: IncidentioSlimUser
external_issue_reference?: IncidentioExternalIssueReference
}
export interface IncidentioFollowUpsCreateParams extends IncidentioBaseParams {
incident_id: string
title: string
description?: string
assignee_id?: string
assignee_team_id?: string
follow_up_category_id?: string
follow_up_priority_option_id?: string
external_issue_reference_id?: string
labels?: string
}
export interface IncidentioFollowUpsCreateResponse extends ToolResponse {
output: {
follow_up: IncidentioFollowUpRecord
}
}
export interface IncidentioFollowUpsUpdateParams extends IncidentioBaseParams {
id: string
title: string
status: 'outstanding' | 'completed' | 'not_doing'
description?: string
assignee_id?: string
assignee_team_id?: string
follow_up_category_id?: string
follow_up_priority_option_id?: string
labels?: string
}
export interface IncidentioFollowUpsUpdateResponse extends ToolResponse {
output: {
follow_up: IncidentioFollowUpRecord
}
}
export interface IncidentioActionsCreateParams extends IncidentioBaseParams {
incident_id: string
description: string
assignee_id?: string
}
export interface IncidentioActionsCreateResponse extends ToolResponse {
output: {
action: IncidentioActionRecord
}
}
export interface IncidentioActionsUpdateParams extends IncidentioBaseParams {
id: string
description: string
status: 'outstanding' | 'completed' | 'not_doing'
assignee_id?: string
}
export interface IncidentioActionsUpdateResponse extends ToolResponse {
output: {
action: IncidentioActionRecord
}
}
/** A person who took part in an incident, annotated with how they participated. */
export interface IncidentioIncidentParticipant {
participant_type: string
user: IncidentioSlimUser
}
export interface IncidentioIncidentParticipantsListParams extends IncidentioBaseParams {
incident_id: string
}
export interface IncidentioIncidentParticipantsListResponse extends ToolResponse {
output: {
active: IncidentioIncidentParticipant[]
passive: IncidentioIncidentParticipant[]
}
}
export interface IncidentioIncidentMembershipsCreateParams extends IncidentioBaseParams {
incident_id: string
user_id: string
}
export interface IncidentioIncidentMembershipsCreateResponse extends ToolResponse {
output: {
incident_membership: {
id: string
incident_id: string
created_at: string
updated_at: string
user: IncidentioSlimUser
}
}
}
export interface IncidentioIncidentMembershipsRevokeParams extends IncidentioBaseParams {
incident_id: string
user_id: string
}
export interface IncidentioIncidentMembershipsRevokeResponse extends ToolResponse {
output: {
message: string
}
}
+38
View File
@@ -1937,8 +1937,16 @@ import {
} from '@/tools/identity_center'
import { imageGenerateTool } from '@/tools/image'
import {
incidentioActionsCreateTool,
incidentioActionsListTool,
incidentioActionsShowTool,
incidentioActionsUpdateTool,
incidentioAlertEventsCreateTool,
incidentioAlertsListTool,
incidentioAlertsResolveTool,
incidentioAlertsShowTool,
incidentioCatalogEntriesListTool,
incidentioCatalogTypesListTool,
incidentioCustomFieldsCreateTool,
incidentioCustomFieldsDeleteTool,
incidentioCustomFieldsListTool,
@@ -1949,11 +1957,18 @@ import {
incidentioEscalationPathsListTool,
incidentioEscalationPathsShowTool,
incidentioEscalationPathsUpdateTool,
incidentioEscalationsCancelTool,
incidentioEscalationsCreateTool,
incidentioEscalationsListTool,
incidentioEscalationsShowTool,
incidentioFollowUpsCreateTool,
incidentioFollowUpsListTool,
incidentioFollowUpsShowTool,
incidentioFollowUpsUpdateTool,
incidentioIncidentAlertsListTool,
incidentioIncidentMembershipsCreateTool,
incidentioIncidentMembershipsRevokeTool,
incidentioIncidentParticipantsListTool,
incidentioIncidentRolesCreateTool,
incidentioIncidentRolesDeleteTool,
incidentioIncidentRolesListTool,
@@ -1968,14 +1983,18 @@ import {
incidentioIncidentTimestampsShowTool,
incidentioIncidentTypesListTool,
incidentioIncidentUpdatesListTool,
incidentioOnCallNowTool,
incidentioScheduleEntriesListTool,
incidentioScheduleOverridesCreateTool,
incidentioScheduleOverridesListTool,
incidentioSchedulesCreateTool,
incidentioSchedulesDeleteTool,
incidentioSchedulesListTool,
incidentioSchedulesShowTool,
incidentioSchedulesUpdateTool,
incidentioSeveritiesListTool,
incidentioTeamsListTool,
incidentioTeamsShowTool,
incidentioUsersListTool,
incidentioUsersShowTool,
incidentioWorkflowsCreateTool,
@@ -8780,6 +8799,25 @@ export const tools: Record<string, ToolConfig> = {
incidentio_incidents_update: incidentioIncidentsUpdateTool,
incidentio_actions_list: incidentioActionsListTool,
incidentio_actions_show: incidentioActionsShowTool,
incidentio_actions_create: incidentioActionsCreateTool,
incidentio_actions_update: incidentioActionsUpdateTool,
incidentio_alerts_list: incidentioAlertsListTool,
incidentio_alerts_show: incidentioAlertsShowTool,
incidentio_alerts_resolve: incidentioAlertsResolveTool,
incidentio_alert_events_create: incidentioAlertEventsCreateTool,
incidentio_incident_alerts_list: incidentioIncidentAlertsListTool,
incidentio_on_call_now: incidentioOnCallNowTool,
incidentio_schedule_overrides_list: incidentioScheduleOverridesListTool,
incidentio_escalations_cancel: incidentioEscalationsCancelTool,
incidentio_catalog_types_list: incidentioCatalogTypesListTool,
incidentio_catalog_entries_list: incidentioCatalogEntriesListTool,
incidentio_teams_list: incidentioTeamsListTool,
incidentio_teams_show: incidentioTeamsShowTool,
incidentio_follow_ups_create: incidentioFollowUpsCreateTool,
incidentio_follow_ups_update: incidentioFollowUpsUpdateTool,
incidentio_incident_participants_list: incidentioIncidentParticipantsListTool,
incidentio_incident_memberships_create: incidentioIncidentMembershipsCreateTool,
incidentio_incident_memberships_revoke: incidentioIncidentMembershipsRevokeTool,
incidentio_custom_fields_create: incidentioCustomFieldsCreateTool,
incidentio_custom_fields_delete: incidentioCustomFieldsDeleteTool,
incidentio_follow_ups_list: incidentioFollowUpsListTool,