sprites-adk 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sprites_adk-0.1.0/.github/workflows/publish.yml +44 -0
- sprites_adk-0.1.0/.gitignore +7 -0
- sprites_adk-0.1.0/LICENSE +21 -0
- sprites_adk-0.1.0/PKG-INFO +144 -0
- sprites_adk-0.1.0/README.md +116 -0
- sprites_adk-0.1.0/docs/adk-docs-page/README.md +16 -0
- sprites_adk-0.1.0/docs/adk-docs-page/sprites.md +79 -0
- sprites_adk-0.1.0/examples/checkpoint_rollback.py +62 -0
- sprites_adk-0.1.0/examples/persistent_environment.py +61 -0
- sprites_adk-0.1.0/examples/quickstart.py +31 -0
- sprites_adk-0.1.0/pyproject.toml +40 -0
- sprites_adk-0.1.0/sprites_adk/__init__.py +30 -0
- sprites_adk-0.1.0/sprites_adk/plugin.py +187 -0
- sprites_adk-0.1.0/sprites_adk/tools.py +483 -0
- sprites_adk-0.1.0/tests/test_tools.py +365 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v[0-9]+.[0-9]+.[0-9]+'
|
|
7
|
+
- 'v[0-9]+.[0-9]+.[0-9]+-*'
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
publish:
|
|
11
|
+
name: Build and publish to PyPI
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
permissions:
|
|
14
|
+
id-token: write
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout code
|
|
17
|
+
uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- name: Set up Python
|
|
20
|
+
uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: '3.11'
|
|
23
|
+
|
|
24
|
+
- name: Update version
|
|
25
|
+
run: |
|
|
26
|
+
# Strip 'v' prefix from tag
|
|
27
|
+
VERSION="${GITHUB_REF_NAME#v}"
|
|
28
|
+
echo "Publishing version: ${VERSION}"
|
|
29
|
+
# Update pyproject.toml
|
|
30
|
+
sed -i "s/^version = \".*\"/version = \"${VERSION}\"/" pyproject.toml
|
|
31
|
+
# Update __version__ in the package
|
|
32
|
+
sed -i "s/__version__ = \".*\"/__version__ = \"${VERSION}\"/" sprites_adk/__init__.py
|
|
33
|
+
|
|
34
|
+
- name: Install and test
|
|
35
|
+
run: |
|
|
36
|
+
python -m pip install --upgrade pip
|
|
37
|
+
pip install '.[dev]' build
|
|
38
|
+
pytest -q
|
|
39
|
+
|
|
40
|
+
- name: Build package
|
|
41
|
+
run: python -m build
|
|
42
|
+
|
|
43
|
+
- name: Publish to PyPI
|
|
44
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fly.io
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: sprites-adk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Google ADK plugin for Sprites: persistent, stateful Linux sandboxes with checkpoint/restore for AI agents.
|
|
5
|
+
Project-URL: Homepage, https://sprites.dev
|
|
6
|
+
Project-URL: Documentation, https://docs.sprites.dev
|
|
7
|
+
Project-URL: Repository, https://github.com/superfly/sprites-adk
|
|
8
|
+
Author: Fly.io
|
|
9
|
+
License: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: adk,agents,code-execution,fly.io,google-adk,sandbox,sprites
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Requires-Python: >=3.9
|
|
23
|
+
Requires-Dist: google-adk>=1.0.0
|
|
24
|
+
Requires-Dist: sprites-py>=0.2.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# sprites-adk
|
|
30
|
+
|
|
31
|
+
Google [ADK](https://google.github.io/adk-docs/) integration for [Sprites](https://sprites.dev) — persistent, stateful Linux sandboxes for AI agents, with checkpoint/restore, from [Fly.io](https://fly.io).
|
|
32
|
+
|
|
33
|
+
Most agent sandboxes are ephemeral: the environment vanishes when the session ends. A Sprite is a **stateful Linux microVM** that suspends when idle and keeps everything — files, packages, databases, running services — so your agent can resume yesterday's environment today. And because Sprites support **checkpoints**, your agent can snapshot the whole environment before a risky change and roll back if it goes wrong.
|
|
34
|
+
|
|
35
|
+
## Installation
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
pip install sprites-adk
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
You'll need a Sprites API token ([get started](https://docs.sprites.dev/quickstart/)):
|
|
42
|
+
|
|
43
|
+
```sh
|
|
44
|
+
export SPRITES_TOKEN=...
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from google.adk.agents import Agent
|
|
51
|
+
from sprites_adk import SpritesPlugin
|
|
52
|
+
|
|
53
|
+
plugin = SpritesPlugin() # or SpritesPlugin(sprite_name="my-project") for a persistent env
|
|
54
|
+
|
|
55
|
+
root_agent = Agent(
|
|
56
|
+
model="gemini-flash-latest",
|
|
57
|
+
name="sprite_agent",
|
|
58
|
+
instruction="Run code and commands in the Sprite sandbox, not locally.",
|
|
59
|
+
tools=plugin.get_tools(),
|
|
60
|
+
)
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Pass the plugin to your runner to get lifecycle callbacks and error handling:
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
runner = InMemoryRunner(agent=root_agent, plugins=[plugin])
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Two modes
|
|
70
|
+
|
|
71
|
+
| | `SpritesPlugin()` | `SpritesPlugin(sprite_name="my-project")` |
|
|
72
|
+
|---|---|---|
|
|
73
|
+
| Sprite name | auto-generated `adk-…` | yours |
|
|
74
|
+
| Reused across sessions | no | **yes — full state persists** |
|
|
75
|
+
| Destroyed on `plugin.close()` | yes | no |
|
|
76
|
+
|
|
77
|
+
The Sprite is created lazily on first tool use; constructing the agent needs no network. Sprites suspend automatically when idle — a parked environment costs (almost) nothing.
|
|
78
|
+
|
|
79
|
+
## Tools
|
|
80
|
+
|
|
81
|
+
| Tool | Description |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `execute_command_in_sprite` | Run a shell command (cwd, timeout supported) |
|
|
84
|
+
| `execute_code_in_sprite` | Run a Python / JavaScript / bash snippet |
|
|
85
|
+
| `write_file_to_sprite` | Write a text file (parents auto-created) |
|
|
86
|
+
| `read_file_from_sprite` | Read a text file |
|
|
87
|
+
| `create_sprite_checkpoint` | Snapshot the entire environment |
|
|
88
|
+
| `list_sprite_checkpoints` | List checkpoints, newest first |
|
|
89
|
+
| `restore_sprite_checkpoint` | Roll back to a checkpoint (**destructive**, requires `confirm=true`) |
|
|
90
|
+
|
|
91
|
+
All tools return structured dicts (`success`, `stdout`/`stderr`/`exit_code`, …); failures come back as `{"success": false, "error": ...}` so the agent can adapt instead of crashing the run.
|
|
92
|
+
|
|
93
|
+
File reads and writes run as commands inside the Sprite (via `base64`, so quotes/newlines/unicode survive) rather than through a separate filesystem API. That keeps them consistent with everything else the agent does — in particular, files written this way are correctly reverted by `restore_sprite_checkpoint`. `write_file_to_sprite` is capped at 256 KB; generate larger files with a command inside the Sprite. `/tmp` is tmpfs and is not captured by checkpoints.
|
|
94
|
+
|
|
95
|
+
### A note on restore
|
|
96
|
+
|
|
97
|
+
`restore_sprite_checkpoint` rewinds the **whole environment** and permanently discards anything newer than the checkpoint. The tool refuses to run unless `confirm=true` is passed, and its description instructs the model to get explicit user confirmation first.
|
|
98
|
+
|
|
99
|
+
## Configuration
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
SpritesPlugin(
|
|
103
|
+
token=None, # default: $SPRITES_TOKEN
|
|
104
|
+
sprite_name=None, # default: auto-generated "adk-…"
|
|
105
|
+
plugin_name="sprites_plugin",
|
|
106
|
+
base_url="https://api.sprites.dev",
|
|
107
|
+
destroy_on_close=None, # default: True if unnamed, False if named
|
|
108
|
+
client_timeout=600.0, # HTTP timeout for Sprites API calls
|
|
109
|
+
)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Examples
|
|
113
|
+
|
|
114
|
+
- [`examples/quickstart.py`](examples/quickstart.py) — minimal agent
|
|
115
|
+
- [`examples/persistent_environment.py`](examples/persistent_environment.py) — a named dev environment that survives across sessions
|
|
116
|
+
- [`examples/checkpoint_rollback.py`](examples/checkpoint_rollback.py) — snapshot, break things, roll back
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```sh
|
|
121
|
+
python -m venv .venv && .venv/bin/pip install -e '.[dev]'
|
|
122
|
+
.venv/bin/pytest
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
### Releasing
|
|
126
|
+
|
|
127
|
+
Publishing to PyPI is automated via [`.github/workflows/publish.yml`](.github/workflows/publish.yml). Push a `vX.Y.Z` tag and the workflow stamps that version into `pyproject.toml` and `sprites_adk/__init__.py`, runs the tests, builds, and publishes via PyPI trusted publishing (OIDC — no API tokens):
|
|
128
|
+
|
|
129
|
+
```sh
|
|
130
|
+
git tag v0.1.0
|
|
131
|
+
git push origin v0.1.0
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
This requires a one-time [PyPI trusted publisher](https://docs.pypi.org/trusted-publishers/) configured for the `sprites-adk` project pointing at `superfly/sprites-adk` and workflow `publish.yml`.
|
|
135
|
+
|
|
136
|
+
## Resources
|
|
137
|
+
|
|
138
|
+
- [Sprites docs](https://docs.sprites.dev)
|
|
139
|
+
- [Sprites Python SDK](https://github.com/superfly/sprites-py)
|
|
140
|
+
- [Google ADK docs](https://google.github.io/adk-docs/)
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# sprites-adk
|
|
2
|
+
|
|
3
|
+
Google [ADK](https://google.github.io/adk-docs/) integration for [Sprites](https://sprites.dev) — persistent, stateful Linux sandboxes for AI agents, with checkpoint/restore, from [Fly.io](https://fly.io).
|
|
4
|
+
|
|
5
|
+
Most agent sandboxes are ephemeral: the environment vanishes when the session ends. A Sprite is a **stateful Linux microVM** that suspends when idle and keeps everything — files, packages, databases, running services — so your agent can resume yesterday's environment today. And because Sprites support **checkpoints**, your agent can snapshot the whole environment before a risky change and roll back if it goes wrong.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
pip install sprites-adk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
You'll need a Sprites API token ([get started](https://docs.sprites.dev/quickstart/)):
|
|
14
|
+
|
|
15
|
+
```sh
|
|
16
|
+
export SPRITES_TOKEN=...
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quickstart
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from google.adk.agents import Agent
|
|
23
|
+
from sprites_adk import SpritesPlugin
|
|
24
|
+
|
|
25
|
+
plugin = SpritesPlugin() # or SpritesPlugin(sprite_name="my-project") for a persistent env
|
|
26
|
+
|
|
27
|
+
root_agent = Agent(
|
|
28
|
+
model="gemini-flash-latest",
|
|
29
|
+
name="sprite_agent",
|
|
30
|
+
instruction="Run code and commands in the Sprite sandbox, not locally.",
|
|
31
|
+
tools=plugin.get_tools(),
|
|
32
|
+
)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Pass the plugin to your runner to get lifecycle callbacks and error handling:
|
|
36
|
+
|
|
37
|
+
```python
|
|
38
|
+
runner = InMemoryRunner(agent=root_agent, plugins=[plugin])
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Two modes
|
|
42
|
+
|
|
43
|
+
| | `SpritesPlugin()` | `SpritesPlugin(sprite_name="my-project")` |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| Sprite name | auto-generated `adk-…` | yours |
|
|
46
|
+
| Reused across sessions | no | **yes — full state persists** |
|
|
47
|
+
| Destroyed on `plugin.close()` | yes | no |
|
|
48
|
+
|
|
49
|
+
The Sprite is created lazily on first tool use; constructing the agent needs no network. Sprites suspend automatically when idle — a parked environment costs (almost) nothing.
|
|
50
|
+
|
|
51
|
+
## Tools
|
|
52
|
+
|
|
53
|
+
| Tool | Description |
|
|
54
|
+
|---|---|
|
|
55
|
+
| `execute_command_in_sprite` | Run a shell command (cwd, timeout supported) |
|
|
56
|
+
| `execute_code_in_sprite` | Run a Python / JavaScript / bash snippet |
|
|
57
|
+
| `write_file_to_sprite` | Write a text file (parents auto-created) |
|
|
58
|
+
| `read_file_from_sprite` | Read a text file |
|
|
59
|
+
| `create_sprite_checkpoint` | Snapshot the entire environment |
|
|
60
|
+
| `list_sprite_checkpoints` | List checkpoints, newest first |
|
|
61
|
+
| `restore_sprite_checkpoint` | Roll back to a checkpoint (**destructive**, requires `confirm=true`) |
|
|
62
|
+
|
|
63
|
+
All tools return structured dicts (`success`, `stdout`/`stderr`/`exit_code`, …); failures come back as `{"success": false, "error": ...}` so the agent can adapt instead of crashing the run.
|
|
64
|
+
|
|
65
|
+
File reads and writes run as commands inside the Sprite (via `base64`, so quotes/newlines/unicode survive) rather than through a separate filesystem API. That keeps them consistent with everything else the agent does — in particular, files written this way are correctly reverted by `restore_sprite_checkpoint`. `write_file_to_sprite` is capped at 256 KB; generate larger files with a command inside the Sprite. `/tmp` is tmpfs and is not captured by checkpoints.
|
|
66
|
+
|
|
67
|
+
### A note on restore
|
|
68
|
+
|
|
69
|
+
`restore_sprite_checkpoint` rewinds the **whole environment** and permanently discards anything newer than the checkpoint. The tool refuses to run unless `confirm=true` is passed, and its description instructs the model to get explicit user confirmation first.
|
|
70
|
+
|
|
71
|
+
## Configuration
|
|
72
|
+
|
|
73
|
+
```python
|
|
74
|
+
SpritesPlugin(
|
|
75
|
+
token=None, # default: $SPRITES_TOKEN
|
|
76
|
+
sprite_name=None, # default: auto-generated "adk-…"
|
|
77
|
+
plugin_name="sprites_plugin",
|
|
78
|
+
base_url="https://api.sprites.dev",
|
|
79
|
+
destroy_on_close=None, # default: True if unnamed, False if named
|
|
80
|
+
client_timeout=600.0, # HTTP timeout for Sprites API calls
|
|
81
|
+
)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Examples
|
|
85
|
+
|
|
86
|
+
- [`examples/quickstart.py`](examples/quickstart.py) — minimal agent
|
|
87
|
+
- [`examples/persistent_environment.py`](examples/persistent_environment.py) — a named dev environment that survives across sessions
|
|
88
|
+
- [`examples/checkpoint_rollback.py`](examples/checkpoint_rollback.py) — snapshot, break things, roll back
|
|
89
|
+
|
|
90
|
+
## Development
|
|
91
|
+
|
|
92
|
+
```sh
|
|
93
|
+
python -m venv .venv && .venv/bin/pip install -e '.[dev]'
|
|
94
|
+
.venv/bin/pytest
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Releasing
|
|
98
|
+
|
|
99
|
+
Publishing to PyPI is automated via [`.github/workflows/publish.yml`](.github/workflows/publish.yml). Push a `vX.Y.Z` tag and the workflow stamps that version into `pyproject.toml` and `sprites_adk/__init__.py`, runs the tests, builds, and publishes via PyPI trusted publishing (OIDC — no API tokens):
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
git tag v0.1.0
|
|
103
|
+
git push origin v0.1.0
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This requires a one-time [PyPI trusted publisher](https://docs.pypi.org/trusted-publishers/) configured for the `sprites-adk` project pointing at `superfly/sprites-adk` and workflow `publish.yml`.
|
|
107
|
+
|
|
108
|
+
## Resources
|
|
109
|
+
|
|
110
|
+
- [Sprites docs](https://docs.sprites.dev)
|
|
111
|
+
- [Sprites Python SDK](https://github.com/superfly/sprites-py)
|
|
112
|
+
- [Google ADK docs](https://google.github.io/adk-docs/)
|
|
113
|
+
|
|
114
|
+
## License
|
|
115
|
+
|
|
116
|
+
MIT
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# ADK docs catalog submission
|
|
2
|
+
|
|
3
|
+
This directory holds the draft page for the `google/adk-docs` integrations
|
|
4
|
+
catalog, per their [contributing guide](https://github.com/google/adk-docs/blob/main/CONTRIBUTING.md#integrations).
|
|
5
|
+
|
|
6
|
+
To submit, open a PR against `google/adk-docs` that adds:
|
|
7
|
+
|
|
8
|
+
1. `docs/integrations/sprites.md` — the page in this directory.
|
|
9
|
+
2. `docs/integrations/assets/sprites.png` — a square, card-sized Sprites
|
|
10
|
+
logo (not included here; export one from the sprites.dev brand assets).
|
|
11
|
+
3. Optional but encouraged: screenshots of an agent session using the
|
|
12
|
+
integration, also under `docs/integrations/assets/`.
|
|
13
|
+
|
|
14
|
+
Their review criteria: working/testable code examples, clear value for ADK
|
|
15
|
+
developers, and terms-of-service compliance. Publish `sprites-adk` to PyPI
|
|
16
|
+
before opening the PR so the installation instructions work.
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
catalog_title: Sprites
|
|
3
|
+
catalog_description: Persistent, stateful Linux sandboxes with checkpoint/restore for agent code execution, by Fly.io
|
|
4
|
+
catalog_icon: /integrations/assets/sprites.png
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Sprites
|
|
8
|
+
|
|
9
|
+
[Sprites](https://sprites.dev) are persistent, stateful Linux sandboxes from [Fly.io](https://fly.io). Unlike ephemeral sandboxes, a Sprite keeps its filesystem, installed packages, and services between sessions — it suspends when idle and resumes in milliseconds. The `sprites-adk` plugin gives ADK agents a full Linux environment with a capability most sandboxes don't have: **checkpoint and restore**, so an agent can snapshot the environment before a risky change and roll back if it goes wrong.
|
|
10
|
+
|
|
11
|
+
Supported in ADK Python.
|
|
12
|
+
|
|
13
|
+
## Use cases
|
|
14
|
+
|
|
15
|
+
- **Persistent development environments**: a named Sprite is reused across agent sessions — packages installed yesterday are still there today, so long-running projects don't rebuild the world every session.
|
|
16
|
+
- **Secure code execution**: run Python, JavaScript, or bash produced by the model in an isolated microVM instead of the host machine.
|
|
17
|
+
- **Fearless experimentation**: checkpoint the entire environment before package upgrades, migrations, or bulk edits; restore if the experiment breaks it.
|
|
18
|
+
- **File workflows**: write scripts and data into the sandbox, run them, and read results back.
|
|
19
|
+
|
|
20
|
+
## Prerequisites
|
|
21
|
+
|
|
22
|
+
- A [Sprites account and API token](https://docs.sprites.dev/quickstart/) (`sprite tokens create`), exported as `SPRITES_TOKEN`.
|
|
23
|
+
- A Google API key for the Gemini model used by your agent.
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
```sh
|
|
28
|
+
pip install sprites-adk
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Use with agent
|
|
32
|
+
|
|
33
|
+
```python
|
|
34
|
+
from google.adk.agents import Agent
|
|
35
|
+
from sprites_adk import SpritesPlugin
|
|
36
|
+
|
|
37
|
+
# SpritesPlugin() creates an ephemeral sandbox, destroyed on plugin.close().
|
|
38
|
+
# SpritesPlugin(sprite_name="my-project") attaches to a persistent environment
|
|
39
|
+
# that keeps all state between sessions and is never destroyed automatically.
|
|
40
|
+
plugin = SpritesPlugin()
|
|
41
|
+
|
|
42
|
+
root_agent = Agent(
|
|
43
|
+
model="gemini-flash-latest",
|
|
44
|
+
name="sprite_agent",
|
|
45
|
+
instruction=(
|
|
46
|
+
"Run code and commands inside the Sprite sandbox, not locally. "
|
|
47
|
+
"Create a checkpoint before risky operations."
|
|
48
|
+
),
|
|
49
|
+
tools=plugin.get_tools(),
|
|
50
|
+
)
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
For lifecycle callbacks and structured tool-error handling, also register the plugin with your runner:
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
from google.adk.runners import InMemoryRunner
|
|
57
|
+
|
|
58
|
+
runner = InMemoryRunner(agent=root_agent, plugins=[plugin])
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
The Sprite is created lazily on first tool use. Named Sprites are get-or-create: if a Sprite with that name already exists, the agent attaches to it with all of its state intact.
|
|
62
|
+
|
|
63
|
+
## Available tools
|
|
64
|
+
|
|
65
|
+
| Tool | Description |
|
|
66
|
+
| --- | --- |
|
|
67
|
+
| `execute_command_in_sprite` | Run a shell command with optional working directory and timeout. |
|
|
68
|
+
| `execute_code_in_sprite` | Run a Python, JavaScript, or bash snippet. |
|
|
69
|
+
| `write_file_to_sprite` | Write a text file (parent directories auto-created). |
|
|
70
|
+
| `read_file_from_sprite` | Read a text file from the sandbox. |
|
|
71
|
+
| `create_sprite_checkpoint` | Snapshot the entire environment (filesystem, packages, processes). |
|
|
72
|
+
| `list_sprite_checkpoints` | List checkpoints, newest first. |
|
|
73
|
+
| `restore_sprite_checkpoint` | Roll back to a checkpoint. Destructive — discards newer state and requires explicit `confirm=true`. |
|
|
74
|
+
|
|
75
|
+
## Resources
|
|
76
|
+
|
|
77
|
+
- [sprites-adk on PyPI](https://pypi.org/project/sprites-adk/)
|
|
78
|
+
- [Source code and examples](https://github.com/superfly/sprites-adk)
|
|
79
|
+
- [Sprites documentation](https://docs.sprites.dev)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
"""Checkpoint / rollback: let an agent experiment fearlessly.
|
|
2
|
+
|
|
3
|
+
The agent snapshots the Sprite before a risky change; if the change breaks
|
|
4
|
+
the environment, it rolls back to the checkpoint instead of trying to
|
|
5
|
+
hand-undo the damage. Restore is destructive (it discards state newer than
|
|
6
|
+
the checkpoint), so the restore tool requires explicit confirmation.
|
|
7
|
+
|
|
8
|
+
export SPRITES_TOKEN=...
|
|
9
|
+
export GOOGLE_API_KEY=...
|
|
10
|
+
python examples/checkpoint_rollback.py
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import asyncio
|
|
14
|
+
|
|
15
|
+
from google.adk.agents import Agent
|
|
16
|
+
from google.adk.runners import InMemoryRunner
|
|
17
|
+
from google.genai import types
|
|
18
|
+
|
|
19
|
+
from sprites_adk import SpritesPlugin
|
|
20
|
+
|
|
21
|
+
PROMPT = """
|
|
22
|
+
Set up a marker file /work/state.txt containing "v1".
|
|
23
|
+
Then create a checkpoint with the comment "before-experiment".
|
|
24
|
+
Then simulate a failed experiment: overwrite /work/state.txt with "broken".
|
|
25
|
+
Finally, restore the checkpoint (I confirm the restore - discarding the
|
|
26
|
+
"broken" state is exactly what I want) and read /work/state.txt to prove
|
|
27
|
+
the environment was rolled back.
|
|
28
|
+
"""
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def main() -> None:
|
|
32
|
+
plugin = SpritesPlugin() # ephemeral sprite, destroyed on close
|
|
33
|
+
|
|
34
|
+
agent = Agent(
|
|
35
|
+
model="gemini-flash-latest",
|
|
36
|
+
name="rollback_agent",
|
|
37
|
+
instruction=(
|
|
38
|
+
"You operate a Sprite sandbox with checkpoint/restore. Before "
|
|
39
|
+
"risky changes, create a checkpoint. Restoring discards newer "
|
|
40
|
+
"state, so only pass confirm=true when the user has clearly "
|
|
41
|
+
"agreed."
|
|
42
|
+
),
|
|
43
|
+
tools=plugin.get_tools(),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
runner = InMemoryRunner(agent=agent, plugins=[plugin])
|
|
47
|
+
session = await runner.session_service.create_session(
|
|
48
|
+
app_name=runner.app_name, user_id="demo"
|
|
49
|
+
)
|
|
50
|
+
async for event in runner.run_async(
|
|
51
|
+
user_id="demo",
|
|
52
|
+
session_id=session.id,
|
|
53
|
+
new_message=types.Content(role="user", parts=[types.Part(text=PROMPT)]),
|
|
54
|
+
):
|
|
55
|
+
if event.content and event.content.parts and event.content.parts[0].text:
|
|
56
|
+
print(event.content.parts[0].text)
|
|
57
|
+
|
|
58
|
+
await plugin.close()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if __name__ == "__main__":
|
|
62
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""A persistent development environment that survives across sessions.
|
|
2
|
+
|
|
3
|
+
Because the Sprite is named, every run of this script attaches to the SAME
|
|
4
|
+
Linux environment: packages installed yesterday are still installed today,
|
|
5
|
+
files are still there, and the agent picks up where it left off. Sprites
|
|
6
|
+
suspend automatically when idle, so a parked environment costs (almost)
|
|
7
|
+
nothing.
|
|
8
|
+
|
|
9
|
+
export SPRITES_TOKEN=...
|
|
10
|
+
export GOOGLE_API_KEY=...
|
|
11
|
+
python examples/persistent_environment.py "install uv and create a fastapi project in /app"
|
|
12
|
+
# ...later, a new process, same environment:
|
|
13
|
+
python examples/persistent_environment.py "add a /health endpoint to the project in /app"
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
import asyncio
|
|
17
|
+
import sys
|
|
18
|
+
|
|
19
|
+
from google.adk.agents import Agent
|
|
20
|
+
from google.adk.runners import InMemoryRunner
|
|
21
|
+
from google.genai import types
|
|
22
|
+
|
|
23
|
+
from sprites_adk import SpritesPlugin
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
async def main() -> None:
|
|
27
|
+
prompt = " ".join(sys.argv[1:]) or "What is in /app? Summarize the project state."
|
|
28
|
+
|
|
29
|
+
# Named sprite: reused across sessions, never auto-destroyed.
|
|
30
|
+
plugin = SpritesPlugin(sprite_name="my-dev-environment")
|
|
31
|
+
|
|
32
|
+
agent = Agent(
|
|
33
|
+
model="gemini-flash-latest",
|
|
34
|
+
name="dev_env_agent",
|
|
35
|
+
instruction=(
|
|
36
|
+
"You maintain a long-lived development environment inside a "
|
|
37
|
+
"Sprite. All commands, code, and files run inside the Sprite. "
|
|
38
|
+
"It persists between sessions, so check existing state before "
|
|
39
|
+
"assuming a fresh machine. Create a checkpoint before risky "
|
|
40
|
+
"changes."
|
|
41
|
+
),
|
|
42
|
+
tools=plugin.get_tools(),
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
runner = InMemoryRunner(agent=agent, plugins=[plugin])
|
|
46
|
+
session = await runner.session_service.create_session(
|
|
47
|
+
app_name=runner.app_name, user_id="demo"
|
|
48
|
+
)
|
|
49
|
+
async for event in runner.run_async(
|
|
50
|
+
user_id="demo",
|
|
51
|
+
session_id=session.id,
|
|
52
|
+
new_message=types.Content(role="user", parts=[types.Part(text=prompt)]),
|
|
53
|
+
):
|
|
54
|
+
if event.content and event.content.parts and event.content.parts[0].text:
|
|
55
|
+
print(event.content.parts[0].text)
|
|
56
|
+
|
|
57
|
+
await plugin.close() # named sprite is preserved
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
if __name__ == "__main__":
|
|
61
|
+
asyncio.run(main())
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"""Quickstart: an ADK agent with a Sprites sandbox.
|
|
2
|
+
|
|
3
|
+
Prerequisites:
|
|
4
|
+
pip install sprites-adk
|
|
5
|
+
export SPRITES_TOKEN=... # `sprite tokens create`
|
|
6
|
+
export GOOGLE_API_KEY=... # for the Gemini model
|
|
7
|
+
|
|
8
|
+
Run with the ADK CLI from the directory above this file:
|
|
9
|
+
adk run examples
|
|
10
|
+
or programmatically via Runner (see persistent_environment.py).
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from google.adk.agents import Agent
|
|
14
|
+
|
|
15
|
+
from sprites_adk import SpritesPlugin
|
|
16
|
+
|
|
17
|
+
# No sprite_name: an ephemeral `adk-` prefixed Sprite is created on first
|
|
18
|
+
# tool use and destroyed when the plugin is closed.
|
|
19
|
+
plugin = SpritesPlugin()
|
|
20
|
+
|
|
21
|
+
root_agent = Agent(
|
|
22
|
+
model="gemini-flash-latest",
|
|
23
|
+
name="sprite_agent",
|
|
24
|
+
instruction=(
|
|
25
|
+
"You help users build and test code inside a persistent Linux "
|
|
26
|
+
"sandbox (a Sprite). Run commands and code in the sandbox, not "
|
|
27
|
+
"locally. Create a checkpoint before risky operations such as "
|
|
28
|
+
"package installs or migrations."
|
|
29
|
+
),
|
|
30
|
+
tools=plugin.get_tools(),
|
|
31
|
+
)
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "sprites-adk"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Google ADK plugin for Sprites: persistent, stateful Linux sandboxes with checkpoint/restore for AI agents."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = { text = "MIT" }
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
authors = [{ name = "Fly.io" }]
|
|
13
|
+
keywords = ["adk", "google-adk", "agents", "sandbox", "sprites", "fly.io", "code-execution"]
|
|
14
|
+
classifiers = [
|
|
15
|
+
"Development Status :: 4 - Beta",
|
|
16
|
+
"Intended Audience :: Developers",
|
|
17
|
+
"License :: OSI Approved :: MIT License",
|
|
18
|
+
"Programming Language :: Python :: 3",
|
|
19
|
+
"Programming Language :: Python :: 3.9",
|
|
20
|
+
"Programming Language :: Python :: 3.10",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"google-adk>=1.0.0",
|
|
28
|
+
"sprites-py>=0.2.0",
|
|
29
|
+
]
|
|
30
|
+
|
|
31
|
+
[project.urls]
|
|
32
|
+
Homepage = "https://sprites.dev"
|
|
33
|
+
Documentation = "https://docs.sprites.dev"
|
|
34
|
+
Repository = "https://github.com/superfly/sprites-adk"
|
|
35
|
+
|
|
36
|
+
[project.optional-dependencies]
|
|
37
|
+
dev = ["pytest>=7.0"]
|
|
38
|
+
|
|
39
|
+
[tool.hatch.build.targets.wheel]
|
|
40
|
+
packages = ["sprites_adk"]
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"""Google ADK integration for Sprites (https://sprites.dev).
|
|
2
|
+
|
|
3
|
+
Gives ADK agents a persistent, stateful Linux sandbox with checkpoint and
|
|
4
|
+
restore, backed by Fly.io's Sprites.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from .plugin import SpritesPlugin
|
|
8
|
+
from .tools import (
|
|
9
|
+
CreateCheckpointTool,
|
|
10
|
+
ExecuteCodeTool,
|
|
11
|
+
ExecuteCommandTool,
|
|
12
|
+
ListCheckpointsTool,
|
|
13
|
+
ReadFileTool,
|
|
14
|
+
RestoreCheckpointTool,
|
|
15
|
+
WriteFileTool,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
__version__ = "0.1.0"
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
"SpritesPlugin",
|
|
22
|
+
"ExecuteCommandTool",
|
|
23
|
+
"ExecuteCodeTool",
|
|
24
|
+
"WriteFileTool",
|
|
25
|
+
"ReadFileTool",
|
|
26
|
+
"CreateCheckpointTool",
|
|
27
|
+
"ListCheckpointsTool",
|
|
28
|
+
"RestoreCheckpointTool",
|
|
29
|
+
"__version__",
|
|
30
|
+
]
|