Skip to main content

Python SDK for LIME 2.0 agent authentication. Zero-config, Proof-of-Work auto-solve, async-first.

Project description

LIME Agents SDK

PyPI version Python versions License: MIT CI

Official Python SDK for LIME agent workers. Async-first client with one public login method: fetch Proof-of-Work challenge, solve SHA-256 PoW, submit approval with retries.

Installation

pip install lime-agents-sdk

Install the latest commit from GitHub:

pip install git+https://github.com/Mawyxx/lime-agents-sdk.git

Requirements: Python 3.10+

Quick start

Examples use readable names (Lime, login) on top of the shipped API (LimeAgent, login). See API reference for exact types and parameters.

Minimal

from lime_agents import LimeAgent as _LimeAgent


class Lime(_LimeAgent):
    """aiogram-style client: token first, login() entrypoint."""

    def __init__(self, token: str):
        super().__init__(agent_token=token)

    async def login(self, request_id: str):
        return await self.login(request_id)


AGENT_TOKEN = "at_..."  # LIME Owner Portal → agent token (copy once)

async def login_to_site(request_id: str) -> str:
    """Agent confirms sign-in to a site. Returns status."""
    lime = Lime(AGENT_TOKEN)
    try:
        result = await lime.login(request_id)
        return result.status  # "DELIVERED"
    finally:
        await lime.aclose()

Production

from lime_agents import LimeAgent as _LimeAgent, PowTimeoutError, ApiError


class Lime(_LimeAgent):
    def __init__(self, token: str):
        super().__init__(agent_token=token)

    async def login(self, request_id: str):
        return await self.login(request_id)


AGENT_TOKEN = "at_..."


class Agent:
    """Autonomous worker that signs in to sites when asked."""

    def __init__(self):
        self.lime = Lime(AGENT_TOKEN)

    async def on_login_required(self, request_id: str) -> str | None:
        """Site requires login — agent confirms."""
        try:
            result = await self.lime.login(request_id)
            return result.status
        except PowTimeoutError:
            # Proof-of-Work exceeded pow_timeout (default 10s) — retry once
            try:
                result = await self.lime.login(request_id)
                return result.status
            except PowTimeoutError:
                return None
        except ApiError as exc:
            print(f"[{exc.code}] {exc.message}")
            return None

Authentication

The SDK authenticates agent HTTP calls with the X-Agent-Token header.

Resolution order:

  1. Constructor argument agent_token="at_..."
  2. Environment variable LIME_AGENT_TOKEN

If neither is set (or the value is empty after trimming), construction raises AuthenticationError:

from lime_agents import LimeAgent, AuthenticationError

try:
    agent = LimeAgent()
except AuthenticationError as exc:
    print(exc.message)

Obtain the agent token once when registering an agent in the LIME owner portal. Store it as a server-side secret in your worker environment.

Integration pattern: Headless agent

Typical embedding: hold one LimeAgent per worker process and call login() when a login request arrives.

from lime_agents import LimeAgent


class TradingAgent:
    def __init__(self, token: str):
        self.lime = LimeAgent(agent_token=token)

    async def on_login_required(self, request_id: str) -> str:
        result = await self.lime.login(request_id)
        return result.status

The site backend creates the request (POST /modules/agent-login/requests), delivers login_request_id to your worker, and long-polls events until status becomes DELIVERED. Your worker only runs the login step above.

Production deployment

For agent workers handling many login jobs, create one LimeAgent per worker process at startup. Do not use async with LimeAgent() inside each job handler — that tears down the HTTP client after every login request.

  • Instantiate LimeAgent once when the worker starts.
  • Reuse the same instance for all login() and get_profile() calls.
  • Optionally pass a shared httpx.AsyncClient via http_client for connection pooling.
from lime_agents import LimeAgent

# Created once at worker startup
agent = LimeAgent()

# Reused in every task
async def handle_login(request_id: str) -> str:
    result = await agent.login(request_id)
    return result.status

Call agent.aclose() only on worker shutdown (or close your injected http_client yourself).

API reference

LimeAgent

Async client for agent-runtime operations (login confirmation, read profile).

Constructor

All arguments are keyword-only.

