Metadata-Version: 2.4
Name: sseurl
Version: 0.1.0
Summary: A curl-like viewer that renders SSE / OpenAI-style event streams for humans
License-Expression: MIT
License-File: LICENSE
Keywords: cli,event-stream,openai,server-sent-events,sse,streaming
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
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 :: Internet :: WWW/HTTP
Classifier: Topic :: Utilities
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: rich>=13.7
Description-Content-Type: text/markdown

# sseurl

A curl-like viewer that renders SSE (`text/event-stream`) streams for humans.

`curl -N` shows you a wall of `data: {...}` JSON. `sseurl` parses the wire
format, auto-detects what kind of stream it is, and renders it readably:
accumulated markdown for LLM output, aligned colored log lines for job event
streams, syntax-highlighted JSON for everything else — plus a live tail while
streaming and an end-of-stream summary (event count, bytes, duration, time to
first event, tokens).

## Install

From PyPI:

```sh
uv tool install sseurl
# or: pipx install sseurl
```

On internal Debian trixie machines, install from the private APT repository.
The repository keyring is provided by the repo admin.

```sh
sudo tee /etc/apt/sources.list.d/hashtable.sources >/dev/null <<'EOF'
Types: deb
URIs: https://repo.hashtable.io/apt/debian
Suites: trixie
Components: main
Architectures: amd64 arm64
Signed-By: /usr/share/keyrings/archive-keyring.gpg
EOF
sudo apt-get update && sudo apt-get install sseurl
```

From a checkout:

```sh
uv tool install .
# or: pipx install .
```

Requires Python ≥ 3.10. Dependencies: `httpx`, `rich`.

### Build your own Debian package

```sh
dpkg-buildpackage -us -uc -b
sudo apt-get install ./sseurl_0.1.0_all.deb
```

## Usage

Fetch a stream directly (curl-style flags):

```sh
sseurl https://gateway.example.com/v1/jobs/job_x/events/stream \
  -H 'Authorization: Bearer TOKEN'

sseurl https://api.openai.com/v1/chat/completions \
  -H "Authorization: Bearer $OPENAI_API_KEY" -d @request.json
```

Or keep your existing curl command and pipe into it (`-` = stdin):

```sh
curl -sN https://api.example.com/stream | sseurl -
```

It also reads saved dumps: `sseurl dump.sse`.

## Rendering profiles

Detected automatically from the first event; force one with `--profile`.

| Profile | Detected by | Rendering |
| --- | --- | --- |
| `openai` | `chat.completion.chunk` / `choices[].delta` | accumulates `delta.content` into live markdown; reasoning deltas dim; `tool_calls` assembled per index and shown with pretty-printed args; usage/finish_reason in summary |
| `responses` | `response.*` event names | accumulates `response.output_text.delta`; function-call args assembled; usage from `response.completed` |
| `gateway` | JobEvent frames (`job_id` + `seq`) | one aligned line per event: seq, time, colored stream (stdout/stderr/system), level, type; known adapter payloads get semantic rendering — codex `command_execution` as `⏵ $ cmd` with exit mark and clipped output, `agent_message` as a markdown panel, `turn_completed` as a token-usage line, claude `assistant`/`tool_use`/`result` similarly; unknown payloads inline-compact or clipped highlighted JSON (full with `--raw`); `gap` frames as red warning panels |
| `generic` | anything else | event name + syntax-highlighted JSON (or plain text) |

Keepalive comments (`: keepalive`) are shown dimmed, so you can tell an idle
connection from a dead one.

## Options

```text
-X, --request METHOD   HTTP method (default GET, or POST when -d is given)
-H, --header 'K: V'    request header, repeatable
-d, --data DATA        request body; @file reads a file, @- reads stdin
-k, --insecure         skip TLS verification
    --timeout SECS     read timeout (default: wait forever)
    --last-event-id ID send Last-Event-ID header
    --profile P        auto | openai | responses | gateway | generic
    --raw              also print each event's full JSON
    --json-theme NAME  render JSON with a pygments theme (dracula, monokai,
                       nord, github-dark, …); default is a built-in palette
    --color            force colors (overrides NO_COLOR and pipes)
    --no-color         disable colors
    --events           compact line per event in accumulating profiles
    --no-md            don't render accumulated text as markdown
    --no-live          disable the live tail region
    --idle-exit SECS   exit after SECS without a new event (keepalives don't
                       count) — for scripted watching of finite streams
-q, --quiet            suppress the end-of-stream summary
```

## Try it without a server

```sh
uv run sseurl tests/fixtures/openai-chat.sse
uv run sseurl tests/fixtures/gateway.sse
uv run python examples/demo_server.py &   # serves fixtures over HTTP with delays
uv run sseurl http://127.0.0.1:8399/openai-chat
```

## Development

```sh
uv sync
uv run pytest
```
