Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,6 @@ dmypy.json

/coverage.xml
/.coverage

# Serena
.serena/
26 changes: 26 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [1.4.0] - 2026-07-20

### Added
- New AI Chat endpoints (create, stream, list session messages, delete session)
- New Shift Coverage Requests endpoints (create, read, delete, list)
- New Workflow Action Item Form Field Conditions endpoints (create, read, update, delete, list)
- Bulk operations for catalog entities, environments, functionalities, services, and teams (bulk upsert and bulk delete)
- New Meeting Recordings actions: import, delete standalone, start recording session, list all
- Alert escalation and snooze actions (`escalate_alert`, `snooze_alert`)
- Alert receipt endpoint (`get_receipt`)
- Alert events feed endpoint (`list_alert_events_feed`)
- New Google Chat workflow task types: create/rename/archive spaces, change space privacy, update space description, invite to space, send messages and attachments
- New workflow task type: `InviteToMicrosoftTeamsChannelRootlyTaskParams` — invite users to Microsoft Teams channels via Rootly
- New workflow task type: `AttachRetrospectivePdfToJiraIssueTaskParams` — attach retrospective PDFs to Jira issues
- Edge connector filters support (`CreateEdgeConnectorBodyDataAttributesFilters`)
- `owner_group_ids` field on heartbeat, alerts source, functionality, and schedule models for team-scoped API key support
- GitHub issue task params: labels mode support (`update_github_issue_task_params_labels_mode`)

### Changed
- Regenerated client from latest OpenAPI specification
- httpx minimum version bumped from `>=0.20.0` to `>=0.23.0`
- 428 new model files, 28 removed models (consolidated upstream)

### Fixed
- Applied nullable enum fix to all model files via `tools/fix_nullable_enums.py`

## [1.3.0] - 2026-04-21

### Added
Expand Down
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,10 @@ regenerate:
--config tools/config.yaml
@echo "Applying nullable enum fix..."
@python tools/fix_nullable_enums.py
@echo "Fixing lint errors..."
@ruff check --fix rootly_sdk/
@echo "Formatting patched files..."
@ruff format rootly_sdk/models/
@ruff format rootly_sdk/

test:
python -c "import rootly_sdk; print('SDK imports successfully')"
7 changes: 2 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "rootly"
version = "1.3.0"
version = "1.4.0"
description = "A client library for accessing Rootly API v1"
authors = []
readme = "README.md"
Expand All @@ -11,13 +11,10 @@ include = ["CHANGELOG.md", "rootly_sdk/py.typed"]

[tool.poetry.dependencies]
python = "^3.10"
httpx = ">=0.20.0,<0.29.0"
httpx = ">=0.23.0,<0.29.0"
attrs = ">=22.2.0"
python-dateutil = "^2.8.0"

[tool.poetry.group.dev.dependencies]
ruff = ">=0.15.0"

[build-system]
requires = ["poetry-core>=2.0.0,<3.0.0"]
build-backend = "poetry.core.masonry.api"
Expand Down
1 change: 1 addition & 0 deletions rootly_sdk/api/ai_chat/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Contains endpoint functions for accessing the API"""
237 changes: 237 additions & 0 deletions rootly_sdk/api/ai_chat/create_ai_chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
from http import HTTPStatus
from typing import Any, cast
from uuid import UUID

import httpx

from ... import errors
from ...client import AuthenticatedClient, Client
from ...models.ai_chat_response import AiChatResponse
from ...types import UNSET, Response, Unset


def _get_kwargs(
*,
message: str,
session_id: UUID | Unset = UNSET,
incident_id: UUID | Unset = UNSET,
alert_id: UUID | Unset = UNSET,
) -> dict[str, Any]:

params: dict[str, Any] = {}

params["message"] = message

json_session_id: str | Unset = UNSET
if not isinstance(session_id, Unset):
json_session_id = str(session_id)
params["session_id"] = json_session_id

json_incident_id: str | Unset = UNSET
if not isinstance(incident_id, Unset):
json_incident_id = str(incident_id)
params["incident_id"] = json_incident_id

json_alert_id: str | Unset = UNSET
if not isinstance(alert_id, Unset):
json_alert_id = str(alert_id)
params["alert_id"] = json_alert_id

params = {k: v for k, v in params.items() if v is not UNSET and v is not None}

_kwargs: dict[str, Any] = {
"method": "post",
"url": "/v1/ai/chat",
"params": params,
}

return _kwargs


def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AiChatResponse | Any | None:
if response.status_code == 200:
response_200 = AiChatResponse.from_dict(response.json())

return response_200

if response.status_code == 403:
response_403 = cast(Any, None)
return response_403

if response.status_code == 422:
response_422 = cast(Any, None)
return response_422

if client.raise_on_unexpected_status:
raise errors.UnexpectedStatus(response.status_code, response.content)
else:
return None


def _build_response(
*, client: AuthenticatedClient | Client, response: httpx.Response
) -> Response[AiChatResponse | Any]:
return Response(
status_code=HTTPStatus(response.status_code),
content=response.content,
headers=response.headers,
parsed=_parse_response(client=client, response=response),
)


def sync_detailed(
*,
client: AuthenticatedClient,
message: str,
session_id: UUID | Unset = UNSET,
incident_id: UUID | Unset = UNSET,
alert_id: UUID | Unset = UNSET,
) -> Response[AiChatResponse | Any]:
"""Send AI chat message