Parameter Type Default Description
agent_token str | None None Agent secret. Falls back to LIME_AGENT_TOKEN.
base_url str | None None API root including /api/v1. Falls back to LIME_API_BASE, then https://lime.pics/api/v1.
timeout float 30.0 Per-request HTTP timeout in seconds (httpx).
max_retries int 3 Maximum retries on transient network errors and HTTP 408/429/5xx.
pow_timeout float 10.0 Wall-clock budget in seconds for the PoW solver loop.
http_client httpx.AsyncClient | None None Inject a custom async HTTP client (tests, corporate proxy/TLS). When omitted, the SDK creates and owns a client.
agent = LimeAgent(
    agent_token="at_live_...",
    base_url="https://lime.pics/api/v1",
    timeout=60.0,
    max_retries=5,
    pow_timeout=15.0,
)

Context manager: async with LimeAgent() as agent: calls aclose() on exit. Call await agent.aclose() manually when not using a context manager.

async login(request_id: str) -> ApprovalResult

Confirms a site login request on behalf of the agent.

Internal steps:

  1. GET /auth/requests/{request_id} (public, no auth) — read pow_challenge, pow_difficulty
  2. Solve PoW: find nonce such that int(SHA256(challenge + nonce), 16) < 2**(256 - difficulty)
  3. POST /modules/agent-login/requests/{request_id}/approve with X-Agent-Token and body {"pow_nonce": "<nonce>"}

Parameters:

Name Type Description
request_id str Login request ID from the site backend (login_request_id from create).

Returns: ApprovalResult with FSM status (typically DELIVERED after successful login confirmation).

from lime_agents import LimeAgent, PowTimeoutError, ApiError

async with LimeAgent() as agent:
    try:
        result = await agent.login("550e8400-e29b-41d4-a716-446655440000")
        print(result.status, result.approved_agent_id)
    except PowTimeoutError:
        print("PoW not solved in time; increase pow_timeout or retry")
    except ApiError as exc:
        print(exc.code, exc.http_status, exc.message)

async get_profile() -> AgentProfile

Returns the authenticated agent's Core profile.

HTTP: GET /core/agents/me/profile with X-Agent-Token.

async with LimeAgent() as agent:
    profile = await agent.get_profile()
    print(profile.agent_id)
    print(profile.owner_kyc_level)
    print(profile.agent_reputation)

Types

ApprovalResult

Frozen dataclass returned by login().

Field Type Description
request_id str Login request ID
site_id str Site that created the request
status str FSM value, e.g. APPROVED, DELIVERED
expires_at datetime Request expiry (timezone-aware when API sends offset)
approved_agent_id str | None Agent that approved the request

AgentProfile

Frozen dataclass returned by get_profile(). Matches GET /core/agents/me/profile response fields.

Field Type Description
agent_id str Agent identifier
owner_id str Owning LIME user
display_name str | None Public display name
avatar_url str | None Avatar URL
description str | None Public description
owner_kyc_level int | None Owner KYC level synced from Foundation
agent_reputation int | None Reputation score

Error handling

All SDK exceptions inherit from LimeError. Each carries message, and optionally code, http_status, and detail (API envelope).

Exception When
LimeError Base class; transport failures after retries, malformed JSON
AuthenticationError Missing/empty token at construct; HTTP 401; MISSING_AGENT_TOKEN, INVALID_AGENT_TOKEN
PowTimeoutError PoW solver exceeded pow_timeout
RateLimitError HTTP 429 / RATE_LIMIT_EXCEEDED
ApiError Other API errors (ok: false envelope)

ApiError attributes: code, message, http_status, detail.

import asyncio

from lime_agents import (
    LimeAgent,
    LimeError,
    AuthenticationError,
    PowTimeoutError,
    RateLimitError,
    ApiError,
)

async def run() -> None:
    try:
        async with LimeAgent() as agent:
            await agent.login("lr_abc123")
    except AuthenticationError as exc:
        print("auth:", exc.message)
    except PowTimeoutError as exc:
        print("pow:", exc.message)
    except RateLimitError as exc:
        print("rate limit:", exc.http_status)
    except ApiError as exc:
        print(f"api [{exc.http_status}] {exc.code}: {exc.message}")
    except LimeError as exc:
        print("sdk:", exc.message)

