Metadata-Version: 2.4
Name: geniete-screens
Version: 0.1.0
Summary: GenieTé Screens Python SDK — live visual output for AI agents (AgentScreen)
License: MIT
License-File: LICENSE
Keywords: agents,screens,geniete,ai,streaming
Author: Genie, Inc.
Author-email: renat@geniete.com
Requires-Python: >=3.10
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Requires-Dist: httpx (>=0.27.0)
Requires-Dist: websockets (>=13.0)
Project-URL: Company, https://www.genieinc.com/
Project-URL: Documentation, https://screens.geniete.com/docs/screens/
Project-URL: Homepage, https://screens.geniete.com/
Description-Content-Type: text/markdown

# geniete-screens

Publish live status, metrics, terminal output, and viewer links from any AI
agent or automation into an AgentScreen.

AgentScreen is a GenieTé service by [Genie, Inc.](https://www.genieinc.com/).
It is built for developers who want their own systems to stay simple and
predictable while offloading live connectivity, session handling, and fair
metered delivery to a service made by developers.

## Limited Access

AgentScreen currently runs as a limited-access service. You need:

- a GenieTé account at `https://account.geniete.com/`;
- a screen created at `https://screens.geniete.com/`;
- credits granted by an administrator;
- a screen API key, shown once when the screen is created.

If your balance reaches zero, ask your administrator for more credits.

## Install

```bash
pip install geniete-screens
```

or:

```bash
uv add geniete-screens
```

The import name is `geniete_screens`.

## Quick Start

Create a screen in the AgentScreen console, copy the API key, and note the
screen id.

```python
from geniete_screens import Screen

screen = Screen(
    api_key="as_key_...",
    screen_id="scr_...",
)

screen.message("Agent booted", title="status", tone="success")
screen.metric("queue_depth", 12)
screen.terminal("$ python agent.py\nready\n")
```

The default base URL is:

```text
https://screens.geniete.com
```

Override it only for local or staging tests:

```python
screen = Screen(
    api_key="as_key_...",
    screen_id="scr_...",
    base_url="https://staging.example.com",
)
```

## Event Types

### Message Card

```python
screen.message(
    "Fetched 42 candidate documents and selected 5 for synthesis.",
    title="retrieval",
    tone="info",
)
```

Tones: `info`, `success`, `warning`, `error`.

### Metric

```python
screen.metric("latency", 184, unit="ms")
screen.metric("tokens", 18342)
screen.metric("cost", "0.42", unit="credits")
```

Calling again with the same metric name updates it in place.

### Terminal Output

```python
screen.terminal("running eval suite...\n")
screen.terminal("pass 128/128\n")
```

### Clear The Screen

```python
screen.clear()
```

## Viewer Links

Create a viewer link when you want another person or system to watch a screen.

```python
url = screen.create_viewer_link(ttl_seconds=3600)
print(url)
```

The server enforces the maximum TTL allowed by the current plan.

## Active Sessions

```python
for session in screen.sessions():
    print(session["session_id"], session.get("ip"))

screen.revoke_session("session_id_here")
```

## Async Agents

Use `AsyncScreen` when your agent already runs in an async loop.

```python
import asyncio
from geniete_screens import AsyncScreen

async def main():
    screen = AsyncScreen(api_key="as_key_...", screen_id="scr_...")
    await screen.message("Async agent started", tone="success")
    await screen.metric("steps", 1)
    sessions = await screen.sessions()
    print(f"{len(sessions)} active viewers")

asyncio.run(main())
```

## Long-Running Streaming Agents

For high-frequency agent output, use the WebSocket producer stream.

```python
import asyncio
from geniete_screens import AsyncScreen

async def run_agent():
    screen = AsyncScreen(api_key="as_key_...", screen_id="scr_...")

    async with screen.stream() as stream:
        await stream.message("planning")
        await stream.terminal("tool: web_search\n")
        await stream.metric("steps", 1)
        await stream.message("done", tone="success")

asyncio.run(run_agent())
```

## Use With Agent Frameworks

AgentScreen does not require a specific agent framework. If your agent can run
Python code or call an HTTP endpoint, it can publish to a screen.

### Generic Agent Loop

```python
from geniete_screens import Screen

screen = Screen(api_key="as_key_...", screen_id="scr_...")

def on_step(step_name: str, detail: str):
    screen.message(detail, title=step_name)

def on_tool_output(tool_name: str, output: str):
    screen.terminal(f"$ {tool_name}\n{output}\n")

def on_score(name: str, value: float):
    screen.metric(name, value)
```

### LangChain, LlamaIndex, CrewAI, AutoGen, Or Custom Runners

Use the same pattern in the framework's callback, event handler, observer, or
tool wrapper:

```python
screen.message("tool call started", title="agent")
screen.terminal(tool_output)
screen.metric("retrieved_docs", len(documents))
```

Keep AgentScreen calls outside your critical decision path when possible. It is
best used as live observability and customer-facing progress, not as part of
the model's core reasoning state.

### Shell, CI, Or Any HTTP Client

The SDK wraps this endpoint:

```bash
curl -X POST https://screens.geniete.com/public/api/publish \
  -H "Authorization: Bearer $AGENTSCREEN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "screen_id": "scr_...",
    "event": {
      "type": "content.message",
      "title": "deploy",
      "body": "release finished",
      "tone": "success"
    }
  }'
```

## Error Handling

`httpx` raises an exception for non-2xx responses. Common cases:

- `401`: missing or invalid API key;
- `403`: key does not allow publish for this screen;
- `404`: screen not found;
- `413`: event payload too large;
- `429`: quota or credit exhaustion.

During limited access, a `429` usually means your account needs more credits
from an administrator.

## Publish Order

When releasing public packages:


The MCP package depends on the SDK.

