From 9af4d222d86d148edf3990aa6e7060cda526d86f Mon Sep 17 00:00:00 2001 From: "balogh.adam@icloud.com" Date: Tue, 10 Feb 2026 11:49:52 +0100 Subject: [PATCH 1/4] twins api --- src/opengradient/__init__.py | 3 +- src/opengradient/cli.py | 4 +- src/opengradient/client/__init__.py | 3 +- src/opengradient/client/client.py | 8 +++ src/opengradient/client/twins.py | 96 +++++++++++++++++++++++++++++ 5 files changed, 109 insertions(+), 5 deletions(-) create mode 100644 src/opengradient/client/twins.py diff --git a/src/opengradient/__init__.py b/src/opengradient/__init__.py index 375581b..3236897 100644 --- a/src/opengradient/__init__.py +++ b/src/opengradient/__init__.py @@ -48,11 +48,12 @@ ## Client Namespaces -The `opengradient.client.Client` object exposes three namespaces: +The `opengradient.client.Client` object exposes four namespaces: - **`opengradient.client.llm`** -- Verifiable LLM chat and completion via TEE-verified execution with x402 payments - **`opengradient.client.alpha`** -- On-chain ONNX model inference, workflow deployment, and scheduled ML model execution (only available on the Alpha Testnet) - **`opengradient.client.model_hub`** -- Model repository management +- **`opengradient.client.twins`** -- Digital twins chat via OpenGradient verifiable inference (requires twins API key) ## Model Hub (requires email auth) diff --git a/src/opengradient/cli.py b/src/opengradient/cli.py index 54225a7..72ffec5 100644 --- a/src/opengradient/cli.py +++ b/src/opengradient/cli.py @@ -324,9 +324,7 @@ def infer(ctx, model_cid: str, inference_mode: str, input_data, input_file: Path model_input = json.load(file) click.echo(f'Running {inference_mode} inference for model "{model_cid}"') - inference_result = client.alpha.infer( - model_cid=model_cid, inference_mode=InferenceModes[inference_mode], model_input=model_input - ) + inference_result = client.alpha.infer(model_cid=model_cid, inference_mode=InferenceModes[inference_mode], model_input=model_input) click.echo() # Add a newline for better spacing click.secho("✅ Transaction successful", fg="green", bold=True) diff --git a/src/opengradient/client/__init__.py b/src/opengradient/client/__init__.py index d7aacdf..a4ffae3 100644 --- a/src/opengradient/client/__init__.py +++ b/src/opengradient/client/__init__.py @@ -3,11 +3,12 @@ ## Overview -The `opengradient.client.client.Client` class provides unified access to three service namespaces: +The `opengradient.client.client.Client` class provides unified access to four service namespaces: - **`opengradient.client.llm`** -- LLM chat and text completion with TEE-verified execution and x402 payment settlement - **`opengradient.client.model_hub`** -- Model repository management: create, version, and upload ML models - **`opengradient.client.alpha`** -- Alpha Testnet features: on-chain ONNX model inference (VANILLA, TEE, ZKML modes), workflow deployment, and scheduled ML model execution +- **`opengradient.client.twins`** -- Digital twins chat via OpenGradient verifiable inference ## Usage diff --git a/src/opengradient/client/client.py b/src/opengradient/client/client.py index 31086f6..472bff7 100644 --- a/src/opengradient/client/client.py +++ b/src/opengradient/client/client.py @@ -14,6 +14,7 @@ from .alpha import Alpha from .llm import LLM from .model_hub import ModelHub +from .twins import Twins class Client: @@ -40,11 +41,15 @@ class Client: alpha: Alpha """Alpha Testnet features including on-chain inference, workflow management, and ML model execution.""" + twins: Twins + """Digital twins chat via OpenGradient verifiable inference.""" + def __init__( self, private_key: str, email: Optional[str] = None, password: Optional[str] = None, + twins_api_key: Optional[str] = None, rpc_url: str = DEFAULT_RPC_URL, api_url: str = DEFAULT_API_URL, contract_address: str = DEFAULT_INFERENCE_CONTRACT_ADDRESS, @@ -58,6 +63,7 @@ def __init__( private_key: Private key for OpenGradient transactions. email: Email for Model Hub authentication. Optional. password: Password for Model Hub authentication. Optional. + twins_api_key: API key for digital twins chat (twin.fun). Optional. rpc_url: RPC URL for the blockchain network. api_url: API URL for the OpenGradient API. contract_address: Inference contract address. @@ -87,3 +93,5 @@ def __init__( api_url=api_url, ) + if twins_api_key is not None: + self.twins = Twins(api_key=twins_api_key) diff --git a/src/opengradient/client/twins.py b/src/opengradient/client/twins.py new file mode 100644 index 0000000..4d6dc0b --- /dev/null +++ b/src/opengradient/client/twins.py @@ -0,0 +1,96 @@ +"""Digital twins chat via OpenGradient verifiable inference.""" + +from typing import Dict, List, Optional + +import httpx + +from ..types import TEE_LLM, TextGenerationOutput +from .exceptions import OpenGradientError + +TWINS_API_BASE_URL = "https://chat-api.memchat.io" + + +class Twins: + """ + Digital twins chat namespace. + + Provides access to digital twin conversations from twin.fun, + backed by OpenGradient verifiable inference. + + Usage: + client = og.init(private_key="0x...", twins_api_key="your-api-key") + response = client.twins.chat( + twin_id="0x1abd463fd6244be4a1dc0f69e0b70cd5", + model=og.TEE_LLM.GROK_4_1_FAST_NON_REASONING, + messages=[{"role": "user", "content": "What do you think about AI?"}], + max_tokens=1000, + ) + print(response.chat_output["content"]) + """ + + def __init__(self, api_key: str): + self._api_key = api_key + + def chat( + self, + twin_id: str, + model: TEE_LLM, + messages: List[Dict], + temperature: Optional[float] = None, + max_tokens: Optional[int] = None, + ) -> TextGenerationOutput: + """ + Chat with a digital twin. + + Args: + twin_id: The unique identifier of the digital twin. + model: The model to use for inference (e.g., TEE_LLM.GROK_4_1_FAST_NON_REASONING). + messages: The conversation messages to send. + temperature: Sampling temperature. Optional. + max_tokens: Maximum number of tokens for the response. Optional. + + Returns: + TextGenerationOutput: Generated text results including chat_output and finish_reason. + + Raises: + OpenGradientError: If the request fails. + """ + url = f"{TWINS_API_BASE_URL}/api/v1/twins/{twin_id}/chat" + headers = { + "Content-Type": "application/json", + "X-API-Key": self._api_key, + } + + payload: Dict = { + "model": model.value, + "messages": messages, + } + if temperature is not None: + payload["temperature"] = temperature + if max_tokens is not None: + payload["max_tokens"] = max_tokens + + try: + response = httpx.post(url, json=payload, headers=headers, timeout=60) + response.raise_for_status() + result = response.json() + + choices = result.get("choices") + if not choices: + raise OpenGradientError(f"Invalid response: 'choices' missing or empty in {result}") + + return TextGenerationOutput( + transaction_hash="", + finish_reason=choices[0].get("finish_reason"), + chat_output=choices[0].get("message"), + payment_hash=None, + ) + except OpenGradientError: + raise + except httpx.HTTPStatusError as e: + raise OpenGradientError( + f"Twins chat request failed: {e.response.status_code} {e.response.text}", + status_code=e.response.status_code, + ) + except Exception as e: + raise OpenGradientError(f"Twins chat request failed: {str(e)}") From 135582249045b3f548d7cc376b22c01c44cd843d Mon Sep 17 00:00:00 2001 From: "balogh.adam@icloud.com" Date: Tue, 10 Feb 2026 11:51:36 +0100 Subject: [PATCH 2/4] docs --- CLAUDE.md | 4 +-- docs/opengradient/client/client.md | 6 ++-- docs/opengradient/client/index.md | 10 ++++-- docs/opengradient/client/twins.md | 51 ++++++++++++++++++++++++++++++ docs/opengradient/index.md | 7 ++-- 5 files changed, 69 insertions(+), 9 deletions(-) create mode 100644 docs/opengradient/client/twins.md diff --git a/CLAUDE.md b/CLAUDE.md index 14065b0..41940d0 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -4,7 +4,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co ## Project Overview -OpenGradient Python SDK - A decentralized model management and inference platform SDK. The SDK enables programmatic access to model repositories and decentralized AI infrastructure, including end-to-end verified AI execution. +OpenGradient Python SDK - A decentralized model management and inference platform SDK. The SDK enables programmatic access to model repositories and decentralized AI infrastructure, including end-to-end verified AI execution. Use virtualenv for dependency management locally (in `venv` folder). ## Development Commands @@ -108,7 +108,7 @@ User configuration stored via `opengradient config init` wizard. ## Documentation (pdoc) -Docs are generated with `pdoc3` using a custom Mako template at `templates/text.mako`. Run `make docs` to regenerate into `docs/`. +Docs are generated with `pdoc3` using a custom Mako template at `templates/text.mako`. Run `make docs` to regenerate into `docs/`. Do not edit generated documentation files in `docs/` by hand. ### Cross-referencing in docstrings diff --git a/docs/opengradient/client/client.md b/docs/opengradient/client/client.md index 91e0ad4..3924cef 100644 --- a/docs/opengradient/client/client.md +++ b/docs/opengradient/client/client.md @@ -21,7 +21,7 @@ blockchain private key and optional Model Hub credentials. #### Constructor ```python -def __init__(private_key: str, email: Optional[str] = None, password: Optional[str] = None, rpc_url: str = 'https://ogevmdevnet.opengradient.ai', api_url: str = 'https://sdk-devnet.opengradient.ai', contract_address: str = '0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE', og_llm_server_url: Optional[str] = 'https://llmogevm.opengradient.ai', og_llm_streaming_server_url: Optional[str] = 'https://llmogevm.opengradient.ai') +def __init__(private_key: str, email: Optional[str] = None, password: Optional[str] = None, twins_api_key: Optional[str] = None, rpc_url: str = 'https://ogevmdevnet.opengradient.ai', api_url: str = 'https://sdk-devnet.opengradient.ai', contract_address: str = '0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE', og_llm_server_url: Optional[str] = 'https://llmogevm.opengradient.ai', og_llm_streaming_server_url: Optional[str] = 'https://llmogevm.opengradient.ai') ``` **Arguments** @@ -29,6 +29,7 @@ def __init__(private_key: str, email: Optional[str] = None, password: Optio * **`private_key`**: Private key for OpenGradient transactions. * **`email`**: Email for Model Hub authentication. Optional. * **`password`**: Password for Model Hub authentication. Optional. +* **`twins_api_key`**: API key for digital twins chat (twin.fun). Optional. * **`rpc_url`**: RPC URL for the blockchain network. * **`api_url`**: API URL for the OpenGradient API. * **`contract_address`**: Inference contract address. @@ -39,4 +40,5 @@ def __init__(private_key: str, email: Optional[str] = None, password: Optio * [**`alpha`**](./alpha): Alpha Testnet features including on-chain inference, workflow management, and ML model execution. * [**`llm`**](./llm): LLM chat and completion via TEE-verified execution. -* [**`model_hub`**](./model_hub): Model Hub for creating, versioning, and uploading ML models. \ No newline at end of file +* [**`model_hub`**](./model_hub): Model Hub for creating, versioning, and uploading ML models. +* [**`twins`**](./twins): Digital twins chat via OpenGradient verifiable inference. \ No newline at end of file diff --git a/docs/opengradient/client/index.md b/docs/opengradient/client/index.md index e3fbf7a..2b3ea2d 100644 --- a/docs/opengradient/client/index.md +++ b/docs/opengradient/client/index.md @@ -10,11 +10,12 @@ OpenGradient Client -- the central entry point to all SDK services. ## Overview -The [Client](./client) class provides unified access to three service namespaces: +The [Client](./client) class provides unified access to four service namespaces: - **[llm](./llm)** -- LLM chat and text completion with TEE-verified execution and x402 payment settlement - **[model_hub](./model_hub)** -- Model repository management: create, version, and upload ML models - **[alpha](./alpha)** -- Alpha Testnet features: on-chain ONNX model inference (VANILLA, TEE, ZKML modes), workflow deployment, and scheduled ML model execution +- **[twins](./twins)** -- Digital twins chat via OpenGradient verifiable inference ## Usage @@ -52,6 +53,7 @@ repo = client.model_hub.create_model("my-model", "A price prediction model") * [exceptions](./exceptions): Exception types for OpenGradient SDK errors. * [llm](./llm): LLM chat and completion via TEE-verified execution with x402 payments. * [model_hub](./model_hub): Model Hub for creating, versioning, and uploading ML models. +* [twins](./twins): Digital twins chat via OpenGradient verifiable inference. ## Classes @@ -66,7 +68,7 @@ blockchain private key and optional Model Hub credentials. #### Constructor ```python -def __init__(private_key: str, email: Optional[str] = None, password: Optional[str] = None, rpc_url: str = 'https://ogevmdevnet.opengradient.ai', api_url: str = 'https://sdk-devnet.opengradient.ai', contract_address: str = '0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE', og_llm_server_url: Optional[str] = 'https://llmogevm.opengradient.ai', og_llm_streaming_server_url: Optional[str] = 'https://llmogevm.opengradient.ai') +def __init__(private_key: str, email: Optional[str] = None, password: Optional[str] = None, twins_api_key: Optional[str] = None, rpc_url: str = 'https://ogevmdevnet.opengradient.ai', api_url: str = 'https://sdk-devnet.opengradient.ai', contract_address: str = '0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE', og_llm_server_url: Optional[str] = 'https://llmogevm.opengradient.ai', og_llm_streaming_server_url: Optional[str] = 'https://llmogevm.opengradient.ai') ``` **Arguments** @@ -74,6 +76,7 @@ def __init__(private_key: str, email: Optional[str] = None, password: Optio * **`private_key`**: Private key for OpenGradient transactions. * **`email`**: Email for Model Hub authentication. Optional. * **`password`**: Password for Model Hub authentication. Optional. +* **`twins_api_key`**: API key for digital twins chat (twin.fun). Optional. * **`rpc_url`**: RPC URL for the blockchain network. * **`api_url`**: API URL for the OpenGradient API. * **`contract_address`**: Inference contract address. @@ -84,4 +87,5 @@ def __init__(private_key: str, email: Optional[str] = None, password: Optio * [**`alpha`**](./alpha): Alpha Testnet features including on-chain inference, workflow management, and ML model execution. * [**`llm`**](./llm): LLM chat and completion via TEE-verified execution. -* [**`model_hub`**](./model_hub): Model Hub for creating, versioning, and uploading ML models. \ No newline at end of file +* [**`model_hub`**](./model_hub): Model Hub for creating, versioning, and uploading ML models. +* [**`twins`**](./twins): Digital twins chat via OpenGradient verifiable inference. \ No newline at end of file diff --git a/docs/opengradient/client/twins.md b/docs/opengradient/client/twins.md new file mode 100644 index 0000000..0e57aad --- /dev/null +++ b/docs/opengradient/client/twins.md @@ -0,0 +1,51 @@ +--- +outline: [2,3] +--- + +[opengradient](../index) / [client](./index) / twins + +# Package opengradient.client.twins + +Digital twins chat via OpenGradient verifiable inference. + +## Classes + +### `Twins` + +Digital twins chat namespace. + +Provides access to digital twin conversations from twin.fun, +backed by OpenGradient verifiable inference. + +#### Constructor + +```python +def __init__(api_key: str) +``` + +#### Methods + +--- + +#### `chat()` + +```python +def chat(self, twin_id: str, model: `TEE_LLM`, messages: List[Dict], temperature: Optional[float] = None, max_tokens: Optional[int] = None) ‑> `TextGenerationOutput` +``` +Chat with a digital twin. + +**Arguments** + +* **`twin_id`**: The unique identifier of the digital twin. +* **`model`**: The model to use for inference (e.g., TEE_LLM.GROK_4_1_FAST_NON_REASONING). +* **`messages`**: The conversation messages to send. +* **`temperature`**: Sampling temperature. Optional. +* **`max_tokens`**: Maximum number of tokens for the response. Optional. + +**Returns** + +TextGenerationOutput: Generated text results including chat_output and finish_reason. + +**Raises** + +* **`OpenGradientError`**: If the request fails. \ No newline at end of file diff --git a/docs/opengradient/index.md b/docs/opengradient/index.md index 33641cb..ce7cb01 100644 --- a/docs/opengradient/index.md +++ b/docs/opengradient/index.md @@ -57,11 +57,12 @@ print(result.model_output) ## Client Namespaces -The [Client](./client/index) object exposes three namespaces: +The [Client](./client/index) object exposes four namespaces: - **[llm](./client/llm)** -- Verifiable LLM chat and completion via TEE-verified execution with x402 payments - **[alpha](./client/alpha)** -- On-chain ONNX model inference, workflow deployment, and scheduled ML model execution (only available on the Alpha Testnet) - **[model_hub](./client/model_hub)** -- Model repository management +- **[twins](./client/twins)** -- Digital twins chat via OpenGradient verifiable inference (requires twins API key) ## Model Hub (requires email auth) @@ -126,7 +127,7 @@ blockchain private key and optional Model Hub credentials. #### Constructor ```python -def __init__(private_key: str, email: Optional[str] = None, password: Optional[str] = None, rpc_url: str = 'https://ogevmdevnet.opengradient.ai', api_url: str = 'https://sdk-devnet.opengradient.ai', contract_address: str = '0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE', og_llm_server_url: Optional[str] = 'https://llmogevm.opengradient.ai', og_llm_streaming_server_url: Optional[str] = 'https://llmogevm.opengradient.ai') +def __init__(private_key: str, email: Optional[str] = None, password: Optional[str] = None, twins_api_key: Optional[str] = None, rpc_url: str = 'https://ogevmdevnet.opengradient.ai', api_url: str = 'https://sdk-devnet.opengradient.ai', contract_address: str = '0x8383C9bD7462F12Eb996DD02F78234C0421A6FaE', og_llm_server_url: Optional[str] = 'https://llmogevm.opengradient.ai', og_llm_streaming_server_url: Optional[str] = 'https://llmogevm.opengradient.ai') ``` **Arguments** @@ -134,6 +135,7 @@ def __init__(private_key: str, email: Optional[str] = None, password: Optio * **`private_key`**: Private key for OpenGradient transactions. * **`email`**: Email for Model Hub authentication. Optional. * **`password`**: Password for Model Hub authentication. Optional. +* **`twins_api_key`**: API key for digital twins chat (twin.fun). Optional. * **`rpc_url`**: RPC URL for the blockchain network. * **`api_url`**: API URL for the OpenGradient API. * **`contract_address`**: Inference contract address. @@ -145,6 +147,7 @@ def __init__(private_key: str, email: Optional[str] = None, password: Optio * [**`alpha`**](./client/alpha): Alpha Testnet features including on-chain inference, workflow management, and ML model execution. * [**`llm`**](./client/llm): LLM chat and completion via TEE-verified execution. * [**`model_hub`**](./client/model_hub): Model Hub for creating, versioning, and uploading ML models. +* [**`twins`**](./client/twins): Digital twins chat via OpenGradient verifiable inference. ### `InferenceMode` From ed48016dd2c85036375de9db39e2df80d792bd1c Mon Sep 17 00:00:00 2001 From: "balogh.adam@icloud.com" Date: Tue, 10 Feb 2026 11:56:08 +0100 Subject: [PATCH 3/4] twins --- CLAUDE.md | 2 ++ examples/twins_chat.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 examples/twins_chat.py diff --git a/CLAUDE.md b/CLAUDE.md index 41940d0..5559f9a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -110,6 +110,8 @@ User configuration stored via `opengradient config init` wizard. Docs are generated with `pdoc3` using a custom Mako template at `templates/text.mako`. Run `make docs` to regenerate into `docs/`. Do not edit generated documentation files in `docs/` by hand. +There are concrete example scripts using the SDK in the examples/ folder that highlight how to use the SDK and provides a starting point for developers. + ### Cross-referencing in docstrings To link to another module or class from a docstring, use fully qualified names in backticks: diff --git a/examples/twins_chat.py b/examples/twins_chat.py new file mode 100644 index 0000000..26b64c1 --- /dev/null +++ b/examples/twins_chat.py @@ -0,0 +1,28 @@ +## Chat with digital twins from twin.fun via OpenGradient verifiable inference + +import os + +import opengradient as og + +client = og.init( + private_key=os.environ.get("OG_PRIVATE_KEY"), + twins_api_key=os.environ.get("TWINS_API_KEY"), +) + +# Chat with Elon Musk +elon = client.twins.chat( + twin_id="0x1abd463fd6244be4a1dc0f69e0b70cd5", + model=og.TEE_LLM.GROK_4_1_FAST_NON_REASONING, + messages=[{"role": "user", "content": "What do you think about AI?"}], + max_tokens=1000, +) +print(f"Elon: {elon.chat_output['content']}") + +# Chat with Donald Trump +trump = client.twins.chat( + twin_id="0x66ae99aae4324ed580b2787ac5e811f6", + model=og.TEE_LLM.GROK_4_1_FAST_NON_REASONING, + messages=[{"role": "user", "content": "What's your plan for America?"}], + max_tokens=1000, +) +print(f"Trump: {trump.chat_output['content']}") From 6e655485e00baf614724e58349db76b2b572aad7 Mon Sep 17 00:00:00 2001 From: "balogh.adam@icloud.com" Date: Tue, 10 Feb 2026 11:57:17 +0100 Subject: [PATCH 4/4] link --- examples/twins_chat.py | 1 + src/opengradient/client/twins.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/twins_chat.py b/examples/twins_chat.py index 26b64c1..7e7426a 100644 --- a/examples/twins_chat.py +++ b/examples/twins_chat.py @@ -1,4 +1,5 @@ ## Chat with digital twins from twin.fun via OpenGradient verifiable inference +# Browse available twins at https://twin.fun import os diff --git a/src/opengradient/client/twins.py b/src/opengradient/client/twins.py index 4d6dc0b..77e2b1f 100644 --- a/src/opengradient/client/twins.py +++ b/src/opengradient/client/twins.py @@ -14,8 +14,8 @@ class Twins: """ Digital twins chat namespace. - Provides access to digital twin conversations from twin.fun, - backed by OpenGradient verifiable inference. + Provides access to digital twin conversations backed by OpenGradient + verifiable inference. Browse available twins at https://twin.fun. Usage: client = og.init(private_key="0x...", twins_api_key="your-api-key")