asyncio.run(run())

Non-retried HTTP statuses: 400, 401, 403, 404, 409 (e.g. INVALID_POW, SITE_LOGIN_CONFLICT).

Configuration

Environment variables

Variable Required Description
LIME_AGENT_TOKEN Yes (unless agent_token= passed) Agent secret (at_...)
LIME_API_BASE No API root, e.g. https://lime.pics/api/v1

Constructor tuning

Use case Suggestion
Slow network Increase timeout (e.g. 60.0)
Flaky upstream Increase max_retries (e.g. 5)
High PoW difficulty / slow CPU Increase pow_timeout (e.g. 30.0)
Staging / self-hosted API Set base_url or LIME_API_BASE

Logging

HTTP and retry events are logged under the lime logger (not lime_agents):

import logging

logging.basicConfig(level=logging.DEBUG)
logging.getLogger("lime").setLevel(logging.DEBUG)

At DEBUG, the client logs request method and URL. Tokens, pow_challenge, and pow_nonce are never logged.

Advanced usage

Custom httpx.AsyncClient

Inject a client for custom TLS, proxies, or tests. You own the client lifecycle when injecting; the SDK does not close an injected client.

import httpx
from lime_agents import LimeAgent


async def login_with_proxy() -> None:
    client = httpx.AsyncClient(
        timeout=60.0,
        verify="/path/to/corporate-ca.pem",
        proxy="http://proxy.corp.example:8080",
    )
    agent = LimeAgent(agent_token="at_...", http_client=client)
    try:
        await agent.login("lr_abc123")
    finally:
        await client.aclose()

Retries and timeouts

Retries use exponential backoff with jitter on connection errors, timeouts, and HTTP 408, 429, 500, 502, 503, 504. Each retry attempt is bounded by max_retries (default 3).

agent = LimeAgent(
    agent_token="at_...",
    max_retries=5,
    timeout=45.0,
    pow_timeout=20.0,
)

PoW debugging

PoW runs in a thread pool (asyncio.to_thread) so the event loop stays responsive. To observe HTTP flow (not nonce values):

import logging

logging.getLogger("lime").setLevel(logging.DEBUG)

If PowTimeoutError occurs, increase pow_timeout or verify pow_difficulty from GET /auth/requests/{id} (default 15 on production).

Development

pip install -e ".[dev]"
ruff check src tests
mypy src/lime_agents
pytest --cov=lime_agents --cov-fail-under=100

Live integration

pip install lime-agents-sdk lime-sites-sdk
LIME_INTEGRATION=1 pytest tests/integration -v

Full cycle (both SDKs): see lime-sait-sdk tests/integration/test_full_cycle_both_sdks.py — site LimeSite + agent LimeAgent against https://lime.pics/api/v1. From the LIME monorepo, run on the production VPS (SSE-safe): python scripts/_run_both_sdks_integration_remote.py.

Links

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

lime_agents_sdk-0.2.0.tar.gz (15.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

lime_agents_sdk-0.2.0-py3-none-any.whl (11.9 kB view details)

Uploaded Python 3

File details

Details for the file lime_agents_sdk-0.2.0.tar.gz.

File metadata

  • Download URL: lime_agents_sdk-0.2.0.tar.gz
  • Upload date:
  • Size: 15.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lime_agents_sdk-0.2.0.tar.gz
Algorithm Hash digest
SHA256 b2ecbef4cde8870321e8c3ce17c537a81bd0ff92e513f364f56538188d69ff55
MD5 ba6a8ac81a1b26a35046db7d0262f920
BLAKE2b-256 21d3e84051ccd875ac9c675d7fc371567db96aca61cf82a683fb6bbecf29e847

See more details on using hashes here.

File details

Details for the file lime_agents_sdk-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: lime_agents_sdk-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 11.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for lime_agents_sdk-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 fe4c0994c406228265b7af98c1419ac14cd4f46d2ef455de9f069e2d22e2e042
MD5 56e83f2e3e78a0dd466af2d8bdf87cd1
BLAKE2b-256 f190bba72ff7d69b014b2246633089ae32591141ec99a8936a49252192b672d6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page