Metadata-Version: 2.4
Name: marona
Version: 0.2.8
Summary: Official Python client SDK for Marona-compatible AI runtimes and Hub integrations.
Author: Blessing Nyuwani
License-Expression: MIT
Project-URL: Homepage, https://www.marona.ai
Project-URL: Repository, https://github.com/BlessingNyuwani/edge-node-service
Project-URL: Documentation, https://hub.marona.ai
Keywords: marona,sdk,mcp,agents,ai,runtime
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
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 :: Libraries :: Python Modules
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: httpx<1.0,>=0.28
Provides-Extra: dev
Requires-Dist: pytest<9.0,>=8.0; extra == "dev"
Requires-Dist: build<2.0,>=1.2; extra == "dev"
Requires-Dist: twine<7.0,>=6.0; extra == "dev"
Dynamic: license-file

# marona

Official Python client for Marona-compatible AI runtimes and Hub integrations.

Use `marona` to build web apps, mobile backends, WhatsApp bots, desktop apps,
devices, smart glasses, and agents that need one API for online, offline, and
hybrid AI execution.

## Install

```bash
pip install marona
```

## Complete Example

This example shows the normal flow for a developer application:

1. Create a Marona client.
2. Sync Hub metadata into the local cache.
3. Connect approved Hub apps by app ID.
4. Send a user message through the runtime.
5. Print the final assistant response.

```python
import asyncio
import os

from marona import Marona


async def main() -> None:
    api_key = os.environ["MARONA_API_KEY"]
    identity_token = os.getenv("MARONA_IDENTITY_TOKEN")

    async with Marona(api_key=api_key, mode="online") as marona:
        await marona.sync(
            interface="api",
            identity_token=identity_token,
            conversation_id="quickstart",
        )

        tools = await marona.hub.connect(
            ["sda-books", "zimsec"],
            adapter="tools",
        )

        response = await marona.message(
            "Find chapter 1 of Steps to Christ and explain the main point.",
            interface="api",
            identity_token=identity_token,
            conversation_id="quickstart",
            tools=tools,
        )

        print(response.text)


asyncio.run(main())
```

Run it:

```bash
export MARONA_API_KEY="mrn_live_..."
python app.py
```

If the user has paired an interface or connected private apps, pass their
identity token as `MARONA_IDENTITY_TOKEN`. Public apps can still work without a
user identity when they do not require personal authorization.

## Pair A User

Use pairing when an interface needs to become the same user across web, mobile,
WhatsApp, wearables, or another client surface.

```python
async with Marona(api_key=os.environ["MARONA_API_KEY"]) as marona:
    pairing = await marona.start_pairing(
        interface="web",
        device_name="Customer web chat",
    )

    print(pairing.display_code)
    print(pairing.whatsapp_url)

    status = await marona.pairing_status(pairing.pairing_id)
    print(status.status)
```

After the user confirms the pairing, store the returned identity token in your
application and pass it to `marona.message(...)`.

## Online, Offline, And Hybrid Modes

Choose one runtime mode for the client:

- `online`: use online runtime and online app routes.
- `offline`: use only local cache, local/private models, and installed offline-capable app targets.
- `hybrid`: try local/private execution first, then use online runtime when allowed.

Apps also declare one availability mode:

- `online`: online only.
- `offline`: offline only.
- `hybrid`: online and offline capable.

Hybrid is a single mode. Do not declare `online + offline + hybrid`; declare
`hybrid`.

## Hybrid Or Offline With A Local/Private Model

Register a local or private model endpoint once, then use it as the default for
hybrid or offline execution.

```python
async with Marona(api_key=os.environ["MARONA_API_KEY"], mode="hybrid") as marona:
    await marona.sync(interface="api")

    marona.models.register(
        name="office-model",
        endpoint="http://localhost:9379",
    )
    marona.models.use("office-model")

    tools = await marona.hub.connect(["sda-books", "zimsec"], adapter="tools")

    response = await marona.message(
        "Summarize the chapter about faith.",
        interface="desktop",
        conversation_id="local-demo",
        tools=tools,
    )

    print(response.text)
```

In `offline` mode, Marona never calls public cloud runtime. If a model or an
offline-capable app target is missing, the client returns a clear offline error.

## Attach Files

```python
from pathlib import Path

from marona import RuntimeAttachment


attachment = RuntimeAttachment.from_bytes(
    Path("proposal.pdf").read_bytes(),
    filename="proposal.pdf",
    mime_type="application/pdf",
    kind="document",
)

response = await marona.message(
    "Summarize this proposal.",
    attachments=[attachment],
)
```

## Interface Names

`interface` identifies the client surface making the request. Standard values:

- `api`
- `web`
- `mobile_app`
- `desktop`
- `whatsapp`

Future devices can use custom lowercase slugs such as `smart_glasses`,
`vehicle_console`, or `kiosk`.

## Related Packages

- Python client: `marona`, import `marona`
- Dart client: `marona`, import `package:marona/marona.dart`
- TypeScript client: `marona`, import `Marona` from `"marona"`
- Developer SDK for building apps: `marona-sdk`, import `marona_sdk`
