Skip to content
Open
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
8 changes: 4 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/runloop-python' && 'depot-ubuntu-24.04' || 'ubuntu-slim' }}
if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata')
steps:
- uses: actions/checkout@v6
- uses: runloopai/checkout@main

- name: Install uv
uses: runloopai/setup-uv@main
Expand All @@ -46,7 +46,7 @@ jobs:
id-token: write
runs-on: ${{ github.repository == 'stainless-sdks/runloop-python' && 'depot-ubuntu-24.04' || 'ubuntu-slim' }}
steps:
- uses: actions/checkout@v6
- uses: runloopai/checkout@main

- name: Install uv
uses: runloopai/setup-uv@main
Expand All @@ -64,7 +64,7 @@ jobs:
github.repository == 'stainless-sdks/runloop-python' &&
!startsWith(github.ref, 'refs/heads/stl/')
id: github-oidc
uses: actions/github-script@v8
uses: runloopai/github-script@main
with:
script: core.setOutput('github_token', await core.getIDToken());

Expand All @@ -84,7 +84,7 @@ jobs:
runs-on: ${{ github.repository == 'stainless-sdks/runloop-python' && 'depot-ubuntu-24.04' || 'ubuntu-slim' }}
if: github.event_name == 'push' || github.event.pull_request.head.repo.fork
steps:
- uses: actions/checkout@v6
- uses: runloopai/checkout@main

- name: Install uv
uses: runloopai/setup-uv@main
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-slim

steps:
- uses: actions/checkout@v6
- uses: runloopai/checkout@main

- name: Install uv
uses: runloopai/setup-uv@main
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-doctor.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
if: github.repository == 'runloopai/api-client-python' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next')

steps:
- uses: actions/checkout@v6
- uses: runloopai/checkout@main

- name: Check release environment
run: |
Expand Down
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.21.0"
".": "1.22.0"
}
6 changes: 3 additions & 3 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 119
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai/runloop-6ec03cfc156036a0758aebc523b469f3007de431312c536c434efe795e1892e7.yml
openapi_spec_hash: 092761a0209e0950cfd8f262a981adb1
config_hash: 06faf3176c48bf2b258730ce50809f0f
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/runloop-ai/runloop-2c6498f804f6a88977521c2b4b8700d8992235a01ffc965193d87acf8021683b.yml
openapi_spec_hash: cf32b83c81c8aa76f03dda8123b228b5
config_hash: 444e00951b440bf92e7548b2807584a4
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## 1.22.0 (2026-05-20)