Send a message to the AI assistant and receive a synchronous reply. Optionally bind the conversation
to an incident or alert for context-aware responses. Requires `ai.chat:write` OAuth scope or an API
key.

Args:
message (str):
session_id (UUID | Unset):
incident_id (UUID | Unset):
alert_id (UUID | Unset):

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.

Returns:
Response[AiChatResponse | Any]
"""

kwargs = _get_kwargs(
message=message,
session_id=session_id,
incident_id=incident_id,
alert_id=alert_id,
)

response = client.get_httpx_client().request(
**kwargs,
)

return _build_response(client=client, response=response)


def sync(
*,
client: AuthenticatedClient,
message: str,
session_id: UUID | Unset = UNSET,
incident_id: UUID | Unset = UNSET,
alert_id: UUID | Unset = UNSET,
) -> AiChatResponse | Any | None:
"""Send AI chat message

Send a message to the AI assistant and receive a synchronous reply. Optionally bind the conversation
to an incident or alert for context-aware responses. Requires `ai.chat:write` OAuth scope or an API
key.

Args:
message (str):
session_id (UUID | Unset):
incident_id (UUID | Unset):
alert_id (UUID | Unset):

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.

Returns:
AiChatResponse | Any
"""

return sync_detailed(
client=client,
message=message,
session_id=session_id,
incident_id=incident_id,
alert_id=alert_id,
).parsed


async def asyncio_detailed(
*,
client: AuthenticatedClient,
message: str,
session_id: UUID | Unset = UNSET,
incident_id: UUID | Unset = UNSET,
alert_id: UUID | Unset = UNSET,
) -> Response[AiChatResponse | Any]:
"""Send AI chat message

Send a message to the AI assistant and receive a synchronous reply. Optionally bind the conversation
to an incident or alert for context-aware responses. Requires `ai.chat:write` OAuth scope or an API
key.

Args:
message (str):
session_id (UUID | Unset):
incident_id (UUID | Unset):
alert_id (UUID | Unset):

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.

Returns:
Response[AiChatResponse | Any]
"""

kwargs = _get_kwargs(
message=message,
session_id=session_id,
incident_id=incident_id,
alert_id=alert_id,
)

response = await client.get_async_httpx_client().request(**kwargs)

return _build_response(client=client, response=response)


async def asyncio(
*,
client: AuthenticatedClient,
message: str,
session_id: UUID | Unset = UNSET,
incident_id: UUID | Unset = UNSET,
alert_id: UUID | Unset = UNSET,
) -> AiChatResponse | Any | None:
"""Send AI chat message

Send a message to the AI assistant and receive a synchronous reply. Optionally bind the conversation
to an incident or alert for context-aware responses. Requires `ai.chat:write` OAuth scope or an API
key.

Args:
message (str):
session_id (UUID | Unset):
incident_id (UUID | Unset):
alert_id (UUID | Unset):

Raises:
errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
httpx.TimeoutException: If the request takes longer than Client.timeout.

Returns:
AiChatResponse | Any
"""

return (
await asyncio_detailed(
client=client,
message=message,
session_id=session_id,
incident_id=incident_id,
alert_id=alert_id,
)
).parsed
Loading