opengradient 0.5.0a1__tar.gz → 0.5.0a3__tar.gz

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.
Files changed (40) hide show
  1. {opengradient-0.5.0a1/src/opengradient.egg-info → opengradient-0.5.0a3}/PKG-INFO +2 -1
  2. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/pyproject.toml +2 -1
  3. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/__init__.py +2 -1
  4. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/client.py +210 -56
  5. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/defaults.py +2 -1
  6. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/llm/og_langchain.py +5 -3
  7. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/types.py +3 -0
  8. {opengradient-0.5.0a1 → opengradient-0.5.0a3/src/opengradient.egg-info}/PKG-INFO +2 -1
  9. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient.egg-info/requires.txt +1 -0
  10. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/LICENSE +0 -0
  11. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/README.md +0 -0
  12. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/setup.cfg +0 -0
  13. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/abi/InferencePrecompile.abi +0 -0
  14. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/abi/PriceHistoryInference.abi +0 -0
  15. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/abi/WorkflowScheduler.abi +0 -0
  16. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/abi/inference.abi +0 -0
  17. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/account.py +0 -0
  18. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/alphasense/__init__.py +0 -0
  19. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/alphasense/read_workflow_tool.py +0 -0
  20. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/alphasense/run_model_tool.py +0 -0
  21. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/alphasense/types.py +0 -0
  22. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/bin/PriceHistoryInference.bin +0 -0
  23. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/cli.py +0 -0
  24. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/exceptions.py +0 -0
  25. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/llm/__init__.py +0 -0
  26. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/llm/og_openai.py +0 -0
  27. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/proto/__init__.py +0 -0
  28. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/proto/infer.proto +0 -0
  29. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/proto/infer_pb2.py +0 -0
  30. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/proto/infer_pb2_grpc.py +0 -0
  31. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/utils.py +0 -0
  32. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/workflow_models/__init__.py +0 -0
  33. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/workflow_models/constants.py +0 -0
  34. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/workflow_models/types.py +0 -0
  35. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/workflow_models/utils.py +0 -0
  36. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient/workflow_models/workflow_models.py +0 -0
  37. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient.egg-info/SOURCES.txt +0 -0
  38. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient.egg-info/dependency_links.txt +0 -0
  39. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient.egg-info/entry_points.txt +0 -0
  40. {opengradient-0.5.0a1 → opengradient-0.5.0a3}/src/opengradient.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengradient
3
- Version: 0.5.0a1
3
+ Version: 0.5.0a3
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
@@ -23,6 +23,7 @@ Requires-Dist: requests>=2.32.3
23
23
  Requires-Dist: langchain>=0.3.7
24
24
  Requires-Dist: openai>=1.58.1
25
25
  Requires-Dist: pydantic>=2.9.2
26
+ Requires-Dist: og-test-x402==0.0.1
26
27
  Dynamic: license-file
27
28
 
28
29
  # OpenGradient Python SDK
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "opengradient"
7
- version = "0.5.0a1"
7
+ version = "0.5.0a3"
8
8
  description = "Python SDK for OpenGradient decentralized model management & inference services"
9
9
  authors = [{name = "OpenGradient", email = "kyle@vannalabs.ai"}]
10
10
  readme = "README.md"
@@ -29,6 +29,7 @@ dependencies = [
29
29
  "langchain>=0.3.7",
30
30
  "openai>=1.58.1",
31
31
  "pydantic>=2.9.2",
32
+ "og-test-x402==0.0.1",
32
33
  ]
33
34
 
34
35
  [project.scripts]
@@ -34,6 +34,7 @@ def new_client(
34
34
  rpc_url=DEFAULT_RPC_URL,
35
35
  api_url=DEFAULT_API_URL,
36
36
  contract_address=DEFAULT_INFERENCE_CONTRACT_ADDRESS,
37
+ **kwargs,
37
38
  ) -> Client:
38
39
  """
39
40
  Creates a unique OpenGradient client instance with the given authentication and network settings.
@@ -46,7 +47,7 @@ def new_client(
46
47
  contract_address: Optional inference contract address
47
48
  """
48
49
 
49
- return Client(email=email, password=password, private_key=private_key, rpc_url=rpc_url, api_url=api_url, contract_address=contract_address)
50
+ return Client(email=email, password=password, private_key=private_key, rpc_url=rpc_url, api_url=api_url, contract_address=contract_address, **kwargs)
50
51
 
51
52
 
52
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):
@@ -14,6 +14,9 @@ from web3 import Web3
14
14
  from web3.exceptions import ContractLogicError
15
15
  from web3.logs import DISCARD
16
16
  import urllib.parse
17
+ import asyncio
18
+ from x402.clients.httpx import x402HttpxClient
19
+ from x402.clients.base import decode_x_payment_response, x402Client
17
20
 
18
21
  from .exceptions import OpenGradientError
19
22
  from .proto import infer_pb2, infer_pb2_grpc
@@ -30,7 +33,12 @@ from .types import (
30
33
  ModelRepository,
31
34
  FileUploadResult,
32
35
  )
33
- from .defaults import DEFAULT_IMAGE_GEN_HOST, DEFAULT_IMAGE_GEN_PORT, DEFAULT_SCHEDULER_ADDRESS, DEFAULT_LLM_SERVER_URL
36
+ from .defaults import (
37
+ DEFAULT_IMAGE_GEN_HOST,
38
+ DEFAULT_IMAGE_GEN_PORT,
39
+ DEFAULT_SCHEDULER_ADDRESS,
40
+ DEFAULT_LLM_SERVER_URL,
41
+ DEFAULT_OPENGRADIENT_LLM_SERVER_URL)
34
42
  from .utils import convert_array_to_model_output, convert_to_model_input, convert_to_model_output
35
43
 
