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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

Please refer to individual package changelogs:

* [`automa-bot`](./packages/bot/CHANGELOG.md)
- [`automa-bot`](./packages/bot/CHANGELOG.md)
35 changes: 35 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# How to Contribute

## Prerequisites

- Have [`git`](https://git-scm.com/) installed.
- Have [`uv`](https://docs.astral.sh/uv/) installed.

## Installing dependencies

```sh
uv sync
```

## CI/CD

#### Testing

In each package, you can run tests using:

```sh
export PYTHON_ENV=test
uv run pytest
```

#### Linting

```sh
uv run ruff check
```

#### Formatting

```sh
uv run ruff format
```
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2025 Sunkara, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
20 changes: 19 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
# sdk-python

Automa SDK for Python
Automa SDKs for Python.

Please refer to individual package documentation:

- [`automa-bot`](./packages/bot)

Please refer to the [Automa documentation](https://docs.automa.app/sdks) for more information on how to use these SDKs.

## Contributing

Contributions and feedback are welcome! Feel free to open an issue or submit a pull request. See [CONTRIBUTING.md](CONTRIBUTING.md) for more details. Here is a list of [Contributors](https://github.com/automa/sdk-python/contributors).

## LICENSE

MIT

## Bug Reports

Report [here](https://github.com/automa/sdk-python/issues).
220 changes: 219 additions & 1 deletion packages/bot/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,221 @@
# automa-bot

Bot helpers for Automa
Bot SDK for Automa.

Please read more about Automa [Bots](https://docs.automa.app/bots) and their [development](https://docs.automa.app/bot-development) in our documentation.

1. [Installation](#installation)
2. [Usage](#usage)
3. [Webhook signatures](#webhook-signatures)
4. [Testing](#testing)
5. [Reference](#reference)

## Installation

```sh
# Using pip
pip install automa-bot

# Using uv
uv add automa-bot
```

## Usage

```python
from automa import Automa

client = Automa()

def main():
# Download code for a task
folder = client.code.download({
"task": {
"id": 10,
"token": '3ee12f8ca60132c087c6303efb46c3b5',
},
})

# Change code in the folder ...

# Propose the changed code
client.code.propose({
"task": { "id": 10 },
})

# Remove the downloaded code folder
client.code.cleanup({
"task": { "id": 10 },
})

main()
```

### Asynchronous

Simply import `AsyncAutoma` instead of `Automa` and use `await` with each method call:

```python
import asyncio
from automa import AsyncAutoma

client = AsyncAutoma()

async def main() -> None:
# Download code for a task
folder = await client.code.download({
"task": {
"id": 10,
"token": '3ee12f8ca60132c087c6303efb46c3b5',
},
})

# Change code in the folder ...

# Propose the changed code
await client.code.propose({
"task": { "id": 10 },
})

# Remove the downloaded code folder
await client.code.cleanup({
"task": { "id": 10 },
})

asyncio.run(main())
```

Functionality between the synchronous and asynchronous clients is otherwise identical.

### Managing client resource

By default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.

```py
from automa import Automa

with Automa() as client:
# make requests here
...

# HTTP client is now closed
```

## Webhook signatures

To verify webhook signatures, you can use the `verify_webhook` helper provided by the SDK.

```python
import os
from automa.bot.webhook import verify_webhook

payload = (await request.body()).decode("utf-8") # The body of the webhook request
signature = request.headers.get('webhook-signature') # The signature header from the request

is_valid = verify_webhook(
os.environ['AUTOMA_WEBHOOK_SECRET'],
signature,
payload
)
```

## Testing

When writing tests for your bot, you can mock the client methods to simulate the behavior of the SDK without making actual network requests.

```python
from automa.bot import CodeFolder

fixture_code = CodeFolder("." / "fixtures" / "code")

@patch("automa.bot.AsyncCodeResource.cleanup")
@patch("automa.bot.AsyncCodeResource.propose")
@patch("automa.bot.AsyncCodeResource.download", return_value=fixture_code)
def test(download_mock, propose_mock, cleanup_mock):
pass
```

### Webhook signatures in tests

When testing webhook handling, you may want to simulate valid webhook requests. The SDK provides `generate_webhook_signature` helper to generate valid signatures for your test payloads.

```python
import os
from automa.bot.webhook import generate_webhook_signature

payload = '{}' # Example payload

signature = generate_webhook_signature(
os.environ['AUTOMA_WEBHOOK_SECRET'],
payload
)

# Use this signature in your tests to simulate a valid webhook request
```

## Reference

Please find below the reference for both the client and its methods in the SDK.

All methods are available in both synchronous and asynchronous clients.

### `Automa`/`AsyncAutoma`

Named parameters:

- `base_url` (optional): Base URL for the Automa API. Defaults to `https://api.automa.app`.

If you are using the bot with a self-hosted instance of Automa, you can specify the base URL like this:

```python
client = Automa(base_url="https://api.your-automa-instance.com")
```

Properties:

- `code`: `CodeResource` / `AsyncCodeResource` providing code related methods.

### `code.download`

Downloads the code for the specified task and returns a [`CodeFolder`](#codefolder) pointing to the cloned or extracted code directory.

Parameters:

- `body` (`CodeDownloadParams`)
- `task` (dict)
- `id` (int): The identifier of the task.
- `token` (str): The authorization token for the task sent in webhook request.

### `code.propose`

Submits a code change proposal for the specified task, using the diff between the current working directory and the base commit saved on download.

Parameters:

- `body` (`CodeProposeParams`)
- `task` (dict)
- `id` (int): The identifier of the task.
- `proposal` (dict, optional)
- `title` (str): Title of the pull request for the proposal.
- `body` (str): Description of the pull request for the proposal.
- `metadata` (dict, optional)
- `cost` (float): Cost incurred for implementing the task.

### `code.cleanup`

Removes any downloaded code folder and its archive for the specified task.

Parameters:

- `body` (`CodeCleanupParams`)
- `task` (dict)
- `id` (int): The identifier of the task.

### `CodeFolder`

Represents a folder containing the downloaded code for a task. It provides some helper methods to build the code proposal.

Methods:

- `add(paths: str | list[str])`: Add the specified new file(s) to the code proposal.
- `add_all()`: Add all new files to the code proposal.
2 changes: 1 addition & 1 deletion packages/bot/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "automa-bot"
version = "0.3.0"

authors = [{ name = "Sunkara, Inc.", email = "engineering@automa.app" }]
description = "Bot helpers for Automa"
description = "Bot SDK for Automa"
license = "MIT"
readme = "README.md"
requires-python = ">=3.11"
Expand Down