opengradient 0.5.7__py3-none-any.whl → 0.5.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
opengradient/__init__.py CHANGED
@@ -20,6 +20,7 @@ from .types import (
20
20
  ModelOutput,
21
21
  ModelRepository,
22
22
  FileUploadResult,
23
+ x402SettlementMode,
23
24
  )
24
25
 
25
26
  from . import llm, alphasense
@@ -47,10 +48,25 @@ def new_client(
47
48
  contract_address: Optional inference contract address
48
49
  """
49
50
 
50
- return Client(email=email, password=password, private_key=private_key, rpc_url=rpc_url, api_url=api_url, contract_address=contract_address, **kwargs)
51
+ return Client(
52
+ email=email,
53
+ password=password,
54
+ private_key=private_key,
55
+ rpc_url=rpc_url,
56
+ api_url=api_url,
57
+ contract_address=contract_address,
58
+ **kwargs,
59
+ )
51
60
 
52
61
 
53
- def init(email: str, password: str, private_key: str, rpc_url=DEFAULT_RPC_URL, api_url=DEFAULT_API_URL, contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS):
62
+ def init(
63
+ email: str,
64
+ password: str,
65
+ private_key: str,
66
+ rpc_url=DEFAULT_RPC_URL,
67
+ api_url=DEFAULT_API_URL,
68
+ contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS,
69
+ ):
54
70
  """Initialize the OpenGradient SDK with authentication and network settings.
55
71
 
56
72
  Args:
@@ -62,8 +78,10 @@ def init(email: str, password: str, private_key: str, rpc_url=DEFAULT_RPC_URL, a
62
78
  contract_address: Optional inference contract address
63
79
  """
64
80
  global _client
65
-
66
- _client = Client(private_key=private_key, rpc_url=rpc_url, api_url=api_url, email=email, password=password, contract_address=contract_address)
81
+
82
+ _client = Client(
83
+ private_key=private_key, rpc_url=rpc_url, api_url=api_url, email=email, password=password, contract_address=contract_address
84
+ )
67
85
  return _client
68
86
 
69
87
 
@@ -162,6 +180,7 @@ def llm_completion(
162
180
  stop_sequence: Optional[List[str]] = None,
163
181
  temperature: float = 0.0,
164
182
  max_retries: Optional[int] = None,
183
+ x402_settlement_mode: Optional[x402SettlementMode] = x402SettlementMode.SETTLE_BATCH,
165
184
  ) -> TextGenerationOutput:
166
185
  """Generate text completion using an LLM.
167
186
 
@@ -173,6 +192,7 @@ def llm_completion(
173
192
  stop_sequence: Optional list of sequences where generation should stop
174
193
  temperature: Sampling temperature (0.0 = deterministic, 1.0 = creative)
175
194
  max_retries: Maximum number of retries for failed transactions
195
+ x402_settlement_mode: Settlement modes for x402 payment protocol transactions (enum x402SettlementMode)
176
196
 
177
197
  Returns:
178
198
  TextGenerationOutput: Transaction hash and generated text
@@ -190,6 +210,7 @@ def llm_completion(
190
210
  stop_sequence=stop_sequence,
191
211
  temperature=temperature,
192
212
  max_retries=max_retries,
213
+ x402_settlement_mode=x402_settlement_mode
193
214
  )
194
215
 
195
216
 
@@ -203,6 +224,7 @@ def llm_chat(
203
224
  tools: Optional[List[Dict]] = None,
204
225
  tool_choice: Optional[str] = None,
205
226
  max_retries: Optional[int] = None,
227
+ x402_settlement_mode: Optional[x402SettlementMode] = x402SettlementMode.SETTLE_BATCH,
206
228
  ) -> TextGenerationOutput:
207
229
  """Have a chat conversation with an LLM.
208
230
 
@@ -216,6 +238,7 @@ def llm_chat(
216
238
  tools: Optional list of tools the model can use
217
239
  tool_choice: Optional specific tool to use
218
240
  max_retries: Maximum number of retries for failed transactions
241
+ x402_settlement_mode: Settlement modes for x402 payment protocol transactions (enum x402SettlementMode)
219
242
 
220
243
  Returns:
221
244
  TextGenerationOutput
@@ -235,6 +258,7 @@ def llm_chat(
235
258
  tools=tools,
236
259
  tool_choice=tool_choice,
237
260
  max_retries=max_retries,
261
+ x402_settlement_mode=x402_settlement_mode
238
262
  )
239
263
 
240
264
 
opengradient/cli.py CHANGED
@@ -80,6 +80,7 @@ x402SettlementModes = {
80
80
  "settle-metadata": x402SettlementMode.SETTLE_METADATA,
81
81
  }
82
82
 
83
+
83
84
  def initialize_config(ctx):
84
85
  """Interactively initialize OpenGradient config"""
85
86
  if ctx.obj: # Check if config data already exists
@@ -140,7 +141,7 @@ def cli(ctx):
140
141
  openai_api_key = ctx.obj.get("openai_api_key")
141
142
  anthropic_api_key = ctx.obj.get("anthropic_api_key")
142
143
  google_api_key = ctx.obj.get("google_api_key")
143
-
144
+
144
145
  ctx.obj["client"] = Client(
145
146
  private_key=ctx.obj["private_key"],
146
147
  rpc_url=DEFAULT_RPC_URL,
@@ -219,9 +220,9 @@ def clear(ctx):
219
220
  def set_api_key(ctx, provider: str, key: str):
220
221
  """
221
222
  Set API key for external LLM providers.
222
-
223
+
223
224
  Example usage:
224
-
225
+
225
226
  \b
226
227
  opengradient config set-api-key --provider openai --key ..
227
228
  opengradient config set-api-key --provider anthropic --key ...
@@ -230,7 +231,7 @@ def set_api_key(ctx, provider: str, key: str):
230
231
  config_key = f"{provider}_api_key"
231
232
  ctx.obj[config_key] = key
232
233
  save_og_config(ctx)
233
-
234
+
234
235
  click.secho(f"✅ API key for {provider} has been set", fg="green")
235
236
  click.echo("You can now use models from this provider in completion and chat commands.")
236
237
 
@@ -241,9 +242,9 @@ def set_api_key(ctx, provider: str, key: str):
241
242
  def remove_api_key(ctx, provider: str):
242
243
  """
243
244
  Remove API key for an external LLM provider.
244
-
245
+
245
246
  Example usage:
246
-
247
+
247
248
  \b
248
249
  opengradient config remove-api-key --provider openai
249
250
  """
@@ -417,52 +418,68 @@ def infer(ctx, model_cid: str, inference_mode: str, input_data, input_file: Path
417
418
  help="Model identifier (local model from LLM enum or external model like 'gpt-4o', 'gemini-2.5-flash-lite', etc.)",
418
419
  )
419
420
  @click.option(
420
- "--mode",
421
- "inference_mode",
422
- type=click.Choice(LlmInferenceModes.keys()),
423
- default="VANILLA",
424
- help="Inference mode (only applies to local models, default: VANILLA)"
421
+ "--mode",
422
+ "inference_mode",
423
+ type=click.Choice(LlmInferenceModes.keys()),
424
+ default="VANILLA",
425
+ help="Inference mode (only applies to local models, default: VANILLA)",
425
426
  )
426
427
  @click.option("--prompt", "-p", required=True, help="Input prompt for the LLM completion")
427
428
  @click.option("--max-tokens", type=int, default=100, help="Maximum number of tokens for LLM completion output")
428
429
  @click.option("--stop-sequence", multiple=True, help="Stop sequences for LLM")
429
430
  @click.option("--temperature", type=float, default=0.0, help="Temperature for LLM inference (0.0 to 1.0)")
430
431
  @click.option("--local", is_flag=True, help="Force use of local model even if not in LLM enum")
431
- @click.option("--x402-settlement-mode", "x402_settlement_mode", type=click.Choice(x402SettlementModes.keys()), default="settle-batch", help="Settlement mode for x402 payload")
432
+ @click.option(
433
+ "--x402-settlement-mode",
434
+ "x402_settlement_mode",
435
+ type=click.Choice(x402SettlementModes.keys()),
436
+ default="settle-batch",
437
+ help="Settlement mode for x402 payments: settle (hashes only), settle-batch (batched, default), settle-metadata (full data)",
438
+ )
432
439
  @click.pass_context
433
- def completion(ctx, model_cid: str, inference_mode: str, x402_settlement_mode: str, prompt: str, max_tokens: int, stop_sequence: List[str], temperature: float, local: bool):
440
+ def completion(
441
+ ctx,
442
+ model_cid: str,
443
+ inference_mode: str,
444
+ x402_settlement_mode: str,
445
+ prompt: str,
446
+ max_tokens: int,
447
+ stop_sequence: List[str],
448
+ temperature: float,
449
+ local: bool,
450
+ ):
434
451
  """
435
452
  Run completion inference on an LLM model (local or external).
436
453
 
437
- This command supports both local OpenGradient models and external providers
438
- (OpenAI, Anthropic, Google, etc.). For external models, make sure to set
454
+ This command supports both local OpenGradient models and external providers
455
+ (OpenAI, Anthropic, Google, etc.). For external models, make sure to set
439
456
  the appropriate API key using 'opengradient config set-api-key'.
440
457
 
441
458
  Example usage:
442
459
 
443
460
  \b
444
- # Local model
445
- opengradient completion --model meta-llama/Meta-Llama-3-8B-Instruct --prompt "Hello, how are you?" --max-tokens 50
446
-
461
+ # TEE model
462
+ opengradient completion --model anthropic/claude-3.5-haiku --prompt "Hello, how are you?" --max-tokens 50
463
+
447
464
  # External OpenAI model
448
465
  opengradient completion --model gpt-4o --prompt "Translate to French: Hello world" --max-tokens 50
449
-
466
+
450
467
  # External Anthropic model
451
- opengradient completion --model claude-haiku-4-5-20251001--prompt "Write a haiku about coding" --max-tokens 100
452
-
468
+ opengradient completion --model claude-haiku-4-5-20251001 --prompt "Write a haiku about coding" --max-tokens 100
469
+
453
470
  # External Google model
454
471
  opengradient completion --model gemini-2.5-flash-lite --prompt "Explain quantum computing" --max-tokens 200
455
472
  """
456
473
  client: Client = ctx.obj["client"]
457
-
474
+
458
475
  try:
459
476
  is_local = local or model_cid in [llm.value for llm in LLM]
460
-
477
+
461
478
  if is_local:
462
479
  click.echo(f'Running LLM completion inference for local model "{model_cid}"\n')
463
480
  else:
464
481
  click.echo(f'Running LLM completion inference for external model "{model_cid}"\n')
465
-
482
+
466
483
  completion_output = client.llm_completion(
467
484
  model_cid=model_cid,
468
485
  inference_mode=LlmInferenceModes[inference_mode],
@@ -475,7 +492,7 @@ def completion(ctx, model_cid: str, inference_mode: str, x402_settlement_mode: s
475
492
  )
476
493
 
477
494
  print_llm_completion_result(model_cid, completion_output.transaction_hash, completion_output.completion_output, is_local)
478
-
495
+
479
496
  except Exception as e:
480
497
  click.echo(f"Error running LLM completion: {str(e)}")
481
498
 
@@ -485,7 +502,7 @@ def print_llm_completion_result(model_cid, tx_hash, llm_output, is_local=True):
485
502
  click.echo("──────────────────────────────────────")
486
503
  click.echo("Model: ", nl=False)
487
504
  click.secho(model_cid, fg="cyan", bold=True)
488
-
505
+
489
506
  if is_local and tx_hash != "external":
490
507
  click.echo("Transaction hash: ", nl=False)
491
508
  click.secho(tx_hash, fg="cyan", bold=True)
@@ -495,7 +512,7 @@ def print_llm_completion_result(model_cid, tx_hash, llm_output, is_local=True):
495
512
  else:
496
513
  click.echo("Source: ", nl=False)
497
514
  click.secho("External Provider", fg="cyan", bold=True)
498
-
515
+
499
516
  click.echo("──────────────────────────────────────")
500
517
  click.secho("LLM Output:", fg="yellow", bold=True)
501
518
  click.echo()
@@ -512,11 +529,11 @@ def print_llm_completion_result(model_cid, tx_hash, llm_output, is_local=True):
512
529
  help="Model identifier (local model from LLM enum or external model like 'gpt-4o', 'gemini-2.5-flash-lite', etc.)",
513
530
  )
514
531
  @click.option(
515
- "--mode",
516
- "inference_mode",
517
- type=click.Choice(LlmInferenceModes.keys()),
518
- default="VANILLA",
519
- help="Inference mode (only applies to local models, default: VANILLA)"
532
+ "--mode",
533
+ "inference_mode",
534
+ type=click.Choice(LlmInferenceModes.keys()),
535
+ default="VANILLA",
536
+ help="Inference mode (only applies to local models, default: VANILLA)",
520
537
  )
521
538
  @click.option("--messages", type=str, required=False, help="Input messages for the chat inference in JSON format")
522
539
  @click.option(
@@ -530,14 +547,16 @@ def print_llm_completion_result(model_cid, tx_hash, llm_output, is_local=True):
530
547
  @click.option("--temperature", type=float, default=0.0, help="Temperature for LLM inference (0.0 to 1.0)")
531
548
  @click.option("--tools", type=str, default=None, help="Tool configurations in JSON format")
532
549
  @click.option(
533
- "--tools-file",
534
- type=click.Path(exists=True, path_type=Path),
535
- required=False,
536
- help="Path to JSON file containing tool configurations"
550
+ "--tools-file", type=click.Path(exists=True, path_type=Path), required=False, help="Path to JSON file containing tool configurations"
537
551
  )
538
552
  @click.option("--tool-choice", type=str, default="", help="Specific tool choice for the LLM")
539
553
  @click.option("--local", is_flag=True, help="Force use of local model even if not in LLM enum")
540
- @click.option("--x402-settlement-mode", type=click.Choice(x402SettlementModes.keys()), default="settle-batch", help="Settlement mode for x402 payload")
554
+ @click.option(
555
+ "--x402-settlement-mode",
556
+ type=click.Choice(x402SettlementModes.keys()),
557
+ default="settle-batch",
558
+ help="Settlement mode for x402 payments: settle (hashes only), settle-batch (batched, default), settle-metadata (full data)",
559
+ )
541
560
  @click.pass_context
542
561
  def chat(
543
562
  ctx,
@@ -563,25 +582,25 @@ def chat(
563
582
  Example usage:
564
583
 
565
584
  \b
566
- # Local model
567
- opengradient chat --model meta-llama/Meta-Llama-3-8B-Instruct --messages '[{"role":"user","content":"hello"}]' --max-tokens 50
568
-
585
+ # TEE model
586
+ opengradient chat --model anthropic/claude-3.5-haiku --messages '[{"role":"user","content":"hello"}]' --max-tokens 50
587
+
569
588
  # External OpenAI model with tools
570
589
  opengradient chat --model gpt-4o --messages-file messages.json --tools-file tools.json --max-tokens 200
571
-
590
+
572
591
  # External Anthropic model
573
592
  opengradient chat --model claude-haiku-4-5-20251001 --messages '[{"role":"user","content":"Write a poem"}]' --max-tokens 100
574
593
  """
575
594
  client: Client = ctx.obj["client"]
576
-
595
+
577
596
  try:
578
597
  is_local = local or model_cid in [llm.value for llm in LLM]
579
-
598
+
580
599
  if is_local:
581
600
  click.echo(f'Running LLM chat inference for local model "{model_cid}"\n')
582
601
  else:
583
602
  click.echo(f'Running LLM chat inference for external model "{model_cid}"\n')
584
-
603
+
585
604
  # Parse messages
586
605
  if not messages and not messages_file:
587
606
  click.echo("Must specify either messages or messages-file")
@@ -651,13 +670,9 @@ def chat(
651
670
  )
652
671
 
653
672
  print_llm_chat_result(
654
- model_cid,
655
- completion_output.transaction_hash,
656
- completion_output.finish_reason,
657
- completion_output.chat_output,
658
- is_local
673
+ model_cid, completion_output.transaction_hash, completion_output.finish_reason, completion_output.chat_output, is_local
659
674
  )
660
-
675
+
661
676
  except Exception as e:
662
677
  click.echo(f"Error running LLM chat inference: {str(e)}")
663
678
 
@@ -667,7 +682,7 @@ def print_llm_chat_result(model_cid, tx_hash, finish_reason, chat_output, is_loc
667
682
  click.echo("──────────────────────────────────────")
668
683
  click.echo("Model: ", nl=False)
669
684
  click.secho(model_cid, fg="cyan", bold=True)
670
-
685
+
671
686
  if is_local and tx_hash != "external":
672
687
  click.echo("Transaction hash: ", nl=False)
673
688
  click.secho(tx_hash, fg="cyan", bold=True)
@@ -677,7 +692,7 @@ def print_llm_chat_result(model_cid, tx_hash, finish_reason, chat_output, is_loc
677
692
  else:
678
693
  click.echo("Source: ", nl=False)
679
694
  click.secho("External Provider", fg="cyan", bold=True)
680
-
695
+
681
696
  click.echo("──────────────────────────────────────")
682
697
  click.secho("Finish Reason: ", fg="yellow", bold=True)
683
698
  click.echo()
opengradient/client.py CHANGED
@@ -35,11 +35,12 @@ from .types import (
35
35
  FileUploadResult,
36
36
  )
37
37
  from .defaults import (
38
- DEFAULT_IMAGE_GEN_HOST,
39
- DEFAULT_IMAGE_GEN_PORT,
38
+ DEFAULT_IMAGE_GEN_HOST,
39
+ DEFAULT_IMAGE_GEN_PORT,
40
40
  DEFAULT_SCHEDULER_ADDRESS,
41
- DEFAULT_LLM_SERVER_URL,
42
- DEFAULT_OPENGRADIENT_LLM_SERVER_URL)
41
+ DEFAULT_LLM_SERVER_URL,
42
+ DEFAULT_OPENGRADIENT_LLM_SERVER_URL,
43
+ )
43
44
  from .utils import convert_array_to_model_output, convert_to_model_input, convert_to_model_output
44
45
 
45
46
  _FIREBASE_CONFIG = {
@@ -65,6 +66,7 @@ PRECOMPILE_CONTRACT_ADDRESS = "0x00000000000000000000000000000000000000F4"
65
66
  X402_PROCESSING_HASH_HEADER = "x-processing-hash"
66
67
  X402_PLACEHOLDER_API_KEY = "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
67
68
 
69
+
68
70
  class Client:
69
71
  _inference_hub_contract_address: str
70
72
  _blockchain: Web3
@@ -76,20 +78,21 @@ class Client:
76
78
  _precompile_abi: Dict
77
79
  _llm_server_url: str
78
80
  _external_api_keys: Dict[str, str]
81
+
79
82
  def __init__(
80
- self,
81
- private_key: str,
82
- rpc_url: str,
83
- api_url: str,
84
- contract_address: str,
85
- email: Optional[str] = None,
86
- password: Optional[str] = None,
83
+ self,
84
+ private_key: str,
85
+ rpc_url: str,
86
+ api_url: str,
87
+ contract_address: str,
88
+ email: Optional[str] = None,
89
+ password: Optional[str] = None,
87
90
  llm_server_url: Optional[str] = DEFAULT_LLM_SERVER_URL,
88
91
  og_llm_server_url: Optional[str] = DEFAULT_OPENGRADIENT_LLM_SERVER_URL,
89
92
  openai_api_key: Optional[str] = None,
90
93
  anthropic_api_key: Optional[str] = None,
91
94
  google_api_key: Optional[str] = None,
92
- ):
95
+ ):
93
96
  """
94
97
  Initialize the Client with private key, RPC URL, and contract address.
95
98
 
@@ -120,7 +123,7 @@ class Client:
120
123
 
121
124
  self._llm_server_url = llm_server_url
122
125
  self._og_llm_server_url = og_llm_server_url
123
-
126
+
124
127
  self._external_api_keys = {}
125
128
  if openai_api_key or os.getenv("OPENAI_API_KEY"):
126
129
  self._external_api_keys["openai"] = openai_api_key or os.getenv("OPENAI_API_KEY")
@@ -132,7 +135,7 @@ class Client:
132
135
  def set_api_key(self, provider: str, api_key: str):
133
136
  """
134
137
  Set or update API key for an external provider.
135
-
138
+
136
139
  Args:
137
140
  provider: Provider name (e.g., 'openai', 'anthropic', 'google')
138
141
  api_key: The API key for the provider
@@ -142,10 +145,10 @@ class Client:
142
145
  def _is_local_model(self, model_cid: str) -> bool:
143
146
  """
144
147
  Check if a model is hosted locally on OpenGradient.
145
-
148
+
146
149
  Args:
147
150
  model_cid: Model identifier
148
-
151
+
149
152
  Returns:
150
153
  True if model is local, False if it should use external provider
151
154
  """
@@ -158,7 +161,7 @@ class Client:
158
161
  def _get_provider_from_model(self, model: str) -> str:
159
162
  """Infer provider from model name."""
160
163
  model_lower = model.lower()
161
-
164
+
162
165
  if "gpt" in model_lower or model.startswith("openai/"):
163
166
  return "openai"
164
167
  elif "claude" in model_lower or model.startswith("anthropic/"):
@@ -173,10 +176,10 @@ class Client:
173
176
  def _get_api_key_for_model(self, model: str) -> Optional[str]:
174
177
  """
175
178
  Get the appropriate API key for a model.
176
-
179
+
177
180
  Args:
178
181
  model: Model identifier
179
-
182
+
180
183
  Returns:
181
184
  API key string or None
182
185
  """
@@ -451,11 +454,17 @@ class Client:
451
454
  temperature (float): Temperature for LLM inference, between 0 and 1. Default is 0.0.
452
455
  max_retries (int, optional): Maximum number of retry attempts for blockchain transactions.
453
456
  local_model (bool, optional): Force use of local model even if not in LLM enum.
457
+ x402_settlement_mode (x402SettlementMode, optional): Settlement mode for x402 payments.
458
+ - SETTLE: Records input/output hashes only (most privacy-preserving).
459
+ - SETTLE_BATCH: Aggregates multiple inferences into batch hashes (most cost-efficient).
460
+ - SETTLE_METADATA: Records full model info, complete input/output data, and all metadata.
461
+ Defaults to SETTLE_BATCH.
454
462
 
455
463
  Returns:
456
464
  TextGenerationOutput: Generated text results including:
457
465
  - Transaction hash (or "external" for external providers)
458
466
  - String of completion output
467
+ - Payment hash for x402 transactions (when using x402 settlement)
459
468
 
460
469
  Raises:
461
470
  OpenGradientError: If the inference fails.
@@ -467,14 +476,14 @@ class Client:
467
476
  return OpenGradientError("That model CID is not supported yet for TEE inference")
468
477
 
469
478
  return self._external_llm_completion(
470
- model=model_cid.split('/')[1],
479
+ model=model_cid.split("/")[1],
471
480
  prompt=prompt,
472
481
  max_tokens=max_tokens,
473
482
  stop_sequence=stop_sequence,
474
483
  temperature=temperature,
475
484
  x402_settlement_mode=x402_settlement_mode,
476
485
  )
477
-
486
+
478
487
  # Original local model logic
479
488
  def execute_transaction():
480
489
  if inference_mode != LlmInferenceMode.VANILLA:
@@ -482,10 +491,10 @@ class Client:
482
491
 
483
492
  if model_cid not in [llm.value for llm in LLM]:
484
493
  raise OpenGradientError("That model CID is not yet supported for inference")
485
-
494
+
486
495
  model_name = model_cid
487
496
  if model_cid in [llm.value for llm in TEE_LLM]:
488
- model_name = model_cid.split('/')[1]
497
+ model_name = model_cid.split("/")[1]
489
498
 
490
499
  contract = self._blockchain.eth.contract(address=self._inference_hub_contract_address, abi=self._inference_abi)
491
500
 
@@ -523,55 +532,49 @@ class Client:
523
532
  ) -> TextGenerationOutput:
524
533
  """
525
534
  Route completion request to external LLM server with x402 payments.
526
-
535
+
527
536
  Args:
528
537
  model: Model identifier
529
538
  prompt: Input prompt
530
539
  max_tokens: Maximum tokens to generate
531
540
  stop_sequence: Stop sequences
532
541
  temperature: Sampling temperature
533
-
542
+
534
543
  Returns:
535
544
  TextGenerationOutput with completion
536
-
545
+
537
546
  Raises:
538
547
  OpenGradientError: If request fails
539
548
  """
540
549
  api_key = self._get_api_key_for_model(model)
541
-
550
+
542
551
  if api_key:
543
552
  logging.debug("External LLM completions using API key")
544
553
  url = f"{self._llm_server_url}/v1/completions"
545
-
546
- headers = {
547
- "Content-Type": "application/json",
548
- "Authorization": f"Bearer {api_key}"
549
- }
550
-
554
+
555
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
556
+
551
557
  payload = {
552
558
  "model": model,
553
559
  "prompt": prompt,
554
560
  "max_tokens": max_tokens,
555
561
  "temperature": temperature,
556
562
  }
557
-
563
+
558
564
  if stop_sequence:
559
565
  payload["stop"] = stop_sequence
560
-
566
+
561
567
  try:
562
568
  response = requests.post(url, json=payload, headers=headers, timeout=60)
563
569
  response.raise_for_status()
564
-
570
+
565
571
  result = response.json()
566
-
567
- return TextGenerationOutput(
568
- transaction_hash="external",
569
- completion_output=result.get("completion")
570
- )
571
-
572
+
573
+ return TextGenerationOutput(transaction_hash="external", completion_output=result.get("completion"))
574
+
572
575
  except requests.RequestException as e:
573
576
  error_msg = f"External LLM completion failed: {str(e)}"
574
- if hasattr(e, 'response') and e.response is not None:
577
+ if hasattr(e, "response") and e.response is not None:
575
578
  try:
576
579
  error_detail = e.response.json()
577
580
  error_msg += f" - {error_detail}"
@@ -591,20 +594,20 @@ class Client:
591
594
  "Authorization": f"Bearer {X402_PLACEHOLDER_API_KEY}",
592
595
  "X-SETTLEMENT-TYPE": x402_settlement_mode,
593
596
  }
594
-
597
+
595
598
  payload = {
596
599
  "model": model,
597
600
  "prompt": prompt,
598
601
  "max_tokens": max_tokens,
599
602
  "temperature": temperature,
600
603
  }
601
-
604
+
602
605
  if stop_sequence:
603
606
  payload["stop"] = stop_sequence
604
-
607
+
605
608
  try:
606
609
  response = await client.post("/v1/completions", json=payload, headers=headers, timeout=60)
607
-
610
+
608
611
  # Read the response content
609
612
  content = await response.aread()
610
613
  result = json.loads(content.decode())
@@ -612,24 +615,22 @@ class Client:
612
615
 
613
616
  if X402_PROCESSING_HASH_HEADER in response.headers:
614
617
  payment_hash = response.headers[X402_PROCESSING_HASH_HEADER]
615
-
618
+
616
619
  return TextGenerationOutput(
617
- transaction_hash="external",
618
- completion_output=result.get("completion"),
619
- payment_hash=payment_hash
620
+ transaction_hash="external", completion_output=result.get("completion"), payment_hash=payment_hash
620
621
  )
621
-
622
+
622
623
  except Exception as e:
623
624
  error_msg = f"External LLM completion request failed: {str(e)}"
624
625
  logging.error(error_msg)
625
626
  raise OpenGradientError(error_msg)
626
-
627
+
627
628
  try:
628
629
  # Run the async function in a sync context
629
630
  return asyncio.run(make_request())
630
631
  except Exception as e:
631
632
  error_msg = f"External LLM completion failed: {str(e)}"
632
- if hasattr(e, 'response') and e.response is not None:
633
+ if hasattr(e, "response") and e.response is not None:
633
634
  try:
634
635
  error_detail = e.response.json()
635
636
  error_msg += f" - {error_detail}"
@@ -666,9 +667,18 @@ class Client:
666
667
  tool_choice (str, optional): Sets a specific tool to choose.
667
668
  max_retries (int, optional): Maximum number of retry attempts.
668
669
  local_model (bool, optional): Force use of local model.
670
+ x402_settlement_mode (x402SettlementMode, optional): Settlement mode for x402 payments.
671
+ - SETTLE: Records input/output hashes only (most privacy-preserving).
672
+ - SETTLE_BATCH: Aggregates multiple inferences into batch hashes (most cost-efficient).
673
+ - SETTLE_METADATA: Records full model info, complete input/output data, and all metadata.
674
+ Defaults to SETTLE_BATCH.
669
675
 
670
676
  Returns:
671
- TextGenerationOutput: Generated text results.
677
+ TextGenerationOutput: Generated text results including:
678
+ - chat_output: Dict with role, content, and tool_calls
679
+ - transaction_hash: Blockchain hash (or "external" for external providers)
680
+ - finish_reason: Reason for completion (e.g., "stop", "tool_call")
681
+ - payment_hash: Payment hash for x402 transactions (when using x402 settlement)
672
682
 
673
683
  Raises:
674
684
  OpenGradientError: If the inference fails.
@@ -680,7 +690,7 @@ class Client:
680
690
  return OpenGradientError("That model CID is not supported yet for TEE inference")
681
691
 
682
692
  return self._external_llm_chat(
683
- model=model_cid.split('/')[1],
693
+ model=model_cid.split("/")[1],
684
694
  messages=messages,
685
695
  max_tokens=max_tokens,
686
696
  stop_sequence=stop_sequence,
@@ -689,18 +699,18 @@ class Client:
689
699
  tool_choice=tool_choice,
690
700
  x402_settlement_mode=x402_settlement_mode,
691
701
  )
692
-
702
+
693
703
  # Original local model logic
694
704
  def execute_transaction():
695
705
  if inference_mode != LlmInferenceMode.VANILLA:
696
706
  raise OpenGradientError("Invalid inference mode %s: Inference mode must be VANILLA or TEE" % inference_mode)
697
-
707
+
698
708
  if model_cid not in [llm.value for llm in LLM]:
699
709
  raise OpenGradientError("That model CID is not yet supported for inference")
700
-
710
+
701
711
  model_name = model_cid
702
712
  if model_cid in [llm.value for llm in TEE_LLM]:
703
- model_name = model_cid.split('/')[1]
713
+ model_name = model_cid.split("/")[1]
704
714
 
705
715
  contract = self._blockchain.eth.contract(address=self._inference_hub_contract_address, abi=self._inference_abi)
706
716
 
@@ -771,7 +781,7 @@ class Client:
771
781
  ) -> TextGenerationOutput:
772
782
  """
773
783
  Route chat request to external LLM server with x402 payments.
774
-
784
+
775
785
  Args:
776
786
  model: Model identifier
777
787
  messages: List of chat messages
@@ -780,53 +790,48 @@ class Client:
780
790
  temperature: Sampling temperature
781
791
  tools: Function calling tools
782
792
  tool_choice: Tool selection strategy
783
-
793
+
784
794
  Returns:
785
795
  TextGenerationOutput with chat completion
786
-
796
+
787
797
  Raises:
788
798
  OpenGradientError: If request fails
789
799
  """
790
800
  api_key = self._get_api_key_for_model(model)
791
-
801
+
792
802
  if api_key:
793
803
  logging.debug("External LLM completion using API key")
794
804
  url = f"{self._llm_server_url}/v1/chat/completions"
795
-
796
- headers = {
797
- "Content-Type": "application/json",
798
- "Authorization": f"Bearer {api_key}"
799
- }
800
-
805
+
806
+ headers = {"Content-Type": "application/json", "Authorization": f"Bearer {api_key}"}
807
+
801
808
  payload = {
802
809
  "model": model,
803
810
  "messages": messages,
804
811
  "max_tokens": max_tokens,
805
812
  "temperature": temperature,
806
813
  }
807
-
814
+
808
815
  if stop_sequence:
809
816
  payload["stop"] = stop_sequence
810
-
817
+
811
818
  if tools:
812
819
  payload["tools"] = tools
813
820
  payload["tool_choice"] = tool_choice or "auto"
814
-
821
+
815
822
  try:
816
823
  response = requests.post(url, json=payload, headers=headers, timeout=60)
817
824
  response.raise_for_status()
818
-
825
+
819
826
  result = response.json()
820
-
827
+
821
828
  return TextGenerationOutput(
822
- transaction_hash="external",
823
- finish_reason=result.get("finish_reason"),
824
- chat_output=result.get("message")
829
+ transaction_hash="external", finish_reason=result.get("finish_reason"), chat_output=result.get("message")
825
830
  )
826
-
831
+
827
832
  except requests.RequestException as e:
828
833
  error_msg = f"External LLM chat failed: {str(e)}"
829
- if hasattr(e, 'response') and e.response is not None:
834
+ if hasattr(e, "response") and e.response is not None:
830
835
  try:
831
836
  error_detail = e.response.json()
832
837
  error_msg += f" - {error_detail}"
@@ -844,26 +849,26 @@ class Client:
844
849
  headers = {
845
850
  "Content-Type": "application/json",
846
851
  "Authorization": f"Bearer {X402_PLACEHOLDER_API_KEY}",
847
- "X-SETTLEMENT-TYPE": x402_settlement_mode
852
+ "X-SETTLEMENT-TYPE": x402_settlement_mode,
848
853
  }
849
-
854
+
850
855
  payload = {
851
856
  "model": model,
852
857
  "messages": messages,
853
858
  "max_tokens": max_tokens,
854
859
  "temperature": temperature,
855
860
  }
856
-
861
+
857
862
  if stop_sequence:
858
863
  payload["stop"] = stop_sequence
859
-
864
+
860
865
  if tools:
861
866
  payload["tools"] = tools
862
867
  payload["tool_choice"] = tool_choice or "auto"
863
-
868
+
864
869
  try:
865
870
  response = await client.post("/v1/chat/completions", json=payload, headers=headers, timeout=60)
866
-
871
+
867
872
  # Read the response content
868
873
  content = await response.aread()
869
874
  result = json.loads(content.decode())
@@ -873,29 +878,29 @@ class Client:
873
878
  payment_hash = ""
874
879
  if X402_PROCESSING_HASH_HEADER in response.headers:
875
880
  payment_hash = response.headers[X402_PROCESSING_HASH_HEADER]
876
-
881
+
877
882
  choices = result.get("choices")
878
883
  if not choices:
879
884
  raise OpenGradientError(f"Invalid response: 'choices' missing or empty in {result}")
880
-
885
+
881
886
  return TextGenerationOutput(
882
887
  transaction_hash="external",
883
888
  finish_reason=choices[0].get("finish_reason"),
884
889
  chat_output=choices[0].get("message"),
885
- payment_hash=payment_hash
890
+ payment_hash=payment_hash,
886
891
  )
887
-
892
+
888
893
  except Exception as e:
889
894
  error_msg = f"External LLM chat request failed: {str(e)}"
890
895
  logging.error(error_msg)
891
896
  raise OpenGradientError(error_msg)
892
-
897
+
893
898
  try:
894
899
  # Run the async function in a sync context
895
900
  return asyncio.run(make_request())
896
901
  except Exception as e:
897
902
  error_msg = f"External LLM chat failed: {str(e)}"
898
- if hasattr(e, 'response') and e.response is not None:
903
+ if hasattr(e, "response") and e.response is not None:
899
904
  try:
900
905
  error_detail = e.response.json()
901
906
  error_msg += f" - {error_detail}"
@@ -1104,12 +1109,12 @@ class Client:
1104
1109
  except ContractLogicError as e:
1105
1110
  try:
1106
1111
  run_function.call({"from": self._wallet_account.address})
1107
-
1112
+
1108
1113
  except ContractLogicError as call_err:
1109
1114
  raise ContractLogicError(f"simulation failed with revert reason: {call_err.args[0]}")
1110
-
1115
+
1111
1116
  raise ContractLogicError(f"simulation failed with no revert reason. Reason: {e}")
1112
-
1117
+
1113
1118
  gas_limit = int(estimated_gas * 3)
1114
1119
 
1115
1120
  transaction = run_function.build_transaction(
@@ -1128,10 +1133,10 @@ class Client:
1128
1133
  if tx_receipt["status"] == 0:
1129
1134
  try:
1130
1135
  run_function.call({"from": self._wallet_account.address})
1131
-
1136
+
1132
1137
  except ContractLogicError as call_err:
1133
1138
  raise ContractLogicError(f"Transaction failed with revert reason: {call_err.args[0]}")
1134
-
1139
+
1135
1140
  raise ContractLogicError(f"Transaction failed with no revert reason. Receipt: {tx_receipt}")
1136
1141
 
1137
1142
  return tx_hash, tx_receipt
@@ -1346,45 +1351,42 @@ class Client:
1346
1351
  results = contract.functions.getLastInferenceResults(num_results).call()
1347
1352
  return [convert_array_to_model_output(result) for result in results]
1348
1353
 
1349
-
1350
1354
  def _get_inference_result_from_node(self, inference_id: str, inference_mode: InferenceMode) -> Dict:
1351
1355
  """
1352
1356
  Get the inference result from node.
1353
-
1357
+
1354
1358
  Args:
1355
1359
  inference_id (str): Inference id for a inference request
1356
-
1360
+
1357
1361
  Returns:
1358
1362
  Dict: The inference result as returned by the node
1359
-
1363
+
1360
1364
  Raises:
1361
1365
  OpenGradientError: If the request fails or returns an error
1362
1366
  """
1363
1367
  try:
1364
- encoded_id = urllib.parse.quote(inference_id, safe='')
1368
+ encoded_id = urllib.parse.quote(inference_id, safe="")
1365
1369
  url = f"{self._api_url}/artela-network/artela-rollkit/inference/tx/{encoded_id}"
1366
-
1370
+
1367
1371
  response = requests.get(url)
1368
1372
  if response.status_code == 200:
1369
1373
  resp = response.json()
1370
1374
  inference_result = resp.get("inference_results", {})
1371
1375
  if inference_result:
1372
1376
  decoded_bytes = base64.b64decode(inference_result[0])
1373
- decoded_string = decoded_bytes.decode('utf-8')
1374
- output = json.loads(decoded_string).get("InferenceResult",{})
1377
+ decoded_string = decoded_bytes.decode("utf-8")
1378
+ output = json.loads(decoded_string).get("InferenceResult", {})
1375
1379
  if output is None:
1376
1380
  raise OpenGradientError("Missing InferenceResult in inference output")
1377
-
1381
+
1378
1382
  match inference_mode:
1379
1383
  case InferenceMode.VANILLA:
1380
1384
  if "VanillaResult" not in output:
1381
1385
  raise OpenGradientError("Missing VanillaResult in inference output")
1382
1386
  if "model_output" not in output["VanillaResult"]:
1383
1387
  raise OpenGradientError("Missing model_output in VanillaResult")
1384
- return {
1385
- "output": output["VanillaResult"]["model_output"]
1386
- }
1387
-
1388
+ return {"output": output["VanillaResult"]["model_output"]}
1389
+
1388
1390
  case InferenceMode.TEE:
1389
1391
  if "TeeNodeResult" not in output:
1390
1392
  raise OpenGradientError("Missing TeeNodeResult in inference output")
@@ -1393,34 +1395,30 @@ class Client:
1393
1395
  if "VanillaResponse" in output["TeeNodeResult"]["Response"]:
1394
1396
  if "model_output" not in output["TeeNodeResult"]["Response"]["VanillaResponse"]:
1395
1397
  raise OpenGradientError("Missing model_output in VanillaResponse")
1396
- return {
1397
- "output": output["TeeNodeResult"]["Response"]["VanillaResponse"]["model_output"]
1398
- }
1399
-
1398
+ return {"output": output["TeeNodeResult"]["Response"]["VanillaResponse"]["model_output"]}
1399
+
1400
1400
  else:
1401
1401
  raise OpenGradientError("Missing VanillaResponse in TeeNodeResult Response")
1402
-
1402
+
1403
1403
  case InferenceMode.ZKML:
1404
1404
  if "ZkmlResult" not in output:
1405
1405
  raise OpenGradientError("Missing ZkmlResult in inference output")
1406
1406
  if "model_output" not in output["ZkmlResult"]:
1407
1407
  raise OpenGradientError("Missing model_output in ZkmlResult")
1408
- return {
1409
- "output": output["ZkmlResult"]["model_output"]
1410
- }
1411
-
1408
+ return {"output": output["ZkmlResult"]["model_output"]}
1409
+
1412
1410
  case _:
1413
1411
  raise OpenGradientError(f"Invalid inference mode: {inference_mode}")
1414
1412
  else:
1415
1413
  return None
1416
-
1414
+
1417
1415
  else:
1418
1416
  error_message = f"Failed to get inference result: HTTP {response.status_code}"
1419
1417
  if response.text:
1420
1418
  error_message += f" - {response.text}"
1421
1419
  logging.error(error_message)
1422
1420
  raise OpenGradientError(error_message)
1423
-
1421
+
1424
1422
  except requests.RequestException as e:
1425
1423
  logging.error(f"Request exception when getting inference result: {str(e)}")
1426
1424
  raise OpenGradientError(f"Failed to get inference result: {str(e)}")
@@ -1428,6 +1426,7 @@ class Client:
1428
1426
  logging.error(f"Unexpected error when getting inference result: {str(e)}", exc_info=True)
1429
1427
  raise OpenGradientError(f"Failed to get inference result: {str(e)}")
1430
1428
 
1429
+
1431
1430
  def run_with_retry(txn_function: Callable, max_retries=DEFAULT_MAX_RETRY, retry_delay=DEFAULT_RETRY_DELAY_SEC):
1432
1431
  """
1433
1432
  Execute a blockchain transaction with retry logic.
opengradient/defaults.py CHANGED
@@ -9,4 +9,4 @@ DEFAULT_BLOCKCHAIN_EXPLORER = "https://explorer.opengradient.ai/tx/"
9
9
  DEFAULT_IMAGE_GEN_HOST = "18.217.25.69"
10
10
  DEFAULT_IMAGE_GEN_PORT = 5125
11
11
  DEFAULT_LLM_SERVER_URL = "http://35.225.197.84:8000"
12
- DEFAULT_OPENGRADIENT_LLM_SERVER_URL = "https://llm.opengradient.ai"
12
+ DEFAULT_OPENGRADIENT_LLM_SERVER_URL = "https://llm.opengradient.ai"
@@ -36,7 +36,12 @@ class OpenGradientChatModel(BaseChatModel):
36
36
  super().__init__()
37
37
 
38
38
  self._client = Client(
39
- private_key=private_key, rpc_url=DEFAULT_RPC_URL, api_url=DEFAULT_API_URL, contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS, email=None, password=None
39
+ private_key=private_key,
40
+ rpc_url=DEFAULT_RPC_URL,
41
+ api_url=DEFAULT_API_URL,
42
+ contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS,
43
+ email=None,
44
+ password=None,
40
45
  )
41
46
  self._model_cid = model_cid
42
47
  self._max_tokens = max_tokens
opengradient/types.py CHANGED
@@ -6,10 +6,37 @@ import numpy as np
6
6
 
7
7
 
8
8
  class x402SettlementMode(StrEnum):
9
+ """
10
+ Settlement modes for x402 payment protocol transactions.
11
+
12
+ These modes control how inference data is recorded on-chain for payment settlement
13
+ and auditability. Each mode offers different trade-offs between data completeness,
14
+ privacy, and transaction costs.
15
+
16
+ Attributes:
17
+ SETTLE: Individual settlement with input/output hashes only.
18
+ Records cryptographic hashes of the inference input and output.
19
+ Most privacy-preserving option - actual data is not stored on-chain.
20
+ Suitable for applications where only proof of execution is needed.
21
+
22
+ SETTLE_METADATA: Individual settlement with full metadata.
23
+ Records complete model information, full input and output data,
24
+ and all inference metadata on-chain.
25
+ Provides maximum transparency and auditability.
26
+ Higher gas costs due to larger data storage.
27
+
28
+ SETTLE_BATCH: Batch settlement for multiple inferences.
29
+ Aggregates multiple inference requests into a single settlement transaction
30
+ using batch hashes.
31
+ Most cost-efficient for high-volume applications.
32
+ Reduced per-inference transaction overhead.
33
+ """
34
+
9
35
  SETTLE = "settle"
10
36
  SETTLE_METADATA = "settle-metadata"
11
37
  SETTLE_BATCH = "settle-batch"
12
38
 
39
+
13
40
  class CandleOrder(IntEnum):
14
41
  ASCENDING = 0
15
42
  DESCENDING = 1
@@ -107,7 +134,7 @@ class InferenceMode(Enum):
107
134
 
108
135
 
109
136
  class LlmInferenceMode(Enum):
110
- """Enum for differetn inference modes available for LLM inferences (VANILLA, TEE)"""
137
+ """Enum for different inference modes available for LLM inference (VANILLA, TEE)"""
111
138
 
112
139
  VANILLA = 0
113
140
  TEE = 1
@@ -205,23 +232,23 @@ class LLM(str, Enum):
205
232
  # META_LLAMA_3_1_70B_INSTRUCT = "meta-llama/Llama-3.1-70B-Instruct"
206
233
  # DOBBY_UNHINGED_3_1_8B = "SentientAGI/Dobby-Mini-Unhinged-Llama-3.1-8B"
207
234
  # DOBBY_LEASHED_3_1_8B = "SentientAGI/Dobby-Mini-Leashed-Llama-3.1-8B"
208
-
235
+
209
236
  # OpenAI models via TEE
210
237
  GPT_4_1_2025_04_14 = "openai/gpt-4.1-2025-04-14"
211
238
  GPT_4O = "openai/gpt-4o"
212
239
  O4_MINI = "openai/o4-mini"
213
-
240
+
214
241
  # Anthropic models via TEE
215
242
  CLAUDE_3_7_SONNET = "anthropic/claude-3.7-sonnet"
216
243
  CLAUDE_3_5_HAIKU = "anthropic/claude-3.5-haiku"
217
244
  CLAUDE_4_0_SONNET = "anthropic/claude-4.0-sonnet"
218
-
245
+
219
246
  # Google models via TEE
220
247
  GEMINI_2_5_FLASH = "google/gemini-2.5-flash"
221
248
  GEMINI_2_5_PRO = "google/gemini-2.5-pro"
222
249
  GEMINI_2_0_FLASH = "google/gemini-2.0-flash"
223
250
  GEMINI_2_5_FLASH_LITE = "google/gemini-2.5-flash-lite"
224
-
251
+
225
252
  # xAI Grok models via TEE
226
253
  GROK_3_MINI_BETA = "x-ai/grok-3-mini-beta"
227
254
  GROK_3_BETA = "x-ai/grok-3-beta"
@@ -230,28 +257,29 @@ class LLM(str, Enum):
230
257
  GROK_4_1_FAST = "x-ai/grok-4.1-fast"
231
258
  GROK_4_1_FAST_NON_REASONING = "x-ai/grok-4-1-fast-non-reasoning"
232
259
 
260
+
233
261
  class TEE_LLM(str, Enum):
234
262
  """Enum for LLM models available for TEE execution"""
235
-
263
+
236
264
  # Existing (Currently turned off)
237
265
  # META_LLAMA_3_1_70B_INSTRUCT = "meta-llama/Llama-3.1-70B-Instruct"
238
-
266
+
239
267
  # OpenAI models via TEE
240
268
  GPT_4_1_2025_04_14 = "openai/gpt-4.1-2025-04-14"
241
269
  GPT_4O = "openai/gpt-4o"
242
270
  O4_MINI = "openai/o4-mini"
243
-
271
+
244
272
  # Anthropic models via TEE
245
273
  CLAUDE_3_7_SONNET = "anthropic/claude-3.7-sonnet"
246
274
  CLAUDE_3_5_HAIKU = "anthropic/claude-3.5-haiku"
247
275
  CLAUDE_4_0_SONNET = "anthropic/claude-4.0-sonnet"
248
-
276
+
249
277
  # Google models via TEE
250
278
  GEMINI_2_5_FLASH = "google/gemini-2.5-flash"
251
279
  GEMINI_2_5_PRO = "google/gemini-2.5-pro"
252
280
  GEMINI_2_0_FLASH = "google/gemini-2.0-flash"
253
281
  GEMINI_2_5_FLASH_LITE = "google/gemini-2.5-flash-lite"
254
-
282
+
255
283
  # xAI Grok models via TEE
256
284
  GROK_3_MINI_BETA = "x-ai/grok-3-mini-beta"
257
285
  GROK_3_BETA = "x-ai/grok-3-beta"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengradient
3
- Version: 0.5.7
3
+ Version: 0.5.8
4
4
  Summary: Python SDK for OpenGradient decentralized model management & inference services
5
5
  Author-email: OpenGradient <kyle@vannalabs.ai>
6
6
  License-Expression: MIT
@@ -24,7 +24,6 @@ Requires-Dist: langchain>=0.3.7
24
24
  Requires-Dist: openai>=1.58.1
25
25
  Requires-Dist: pydantic>=2.9.2
26
26
  Requires-Dist: og-test-x402==0.0.1
27
- Requires-Dist: x402==0.2.1
28
27
  Dynamic: license-file
29
28
 
30
29
  # OpenGradient Python SDK
@@ -133,6 +132,10 @@ For comprehensive documentation, API reference, and examples, visit:
133
132
  - [OpenGradient Documentation](https://docs.opengradient.ai/)
134
133
  - [API Reference](https://docs.opengradient.ai/api_reference/python_sdk/)
135
134
 
135
+ ### Claude Code Users
136
+
137
+ If you use [Claude Code](https://claude.ai/code), copy [docs/CLAUDE_SDK_USERS.md](docs/CLAUDE_SDK_USERS.md) to your project's `CLAUDE.md` to help Claude assist you with OpenGradient SDK development.
138
+
136
139
  ## Support
137
140
 
138
141
  - Run `opengradient --help` for CLI command reference
@@ -1,10 +1,10 @@
1
- opengradient/__init__.py,sha256=wVg0KTFNBl7RnZF9huR5-m_q1E7tO-YyQwY7AD9JFoc,12635
1
+ opengradient/__init__.py,sha256=7UkGoQRDtSb0lh3vobxmyJct_uFfm1Re_oz5s0s9dOs,13263
2
2
  opengradient/account.py,sha256=5wrYpws_1lozjOFjLCTHtxgoxK-LmObDAaVy9eDcJY4,1145
3
- opengradient/cli.py,sha256=RksBEGVcZgUg6ng53Fgz-Ncv1erBwdADgblB2HmKkwk,29868
4
- opengradient/client.py,sha256=lzuC4rEwyf1EgHw49PMXjIyjyTsBIAP2XmCNp0cCNzg,63113
5
- opengradient/defaults.py,sha256=w8-dr5ciF2TGnqbm_ib0Yz4U0YL5ikpNqkcPVpmXzP8,673
3
+ opengradient/cli.py,sha256=4IUKxecZV9la-_nEVxObOIjm6qQ9aEHhq5-m5clzzHc,29901
4
+ opengradient/client.py,sha256=nozp80z8KSYQewKQmSVXZQIdVtsSjv53reS3TBRwlXc,63071
5
+ opengradient/defaults.py,sha256=yiZnpIOLyHEmZhCEQXgWpT2eJin10UVsivJY6r61xmo,674
6
6
  opengradient/exceptions.py,sha256=88tfegboGtlehQcwhxsl6ZzhLJWZWlkf_bkHTiCtXpo,3391
7
- opengradient/types.py,sha256=L60W1O3xmlYxbJ9ouN6nKNKJSdTW3yzCDsU0lozWF8U,7837
7
+ opengradient/types.py,sha256=DSkJAcD4fRQ78bG3Ny5-_OqcfptFSIpliS4qKKYE2jU,9026
8
8
  opengradient/utils.py,sha256=ZUq4OBIml2vsC0tRqus4Zwb_e3g4woo00apByrafuVw,8058
9
9
  opengradient/abi/InferencePrecompile.abi,sha256=reepTHg6Q01UrFP0Gexc-JayplsvOLPfG7jrEZ-cV28,10197
10
10
  opengradient/abi/PriceHistoryInference.abi,sha256=ZB3fZdx1kaFlp2wt1vTbTZZG1k8HPvmNtkG5Q8Bnajw,5098
@@ -16,7 +16,7 @@ opengradient/alphasense/run_model_tool.py,sha256=wlDqXVHa1xpqQy_hmht_wWegxtqdYgY
16
16
  opengradient/alphasense/types.py,sha256=uxk4JQKbaS2cM3ZiKpdHQb234OJ5ylprNR5vi01QFzA,220
17
17
  opengradient/bin/PriceHistoryInference.bin,sha256=nU2FZpGHIKBZ7NSK9Sr-p9lr-nXja_40ISPN9yckDq8,41276
18
18
  opengradient/llm/__init__.py,sha256=eYFBrOf1GZr0VGbIw-gSFr8hM3Rbw74ye8l-pnBPNuA,1104
19
- opengradient/llm/og_langchain.py,sha256=inJmu28aWA1RAWJx8G0h8w4FGXSKMCzJVOBGUwiKqnI,4904
19
+ opengradient/llm/og_langchain.py,sha256=fVHEq_hJbWrLLVZXKSH5wwSG5kQEt_PGnmAOLUnEgmw,4965
20
20
  opengradient/llm/og_openai.py,sha256=26W_NDnLaICIaWbi9aou40v5ZJXLlmLdztDrdFoDGAU,3789
21
21
  opengradient/proto/__init__.py,sha256=AhaSmrqV0TXGzCKaoPV8-XUvqs2fGAJBM2aOmDpkNbE,55
22
22
  opengradient/proto/infer.proto,sha256=13eaEMcppxkBF8yChptsX9HooWFwJKze7oLZNl-LEb8,1217
@@ -27,9 +27,9 @@ opengradient/workflow_models/constants.py,sha256=viIkb_LGcfVprqQNaA80gBTj6cfYam0
27
27
  opengradient/workflow_models/types.py,sha256=Z22hF6c8Y4D2GlzVEIBODGwsqSjSrQvUcpZ7R-mIJdI,409
28
28
  opengradient/workflow_models/utils.py,sha256=ySfpuiOBqLTlfto6ZxZf2vc7K6RGIja0l4eaVm5AOzY,1503
29
29
  opengradient/workflow_models/workflow_models.py,sha256=d4C_gs39DAfy4cdY9Ee6GMXpPfzwvKFpmxzK1A7LNgU,3900
30
- opengradient-0.5.7.dist-info/licenses/LICENSE,sha256=xEcvQ3AxZOtDkrqkys2Mm6Y9diEnaSeQRKvxi-JGnNA,1069
31
- opengradient-0.5.7.dist-info/METADATA,sha256=WmJWW2IPbsKD_fuhafHf_cZeLiCz9_2T8qZUcvw0saU,4019
32
- opengradient-0.5.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
- opengradient-0.5.7.dist-info/entry_points.txt,sha256=yUKTaJx8RXnybkob0J62wVBiCp_1agVbgw9uzsmaeJc,54
34
- opengradient-0.5.7.dist-info/top_level.txt,sha256=oC1zimVLa2Yi1LQz8c7x-0IQm92milb5ax8gHBHwDqU,13
35
- opengradient-0.5.7.dist-info/RECORD,,
30
+ opengradient-0.5.8.dist-info/licenses/LICENSE,sha256=xEcvQ3AxZOtDkrqkys2Mm6Y9diEnaSeQRKvxi-JGnNA,1069
31
+ opengradient-0.5.8.dist-info/METADATA,sha256=DyqayJvXV39OUn5H9jUqVsKqX9ilHMAaQ2-u4GnqIwM,4215
32
+ opengradient-0.5.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
33
+ opengradient-0.5.8.dist-info/entry_points.txt,sha256=yUKTaJx8RXnybkob0J62wVBiCp_1agVbgw9uzsmaeJc,54
34
+ opengradient-0.5.8.dist-info/top_level.txt,sha256=oC1zimVLa2Yi1LQz8c7x-0IQm92milb5ax8gHBHwDqU,13
35
+ opengradient-0.5.8.dist-info/RECORD,,