36
44
  _FIREBASE_CONFIG = {
@@ -73,6 +81,7 @@ class Client:
73
81
  email: Optional[str] = None,
74
82
  password: Optional[str] = None,
75
83
  llm_server_url: Optional[str] = DEFAULT_LLM_SERVER_URL,
84
+ og_llm_server_url: Optional[str] = DEFAULT_OPENGRADIENT_LLM_SERVER_URL,
76
85
  openai_api_key: Optional[str] = None,
77
86
  anthropic_api_key: Optional[str] = None,
78
87
  google_api_key: Optional[str] = None,
@@ -106,6 +115,7 @@ class Client:
106
115
  self._hub_user = None
107
116
 
108
117
  self._llm_server_url = llm_server_url
118
+ self._og_llm_server_url = og_llm_server_url
109
119
 
110
120
  self._external_api_keys = {}
111
121
  if openai_api_key or os.getenv("OPENAI_API_KEY"):
@@ -404,6 +414,15 @@ class Client:
404
414
 
405
415
  return run_with_retry(execute_transaction, max_retries)
406
416
 
417
+ def _og_payment_selector(self, accepts, network_filter=None, scheme_filter=None, max_value=None):
418
+ """Custom payment selector for OpenGradient network (og-devnet)."""
419
+ return x402Client.default_payment_requirements_selector(
420
+ accepts,
421
+ network_filter="og-devnet",
422
+ scheme_filter=scheme_filter,
423
+ max_value=max_value,
424
+ )
425
+
407
426
  def llm_completion(
408
427
  self,
409
428
  model_cid: str, # Changed from LLM to str to accept any model
@@ -488,7 +507,7 @@ class Client:
488
507
  temperature: float = 0.0,
489
508
  ) -> TextGenerationOutput:
490
509
  """
491
- Route completion request to external LLM server.
510
+ Route completion request to external LLM server with x402 payments.
492
511
 
493
512
  Args:
494
513
  model: Model identifier
@@ -503,35 +522,101 @@ class Client:
503
522
  Raises:
504
523
  OpenGradientError: If request fails
505
524
  """
506
- url = f"{self._llm_server_url}/v1/completions"
507
-
508
- headers = {"Content-Type": "application/json"}
509
525
  api_key = self._get_api_key_for_model(model)
526
+
510
527
  if api_key:
511
- headers["Authorization"] = f"Bearer {api_key}"
512
-
513
- payload = {
514
- "model": model,
515
- "prompt": prompt,
516
- "max_tokens": max_tokens,
517
- "temperature": temperature,
518
- }
519
-
520
- if stop_sequence:
521
- payload["stop"] = stop_sequence
522
-
523
- try:
524
- response = requests.post(url, json=payload, headers=headers, timeout=60)
525
- response.raise_for_status()
528
+ print("External LLM completion using API key")
529
+ url = f"{self._llm_server_url}/v1/completions"
526
530
 
527
- result = response.json()
531
+ headers = {
532
+ "Content-Type": "application/json",
533
+ "Authorization": f"Bearer {api_key}"
534
+ }
528
535
 
529
- return TextGenerationOutput(
530
- transaction_hash="external", # No blockchain transaction for external
531
- completion_output=result["completion"]
532
- )
536
+ payload = {
537
+ "model": model,
538
+ "prompt": prompt,
539
+ "max_tokens": max_tokens,
540
+ "temperature": temperature,
541
+ }
533
542
 
534
- except requests.RequestException as e:
543
+ if stop_sequence:
544
+ payload["stop"] = stop_sequence
545
+
546
+ try:
547
+ response = requests.post(url, json=payload, headers=headers, timeout=60)
548
+ response.raise_for_status()
549
+
550
+ result = response.json()
551
+
552
+ return TextGenerationOutput(
553
+ transaction_hash="external",
554
+ completion_output=result.get("completion")
555
+ )
556
+
557
+ except requests.RequestException as e:
558
+ error_msg = f"External LLM completion failed: {str(e)}"
559
+ if hasattr(e, 'response') and e.response is not None:
560
+ try:
561
+ error_detail = e.response.json()
562
+ error_msg += f" - {error_detail}"
563
+ except:
564
+ error_msg += f" - {e.response.text}"
565
+ logging.error(error_msg)
566
+ raise OpenGradientError(error_msg)
567
+
568
+ async def make_request():
569
+ async with x402HttpxClient(
570
+ account=self._wallet_account,
571
+ base_url=self._og_llm_server_url,
572
+ payment_requirements_selector=self._og_payment_selector,
573
+ ) as client:
574
+ headers = {
575
+ "Content-Type": "application/json",
576
+ # "Authorization": "Bearer special-key"
577
+ "Authorization": "Bearer 0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
578
+ }
579
+
580
+ payload = {
581
+ "model": model,
582
+ "prompt": prompt,
583
+ "max_tokens": max_tokens,
584
+ "temperature": temperature,
585
+ }
586
+
587
+ if stop_sequence:
588
+ payload["stop"] = stop_sequence
589
+
590
+ try:
591
+ response = await client.post("/v1/completions", json=payload, headers=headers, timeout=60)
592
+
593
+ # Read the response content
594
+ content = await response.aread()
595
+ result = json.loads(content.decode())
596
+ payment_hash = ""
597
+
598
+ print("Payment response headers: ", response.headers)
599
+ print("Payment response content: ", result)
600
+
601
+ if "X-Payment-Response" in response.headers:
602
+ payment_response = decode_x_payment_response(response.headers["X-Payment-Response"])
603
+ payment_hash = payment_response["transaction"]
604
+
605
+ return TextGenerationOutput(
606
+ transaction_hash="external", # No blockchain transaction for external
607
+ completion_output=result.get("completion"),
608
+ payment_hash=payment_hash
609
+ )
610
+
611
+ except Exception as e:
612
+ error_msg = f"External LLM completion request failed: {str(e)}"
613
+ logging.error(error_msg)
614
+ raise OpenGradientError(error_msg)
615
+
616
+ try:
617
+ # Run the async function in a sync context
618
+ return asyncio.run(make_request())
619
+ except Exception as e:
535
620
  error_msg = f"External LLM completion failed: {str(e)}"
536
621
  if hasattr(e, 'response') and e.response is not None:
537
622
  try:
@@ -663,7 +748,7 @@ class Client:
663
748
  tool_choice: Optional[str] = None,
664
749
  ) -> TextGenerationOutput:
665
750
  """
666
- Route chat request to external LLM server.
751
+ Route chat request to external LLM server with x402 payments.
667
752
 
668
753
  Args:
669
754
  model: Model identifier
@@ -680,40 +765,109 @@ class Client:
680
765
  Raises:
681
766
  OpenGradientError: If request fails
682
767
  """
683
- url = f"{self._llm_server_url}/v1/chat/completions"
684
-
685
- headers = {"Content-Type": "application/json"}
686
768
  api_key = self._get_api_key_for_model(model)
769
+
687
770
  if api_key:
688
- headers["Authorization"] = f"Bearer {api_key}"
689
-
690
- payload = {
691
- "model": model,
692
- "messages": messages,
693
- "max_tokens": max_tokens,
694
- "temperature": temperature,
695
- }
696
-
697
- if stop_sequence:
698
- payload["stop"] = stop_sequence
699
-
700
- if tools:
701
- payload["tools"] = tools
702
- payload["tool_choice"] = tool_choice or "auto"
703
-
704
- try:
705
- response = requests.post(url, json=payload, headers=headers, timeout=60)
706
- response.raise_for_status()
771
+ print("External LLM completion using API key")
772
+ url = f"{self._llm_server_url}/v1/chat/completions"
707
773
 
708
- result = response.json()
774
+ headers = {
775
+ "Content-Type": "application/json",
776
+ "Authorization": f"Bearer {api_key}"
777
+ }
709
778
 
710
- return TextGenerationOutput(
711
- transaction_hash="external", # No blockchain transaction for external
712
- finish_reason=result["finish_reason"],
713
- chat_output=result["message"]
714
- )
779
+ payload = {
780
+ "model": model,
781
+ "messages": messages,
782
+ "max_tokens": max_tokens,
783
+ "temperature": temperature,
784
+ }
715
785
 
716
- except requests.RequestException as e:
786
+ if stop_sequence:
787
+ payload["stop"] = stop_sequence
788
+
789
+ if tools:
790
+ payload["tools"] = tools
791
+ payload["tool_choice"] = tool_choice or "auto"
792
+
793
+ try:
794
+ response = requests.post(url, json=payload, headers=headers, timeout=60)
795
+ response.raise_for_status()
796
+
797
+ result = response.json()
798
+
799
+ return TextGenerationOutput(
800
+ transaction_hash="external",
801
+ finish_reason=result.get("finish_reason"),
802
+ chat_output=result.get("message")
803
+ )
804
+
805
+ except requests.RequestException as e:
806
+ error_msg = f"External LLM chat failed: {str(e)}"
807
+ if hasattr(e, 'response') and e.response is not None:
808
+ try:
809
+ error_detail = e.response.json()
810
+ error_msg += f" - {error_detail}"
811
+ except:
812
+ error_msg += f" - {e.response.text}"
813
+ logging.error(error_msg)
814
+ raise OpenGradientError(error_msg)
815
+
816
+ async def make_request():
817
+ async with x402HttpxClient(
818
+ account=self._wallet_account,
819
+ base_url=self._og_llm_server_url,
820
+ payment_requirements_selector=self._og_payment_selector,
821
+ ) as client:
822
+ headers = {
823
+ "Content-Type": "application/json",
824
+ "Authorization": "Bearer special-key"
825
+ }
826
+
827
+ payload = {
828
+ "model": model,
829
+ "messages": messages,
830
+ "max_tokens": max_tokens,
831
+ "temperature": temperature,
832
+ }
833
+
834
+ if stop_sequence:
835
+ payload["stop"] = stop_sequence
836
+
837
+ if tools:
838
+ payload["tools"] = tools
839
+ payload["tool_choice"] = tool_choice or "auto"
840
+
841
+ try:
842
+ response = await client.post("/v1/chat/completions", json=payload, headers=headers, timeout=60)
843
+
844
+ # Read the response content
845
+ content = await response.aread()
846
+ result = json.loads(content.decode())
847
+
848
+ payment_hash = ""
849
+ print("Payment response headers: ", response.headers)
850
+ print("Payment response content: ", result)
851
+ if "X-Payment-Response" in response.headers:
852
+ payment_response = decode_x_payment_response(response.headers["X-Payment-Response"])
853
+ payment_hash = payment_response["transaction"]
854
+
855
+ return TextGenerationOutput(
856
+ transaction_hash="external",
857
+ finish_reason=result["choices"][0].get("finish_reason"),
858
+ chat_output=result["choices"][0].get("message"),
859
+ payment_hash=payment_hash
860
+ )
861
+
862
+ except Exception as e:
863
+ error_msg = f"External LLM chat request failed: {str(e)}"
864
+ logging.error(error_msg)
865
+ raise OpenGradientError(error_msg)
866
+
867
+ try:
868
+ # Run the async function in a sync context
869
+ return asyncio.run(make_request())
870
+ except Exception as e:
717
871
  error_msg = f"External LLM chat failed: {str(e)}"