Full Changelog: [v1.21.0...v1.22.0](https://github.com/runloopai/api-client-python/compare/v1.21.0...v1.22.0)

### Features

* add reflex initiator type, hidden param ([#9350](https://github.com/runloopai/api-client-python/issues/9350)) ([5922abf](https://github.com/runloopai/api-client-python/commit/5922abfd135589b229cb64ea23750d34fede857f))
* **api:** expose lifecycle_hooks on LaunchParameters lifecycle ([#9115](https://github.com/runloopai/api-client-python/issues/9115)) ([c9c7c37](https://github.com/runloopai/api-client-python/commit/c9c7c37c2a38f91142b0b28d1e5cbc183b8ee53e))


### Bug Fixes

* **mux:** strip internal stub note from PTY OpenAPI descriptions ([#9315](https://github.com/runloopai/api-client-python/issues/9315)) ([214629e](https://github.com/runloopai/api-client-python/commit/214629e9281c38ff75b5769e13b4b977a346bb04))


### Chores

* Update stainless.yml, bump AGENTS.md to keep this updated ([#9268](https://github.com/runloopai/api-client-python/issues/9268)) ([5d86ef5](https://github.com/runloopai/api-client-python/commit/5d86ef5240920ba4b6de9e59456aea3c0971e3ef))

## 1.21.0 (2026-05-13)

Full Changelog: [v1.20.3...v1.21.0](https://github.com/runloopai/api-client-python/compare/v1.20.3...v1.21.0)
Expand Down
3 changes: 3 additions & 0 deletions api.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ from runloop_api_client.types import (
BrokerMount,
CodeMountParameters,
LaunchParameters,
LifecycleConfiguration,
LifecycleHooks,
Mount,
ObjectMount,
ResumeTriggers,
RunProfile,
)
```
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "runloop_api_client"
version = "1.21.0"
version = "1.22.0"
description = "The official Python library for the runloop API"
dynamic = ["readme"]
license = "MIT"
Expand Down
2 changes: 1 addition & 1 deletion src/runloop_api_client/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "runloop_api_client"
__version__ = "1.21.0" # x-release-please-version
__version__ = "1.22.0" # x-release-please-version
64 changes: 24 additions & 40 deletions src/runloop_api_client/resources/pty.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,22 +68,18 @@ def connect(
effect. The response returns a PtyConnectView containing connect_url (a
server-relative path to the WebSocket data plane), idle_ttl_seconds (how long
this session is retained after the last client disconnects), and the resulting
cols/rows. The interactive byte stream itself is intentionally not modeled in
OpenAPI; see the controller-level documentation for the WebSocket close-code
conventions. The single-attach contract is enforced when a client opens the
WebSocket data plane, not on this bootstrap call: bootstrap always succeeds for
a valid session_name, even if another client is currently attached. Rejection of
a second concurrent attach happens at WebSocket upgrade time. If the active
client disconnects, the session is preserved for the idle TTL so a later connect
using the same session_name resumes the same shell. After the TTL expires, after
an explicit close control action, or after the underlying Devbox lifecycle
replaces the PTY process (such as through suspend/resume), a later request with
the same session_name creates a fresh PTY session without the previous shell
state.

Documentation note: this operation is published from mux strictly as an OpenAPI
contract stub for the PTY service control plane. It is not evidence that mux
itself serves the interactive PTY transport.
cols/rows. The interactive terminal byte stream is exchanged over the WebSocket
data plane and is not modeled in this OpenAPI contract; clients should connect
to connect_url and exchange raw binary frames for terminal I/O. The
single-attach contract is enforced when a client opens the WebSocket data plane,
not on this bootstrap call: bootstrap always succeeds for a valid session_name,
even if another client is currently attached. Rejection of a second concurrent
attach happens at WebSocket upgrade time. If the active client disconnects, the
session is preserved for the idle TTL so a later connect using the same
session_name resumes the same shell. After the TTL expires, after an explicit
close control action, or after the underlying Devbox lifecycle replaces the PTY
process (such as through suspend/resume), a later request with the same
session_name creates a fresh PTY session without the previous shell state.

Args:
cols: Optional initial terminal width in character cells (1..=1000). Defaults to 80
Expand Down Expand Up @@ -158,10 +154,6 @@ def control(
from the server's session cache. A subsequent connect with the same session_name
will create a fresh PTY session.

Documentation note: this operation is published from mux strictly as an OpenAPI
contract stub for the PTY service control plane. It is not evidence that mux
itself serves the interactive PTY transport.

Args:
extra_headers: Send extra headers

Expand Down Expand Up @@ -241,22 +233,18 @@ async def connect(
effect. The response returns a PtyConnectView containing connect_url (a
server-relative path to the WebSocket data plane), idle_ttl_seconds (how long
this session is retained after the last client disconnects), and the resulting
cols/rows. The interactive byte stream itself is intentionally not modeled in
OpenAPI; see the controller-level documentation for the WebSocket close-code
conventions. The single-attach contract is enforced when a client opens the
WebSocket data plane, not on this bootstrap call: bootstrap always succeeds for
a valid session_name, even if another client is currently attached. Rejection of
a second concurrent attach happens at WebSocket upgrade time. If the active
client disconnects, the session is preserved for the idle TTL so a later connect
using the same session_name resumes the same shell. After the TTL expires, after
an explicit close control action, or after the underlying Devbox lifecycle
replaces the PTY process (such as through suspend/resume), a later request with
the same session_name creates a fresh PTY session without the previous shell
state.

Documentation note: this operation is published from mux strictly as an OpenAPI
contract stub for the PTY service control plane. It is not evidence that mux
itself serves the interactive PTY transport.
cols/rows. The interactive terminal byte stream is exchanged over the WebSocket
data plane and is not modeled in this OpenAPI contract; clients should connect
to connect_url and exchange raw binary frames for terminal I/O. The
single-attach contract is enforced when a client opens the WebSocket data plane,
not on this bootstrap call: bootstrap always succeeds for a valid session_name,
even if another client is currently attached. Rejection of a second concurrent
attach happens at WebSocket upgrade time. If the active client disconnects, the
session is preserved for the idle TTL so a later connect using the same
session_name resumes the same shell. After the TTL expires, after an explicit
close control action, or after the underlying Devbox lifecycle replaces the PTY
process (such as through suspend/resume), a later request with the same
session_name creates a fresh PTY session without the previous shell state.

Args:
cols: Optional initial terminal width in character cells (1..=1000). Defaults to 80
Expand Down Expand Up @@ -331,10 +319,6 @@ async def control(
from the server's session cache. A subsequent connect with the same session_name
will create a fresh PTY session.

Documentation note: this operation is published from mux strictly as an OpenAPI
contract stub for the PTY service control plane. It is not evidence that mux
itself serves the interactive PTY transport.

Args:
extra_headers: Send extra headers

Expand Down
3 changes: 3 additions & 0 deletions src/runloop_api_client/types/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
AgentSource as AgentSource,
BrokerMount as BrokerMount,
ObjectMount as ObjectMount,
LifecycleHooks as LifecycleHooks,
ResumeTriggers as ResumeTriggers,
LaunchParameters as LaunchParameters,
CodeMountParameters as CodeMountParameters,
LifecycleConfiguration as LifecycleConfiguration,
)
from .axon_view import AxonView as AxonView
from .agent_view import AgentView as AgentView
Expand Down
2 changes: 1 addition & 1 deletion src/runloop_api_client/types/devbox_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ class DevboxView(BaseModel):
initiator_id: Optional[str] = None
"""The ID of the initiator that created the Devbox."""

initiator_type: Optional[Literal["unknown", "api", "scenario", "scoring_validation"]] = None
initiator_type: Optional[Literal["unknown", "api", "scenario", "scoring_validation", "reflex"]] = None
"""The type of initiator that created the Devbox."""

mcp_specs: Optional[Dict[str, McpSpecs]] = None
Expand Down
3 changes: 3 additions & 0 deletions src/runloop_api_client/types/shared/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
from .agent_source import AgentSource as AgentSource
from .broker_mount import BrokerMount as BrokerMount
from .object_mount import ObjectMount as ObjectMount
from .lifecycle_hooks import LifecycleHooks as LifecycleHooks
from .resume_triggers import ResumeTriggers as ResumeTriggers
from .launch_parameters import LaunchParameters as LaunchParameters
from .code_mount_parameters import CodeMountParameters as CodeMountParameters
from .lifecycle_configuration import LifecycleConfiguration as LifecycleConfiguration
37 changes: 6 additions & 31 deletions src/runloop_api_client/types/shared/launch_parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,35 +5,9 @@

from ..._models import BaseModel
from .after_idle import AfterIdle
from .lifecycle_configuration import LifecycleConfiguration

__all__ = ["LaunchParameters", "Lifecycle", "LifecycleResumeTriggers", "UserParameters"]


class LifecycleResumeTriggers(BaseModel):
"""Triggers that can resume a suspended Devbox."""

axon_event: Optional[bool] = None
"""When true, axon events targeting a suspended Devbox will trigger a resume."""

http: Optional[bool] = None
"""When true, HTTP traffic to a suspended Devbox via tunnel will trigger a resume."""


class Lifecycle(BaseModel):
"""Lifecycle configuration for idle and resume behavior.

Configure idle policy via lifecycle.after_idle (if both this and the top-level after_idle are set, they must match) and resume triggers via lifecycle.resume_triggers.
"""

after_idle: Optional[AfterIdle] = None
"""Configure Devbox lifecycle based on idle activity.

If both this and the top-level after_idle are set, they must have the same
value. Prefer this field for new integrations.
"""

resume_triggers: Optional[LifecycleResumeTriggers] = None
"""Triggers that can resume a suspended Devbox."""
__all__ = ["LaunchParameters", "UserParameters"]


class UserParameters(BaseModel):
Expand Down Expand Up @@ -89,12 +63,13 @@ class LaunchParameters(BaseModel):
launch_commands: Optional[List[str]] = None
"""Set of commands to be run at launch time, before the entrypoint process is run."""

lifecycle: Optional[Lifecycle] = None
lifecycle: Optional[LifecycleConfiguration] = None
"""Lifecycle configuration for idle and resume behavior.

Configure idle policy via lifecycle.after_idle (if both this and the top-level
after_idle are set, they must match) and resume triggers via
lifecycle.resume_triggers.
after_idle are set, they must match), resume triggers via
lifecycle.resume_triggers, and optional lifecycle hooks via
lifecycle.lifecycle_hooks.
"""

network_policy_id: Optional[str] = None
Expand Down
34 changes: 34 additions & 0 deletions src/runloop_api_client/types/shared/lifecycle_configuration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Optional

from ..._models import BaseModel
from .after_idle import AfterIdle
from .lifecycle_hooks import LifecycleHooks
from .resume_triggers import ResumeTriggers

__all__ = ["LifecycleConfiguration"]


class LifecycleConfiguration(BaseModel):
"""Lifecycle configuration for Devbox idle and resume behavior.

Configure idle policy via after_idle, resume triggers via resume_triggers, and optional lifecycle hooks via lifecycle_hooks.
"""

after_idle: Optional[AfterIdle] = None
"""Configure Devbox lifecycle based on idle activity.

If both this and the top-level after_idle are set, they must have the same
value. Prefer this field for new integrations.
"""

lifecycle_hooks: Optional[LifecycleHooks] = None
"""Optional lifecycle hooks.

suspend_commands run through the suspend path before the Devbox suspends; see
launch_commands for work on every startup.
"""

resume_triggers: Optional[ResumeTriggers] = None
"""Triggers that can resume a suspended Devbox."""
28 changes: 28 additions & 0 deletions src/runloop_api_client/types/shared/lifecycle_hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import List, Optional

from ..._models import BaseModel

__all__ = ["LifecycleHooks"]


class LifecycleHooks(BaseModel):
"""Lifecycle hooks for Devbox suspend.

suspend_commands run sequentially as the configured Devbox user through the rage/vmagent suspend path before the Devbox suspends; failures are logged but do not block suspending. The suspend_deadline_ms budget defaults to 30000 ms, may not exceed 60000 ms, and covers broker drain plus suspend_commands. If the deadline is exceeded, suspend work is abandoned, the timeout is logged, and the Devbox still proceeds to suspend by shutting down vmagent and killing the VM. Resume hooks and resume deadline settings are persistence/internal only and hidden from the public API reference. launch_commands still run on every startup, including after resume.
"""

suspend_commands: Optional[List[str]] = None
"""Commands to run through the suspend path before the Devbox suspends (e.g.

cleanup, quiesce daemons).
"""

suspend_deadline_ms: Optional[int] = None
"""Deadline in milliseconds for broker drain and suspend_commands during suspend.

Defaults to 30000 ms and may not exceed 60000 ms. If exceeded, suspend work is
abandoned, the timeout is logged, and the Devbox still proceeds to suspend by
shutting down vmagent and killing the VM.
"""
17 changes: 17 additions & 0 deletions src/runloop_api_client/types/shared/resume_triggers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Optional

from ..._models import BaseModel

__all__ = ["ResumeTriggers"]


class ResumeTriggers(BaseModel):
"""Triggers that can resume a suspended Devbox."""

axon_event: Optional[bool] = None
"""When true, axon events targeting a suspended Devbox will trigger a resume."""

http: Optional[bool] = None
"""When true, HTTP traffic to a suspended Devbox via tunnel will trigger a resume."""
3 changes: 3 additions & 0 deletions src/runloop_api_client/types/shared_params/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,8 @@
from .agent_source import AgentSource as AgentSource
from .broker_mount import BrokerMount as BrokerMount
from .object_mount import ObjectMount as ObjectMount
from .lifecycle_hooks import LifecycleHooks as LifecycleHooks
from .resume_triggers import ResumeTriggers as ResumeTriggers
from .launch_parameters import LaunchParameters as LaunchParameters
from .code_mount_parameters import CodeMountParameters as CodeMountParameters
from .lifecycle_configuration import LifecycleConfiguration as LifecycleConfiguration
Loading