Metadata-Version: 2.4
Name: voke
Version: 0.2.0
Summary: Python SDK for Voke — serverless macOS compute on Apple Silicon
Project-URL: Homepage, https://voke.run
Project-URL: Documentation, https://docs.voke.run
Project-URL: Repository, https://github.com/voke-run/sdk-python
Project-URL: Changelog, https://github.com/voke-run/sdk-python/blob/main/CHANGELOG.md
Author-email: Voke <hello@voke.run>
License-Expression: MIT
Keywords: ai-agent,apple-silicon,ci-cd,macos,mcp,serverless,vm
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Software Development :: Build Tools
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.9
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.0
Provides-Extra: crewai
Requires-Dist: crewai-tools>=0.1; extra == 'crewai'
Provides-Extra: dev
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Provides-Extra: langchain
Requires-Dist: langchain-core>=0.3; extra == 'langchain'
Provides-Extra: openai
Requires-Dist: openai>=1.0; extra == 'openai'
Description-Content-Type: text/markdown

# voke

Python SDK for [Voke](https://voke.run) -- serverless macOS compute on Apple Silicon. Run scripts on ephemeral macOS VMs with one function call.

## Install

```bash
pip install voke                 # core SDK
pip install voke[openai]         # + OpenAI function calling
pip install voke[langchain]      # + LangChain integration
pip install voke[crewai]         # + CrewAI integration
```

## Quick start

### Sync

```python
from voke import Voke

client = Voke()  # reads VOKE_API_KEY from env
result = client.jobs.create(script="uname -m && sw_vers").wait()

print(result.exit_code)  # 0
print(result.stdout)     # arm64\nProductName: macOS\n...
```

### Async

```python
import asyncio
from voke import AsyncVoke

async def main():
    client = AsyncVoke()
    job = await client.jobs.create(script="uname -m")
    result = await job.async_wait()
    print(result.stdout)
    await client.close()

asyncio.run(main())
```

## API reference

### `Voke(api_key=None, base_url="https://api.voke.run")`

Create a sync client. If `api_key` is not provided, reads `VOKE_API_KEY` from environment.

### `client.jobs.create(script, *, image="base", timeout=600, env=None, webhook_url=None) -> Job`

Submit a script. Returns a `Job` object immediately (status will be "queued").

### `client.jobs.get(job_id) -> Job`

Fetch a job by ID.

### `client.jobs.list(*, limit=20, offset=0, status=None) -> JobList`

List your jobs, newest first.

### `client.jobs.cancel(job_id) -> Job`

Cancel a queued job.

### `job.wait(poll_interval=1.5, timeout=None) -> Job`

Poll until the job reaches a terminal state (completed/failed/cancelled).

### `client.images() -> dict[str, ImageInfo]`

List available macOS images.

### `client.usage() -> UsageResponse`

Get current month's usage.

## Images

| Image | Description |
|-------|-------------|
| `base` | Clean macOS Sonoma 14.8 with dev tools |
| `xcode16` | base + Xcode 16, Swift 6, CocoaPods, Fastlane |

## Error handling

```python
from voke.errors import VokeError, AuthenticationError, RateLimitError

try:
    client.jobs.create(script="echo hello")
except AuthenticationError:
    print("Bad API key")
except RateLimitError:
    print("Too many requests")
except VokeError as e:
    print(f"API error {e.status_code}: {e}")
```

## OpenAI Function Calling

```python
from openai import OpenAI
from voke.tools.openai import VOKE_TOOLS, handle_tool_call

client = OpenAI()
response = client.chat.completions.create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Check the macOS version"}],
    tools=VOKE_TOOLS,
)

for tc in response.choices[0].message.tool_calls or []:
    result = handle_tool_call(tc, api_key="sk_...")
    print(result)
```

## LangChain

```python
from voke.tools.langchain import VokeRunTool

tool = VokeRunTool()  # reads VOKE_API_KEY from env

# Use with an agent
from langchain.agents import AgentExecutor
agent = AgentExecutor(tools=[tool], ...)

# Or call directly
result = tool.invoke({"script": "sw_vers", "image": "base"})
```

## CrewAI

```python
from voke.tools.crewai import VokeTool
from crewai import Agent

macos_tool = VokeTool()

agent = Agent(
    role="macOS Engineer",
    tools=[macos_tool],
    ...
)
```