718
872
  if hasattr(e, 'response') and e.response is not None:
719
873
  try:
@@ -8,4 +8,5 @@ DEFAULT_SCHEDULER_ADDRESS = "0x7179724De4e7FF9271FA40C0337c7f90C0508eF6"
8
8
  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
- DEFAULT_LLM_SERVER_URL = "http://35.225.197.84:8000"
11
+ DEFAULT_LLM_SERVER_URL = "http://35.225.197.84:8000"
12
+ DEFAULT_OPENGRADIENT_LLM_SERVER_URL = "https://llm.opengradient.ai"
@@ -3,14 +3,16 @@ from typing import Any, Dict, List, Optional, Sequence, Union, Callable
3
3
  from typing_extensions import override
4
4
 
5
5
  from langchain.chat_models.base import BaseChatModel
6
- from langchain.schema import (
6
+ from langchain_core.messages import (
7
7
  AIMessage,
8
8
  BaseMessage,
9
- ChatGeneration,
10
- ChatResult,
11
9
  HumanMessage,
12
10
  SystemMessage,
13
11
  )
12
+ from langchain_core.outputs import (
13
+ ChatGeneration,
14
+ ChatResult,
15
+ )
14
16
  from langchain_core.callbacks.manager import CallbackManagerForLLMRun
15
17
  from langchain_core.messages import ToolCall
16
18
  from langchain_core.messages.tool import ToolMessage
@@ -151,6 +151,9 @@ class TextGenerationOutput:
151
151
  completion_output: Optional[str] = None
152
152
  """Raw text output from completion-style generation. Empty string if not applicable."""
153
153
 
154
+ payment_hash: Optional[str] = None
155
+ """Payment hash for x402 transaction"""
156
+
154
157
 
155
158
  @dataclass
156
159
  class AbiFunction:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opengradient
3
- Version: 0.5.0a1
3
+ Version: 0.5.0a3
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
@@ -23,6 +23,7 @@ Requires-Dist: requests>=2.32.3
23
23
  Requires-Dist: langchain>=0.3.7
24
24
  Requires-Dist: openai>=1.58.1
25
25
  Requires-Dist: pydantic>=2.9.2
26
+ Requires-Dist: og-test-x402==0.0.1
26
27
  Dynamic: license-file
27
28
 
28
29
  # OpenGradient Python SDK
@@ -8,3 +8,4 @@ requests>=2.32.3
8
8
  langchain>=0.3.7
9
9
  openai>=1.58.1
10
10
  pydantic>=2.9.2
11
+ og-test-x402==0.0.1
File without changes
File without changes
File without changes