traia-iatp 0.1.2__py3-none-any.whl → 0.1.67__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.
Files changed (95) hide show
  1. traia_iatp/__init__.py +105 -8
  2. traia_iatp/cli/main.py +85 -1
  3. traia_iatp/client/__init__.py +28 -3
  4. traia_iatp/client/crewai_a2a_tools.py +32 -12
  5. traia_iatp/client/d402_a2a_client.py +348 -0
  6. traia_iatp/contracts/__init__.py +11 -0
  7. traia_iatp/contracts/data/abis/contract-abis-localhost.json +4091 -0
  8. traia_iatp/contracts/data/abis/contract-abis-sepolia.json +4890 -0
  9. traia_iatp/contracts/data/addresses/contract-addresses.json +17 -0
  10. traia_iatp/contracts/data/addresses/contract-proxies.json +12 -0
  11. traia_iatp/contracts/iatp_contracts_config.py +263 -0
  12. traia_iatp/contracts/wallet_creator.py +369 -0
  13. traia_iatp/core/models.py +17 -3
  14. traia_iatp/d402/MIDDLEWARE_ARCHITECTURE.md +205 -0
  15. traia_iatp/d402/PRICE_BUILDER_USAGE.md +249 -0
  16. traia_iatp/d402/README.md +489 -0
  17. traia_iatp/d402/__init__.py +54 -0
  18. traia_iatp/d402/asgi_wrapper.py +469 -0
  19. traia_iatp/d402/chains.py +102 -0
  20. traia_iatp/d402/client.py +150 -0
  21. traia_iatp/d402/clients/__init__.py +7 -0
  22. traia_iatp/d402/clients/base.py +218 -0
  23. traia_iatp/d402/clients/httpx.py +266 -0
  24. traia_iatp/d402/common.py +114 -0
  25. traia_iatp/d402/encoding.py +28 -0
  26. traia_iatp/d402/examples/client_example.py +197 -0
  27. traia_iatp/d402/examples/server_example.py +171 -0
  28. traia_iatp/d402/facilitator.py +481 -0
  29. traia_iatp/d402/mcp_middleware.py +296 -0
  30. traia_iatp/d402/models.py +116 -0
  31. traia_iatp/d402/networks.py +98 -0
  32. traia_iatp/d402/path.py +43 -0
  33. traia_iatp/d402/payment_introspection.py +126 -0
  34. traia_iatp/d402/payment_signing.py +183 -0
  35. traia_iatp/d402/price_builder.py +164 -0
  36. traia_iatp/d402/servers/__init__.py +61 -0
  37. traia_iatp/d402/servers/base.py +139 -0
  38. traia_iatp/d402/servers/example_general_server.py +140 -0
  39. traia_iatp/d402/servers/fastapi.py +253 -0
  40. traia_iatp/d402/servers/mcp.py +304 -0
  41. traia_iatp/d402/servers/starlette.py +878 -0
  42. traia_iatp/d402/starlette_middleware.py +529 -0
  43. traia_iatp/d402/types.py +300 -0
  44. traia_iatp/mcp/D402_MCP_ADAPTER_FLOW.md +357 -0
  45. traia_iatp/mcp/__init__.py +3 -0
  46. traia_iatp/mcp/d402_mcp_tool_adapter.py +526 -0
  47. traia_iatp/mcp/mcp_agent_template.py +78 -13
  48. traia_iatp/mcp/templates/Dockerfile.j2 +27 -4
  49. traia_iatp/mcp/templates/README.md.j2 +104 -8
  50. traia_iatp/mcp/templates/cursor-rules.md.j2 +194 -0
  51. traia_iatp/mcp/templates/deployment_params.json.j2 +1 -2
  52. traia_iatp/mcp/templates/docker-compose.yml.j2 +13 -3
  53. traia_iatp/mcp/templates/env.example.j2 +60 -0
  54. traia_iatp/mcp/templates/mcp_health_check.py.j2 +2 -2
  55. traia_iatp/mcp/templates/pyproject.toml.j2 +11 -5
  56. traia_iatp/mcp/templates/pyrightconfig.json.j2 +22 -0
  57. traia_iatp/mcp/templates/run_local_docker.sh.j2 +320 -10
  58. traia_iatp/mcp/templates/server.py.j2 +174 -197
  59. traia_iatp/mcp/traia_mcp_adapter.py +182 -20
  60. traia_iatp/registry/__init__.py +47 -12
  61. traia_iatp/registry/atlas_search_indexes.json +108 -54
  62. traia_iatp/registry/iatp_search_api.py +169 -39
  63. traia_iatp/registry/mongodb_registry.py +241 -69
  64. traia_iatp/registry/readmes/EMBEDDINGS_SETUP.md +1 -1
  65. traia_iatp/registry/readmes/IATP_SEARCH_API_GUIDE.md +8 -8
  66. traia_iatp/registry/readmes/MONGODB_X509_AUTH.md +1 -1
  67. traia_iatp/registry/readmes/README.md +3 -3
  68. traia_iatp/registry/readmes/REFACTORING_SUMMARY.md +6 -6
  69. traia_iatp/scripts/__init__.py +2 -0
  70. traia_iatp/scripts/create_wallet.py +244 -0
  71. traia_iatp/server/a2a_server.py +22 -7
  72. traia_iatp/server/iatp_server_template_generator.py +23 -0
  73. traia_iatp/server/templates/.dockerignore.j2 +48 -0
  74. traia_iatp/server/templates/Dockerfile.j2 +23 -1
  75. traia_iatp/server/templates/README.md +2 -2
  76. traia_iatp/server/templates/README.md.j2 +5 -5
  77. traia_iatp/server/templates/__main__.py.j2 +374 -66
  78. traia_iatp/server/templates/agent.py.j2 +12 -11
  79. traia_iatp/server/templates/agent_config.json.j2 +3 -3
  80. traia_iatp/server/templates/agent_executor.py.j2 +45 -27
  81. traia_iatp/server/templates/env.example.j2 +32 -4
  82. traia_iatp/server/templates/gitignore.j2 +7 -0
  83. traia_iatp/server/templates/pyproject.toml.j2 +13 -12
  84. traia_iatp/server/templates/run_local_docker.sh.j2 +143 -11
  85. traia_iatp/server/templates/server.py.j2 +197 -10
  86. traia_iatp/special_agencies/registry_search_agency.py +1 -1
  87. traia_iatp/utils/iatp_utils.py +6 -6
  88. traia_iatp-0.1.67.dist-info/METADATA +320 -0
  89. traia_iatp-0.1.67.dist-info/RECORD +117 -0
  90. traia_iatp-0.1.2.dist-info/METADATA +0 -414
  91. traia_iatp-0.1.2.dist-info/RECORD +0 -72
  92. {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/WHEEL +0 -0
  93. {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/entry_points.txt +0 -0
  94. {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/licenses/LICENSE +0 -0
  95. {traia_iatp-0.1.2.dist-info → traia_iatp-0.1.67.dist-info}/top_level.txt +0 -0
traia_iatp/__init__.py CHANGED
@@ -1,13 +1,76 @@
1
- """Traia IATP - Inter Agent Transfer Protocol package."""
1
+ """Traia IATP - Inter Agent Transfer Protocol package with lazy loading for performance."""
2
2
 
3
- from .core.models import UtilityAgent, MCPServer, AgentCard
4
- from .server.iatp_server_agent_generator import IATPServerAgentGenerator
5
- from .registry.mongodb_registry import UtilityAgentRegistry, MCPServerRegistry
6
- from .registry.iatp_search_api import find_utility_agent
7
- from .client.a2a_client import UtilityAgencyTool, create_utility_agency_tools
8
- from .utils.docker_utils import LocalDockerRunner, run_generated_agent_locally, use_run_local_docker_script
3
+ from typing import TYPE_CHECKING
9
4
 
10
- __version__ = "0.1.0"
5
+ # Read version dynamically from pyproject.toml to avoid version mismatches
6
+ def _get_version():
7
+ """Read version from pyproject.toml."""
8
+ try:
9
+ import tomli
10
+ from pathlib import Path
11
+ pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
12
+ with open(pyproject_path, "rb") as f:
13
+ pyproject = tomli.load(f)
14
+ return pyproject["project"]["version"]
15
+ except Exception:
16
+ # Fallback for installed packages where pyproject.toml isn't available
17
+ return "0.1.47"
18
+
19
+ __version__ = _get_version()
20
+
21
+ # Type hints for IDEs and type checkers (not loaded at runtime)
22
+ if TYPE_CHECKING:
23
+ from .core.models import UtilityAgent, MCPServer, AgentCard
24
+ from .server.iatp_server_agent_generator import IATPServerAgentGenerator
25
+ from .registry.mongodb_registry import UtilityAgentRegistry, MCPServerRegistry
26
+ from .registry.iatp_search_api import find_utility_agent
27
+ from .client.a2a_client import UtilityAgencyTool, create_utility_agency_tools
28
+ from .utils.docker_utils import LocalDockerRunner, run_generated_agent_locally, use_run_local_docker_script
29
+ from .d402 import (
30
+ D402Config,
31
+ D402PaymentInfo,
32
+ D402ServicePrice,
33
+ PaymentScheme,
34
+ D402IATPClient,
35
+ IATPSettlementFacilitator,
36
+ require_payment,
37
+ )
38
+ from .client.d402_a2a_client import D402A2AClient, create_d402_a2a_client
39
+
40
+ # Lazy imports - these will only load when accessed
41
+ _LAZY_IMPORTS = {
42
+ # Core models (lightweight)
43
+ "UtilityAgent": ".core.models",
44
+ "MCPServer": ".core.models",
45
+ "AgentCard": ".core.models",
46
+ # Server components
47
+ "IATPServerAgentGenerator": ".server.iatp_server_agent_generator",
48
+ # Registry (lightweight, no CrewAI dependency)
49
+ "UtilityAgentRegistry": ".registry.mongodb_registry",
50
+ "MCPServerRegistry": ".registry.mongodb_registry",
51
+ "find_utility_agent": ".registry.iatp_search_api",
52
+ # Client (HEAVY - imports CrewAI)
53
+ "UtilityAgencyTool": ".client.a2a_client",
54
+ "create_utility_agency_tools": ".client.a2a_client",
55
+ # Docker utilities
56
+ "LocalDockerRunner": ".utils.docker_utils",
57
+ "run_generated_agent_locally": ".utils.docker_utils",
58
+ "use_run_local_docker_script": ".utils.docker_utils",
59
+ # D402 payment integration (HEAVY - imports CrewAI indirectly)
60
+ "D402A2AClient": ".client.d402_a2a_client",
61
+ "create_d402_a2a_client": ".client.d402_a2a_client",
62
+ }
63
+
64
+ # D402 imports need special handling as they come from a submodule
65
+ _D402_IMPORTS = [
66
+ "D402Config",
67
+ "D402PaymentInfo",
68
+ "D402ServicePrice",
69
+ "PaymentScheme",
70
+ "D402IATPClient",
71
+ "IATPSettlementFacilitator",
72
+ "require_payment",
73
+ ]
11
74
 
12
75
  __all__ = [
13
76
  # Core models
@@ -27,4 +90,38 @@ __all__ = [
27
90
  "LocalDockerRunner",
28
91
  "run_generated_agent_locally",
29
92
  "use_run_local_docker_script",
93
+ # D402 payment integration
94
+ "D402Config",
95
+ "D402PaymentInfo",
96
+ "D402ServicePrice",
97
+ "PaymentScheme",
98
+ "D402IATPClient",
99
+ "IATPSettlementFacilitator",
100
+ "require_payment",
101
+ "D402A2AClient",
102
+ "create_d402_a2a_client",
30
103
  ]
104
+
105
+
106
+ def __getattr__(name: str):
107
+ """Lazy import mechanism to load modules only when accessed."""
108
+ # Handle regular lazy imports
109
+ if name in _LAZY_IMPORTS:
110
+ from importlib import import_module
111
+ module_path = _LAZY_IMPORTS[name]
112
+ module = import_module(module_path, package=__package__)
113
+ attr = getattr(module, name)
114
+ # Cache the imported attribute
115
+ globals()[name] = attr
116
+ return attr
117
+
118
+ # Handle D402 imports
119
+ if name in _D402_IMPORTS:
120
+ from importlib import import_module
121
+ d402_module = import_module(".d402", package=__package__)
122
+ attr = getattr(d402_module, name)
123
+ # Cache the imported attribute
124
+ globals()[name] = attr
125
+ return attr
126
+
127
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
traia_iatp/cli/main.py CHANGED
@@ -16,6 +16,7 @@ from ..registry.mongodb_registry import UtilityAgentRegistry, MCPServerRegistry
16
16
  from ..utils.docker_utils import use_run_local_docker_script, LocalDockerRunner
17
17
  from ..client.a2a_client import create_utility_agency_tools
18
18
  from ..mcp.mcp_agent_template import MCPServerConfig
19
+ from ..contracts.wallet_creator import create_iatp_wallet
19
20
 
20
21
  app = typer.Typer(
21
22
  name="iatp",
@@ -24,6 +25,89 @@ app = typer.Typer(
24
25
  console = Console()
25
26
 
26
27
 
28
+ @app.command(name="create-iatp-wallet")
29
+ def create_wallet_cli(
30
+ owner_key: str = typer.Option(..., "--owner-key", help="Owner's private key (REQUIRED INPUT)"),
31
+ operator_address: Optional[str] = typer.Option(None, "--operator-address", help="Operator address (or use --create-operator)"),
32
+ create_operator: bool = typer.Option(False, "--create-operator", help="Generate new operator keypair"),
33
+ wallet_name: str = typer.Option("", "--wallet-name", help="Name for the wallet"),
34
+ wallet_type: str = typer.Option("MCP_SERVER", "--wallet-type", help="Type: CLIENT, HUMAN, MCP_SERVER, WEB_SERVER, AGENT"),
35
+ wallet_description: str = typer.Option("", "--wallet-description", help="Description of the wallet/service"),
36
+ network: str = typer.Option("sepolia", "--network", help="Network (sepolia, base-mainnet)"),
37
+ rpc_url: Optional[str] = typer.Option(None, "--rpc-url", help="Custom RPC URL"),
38
+ output: Optional[Path] = typer.Option(None, "--output", "-o", help="Save wallet info to JSON file")
39
+ ):
40
+ """Create a new IATPWallet contract.
41
+
42
+ The owner creates the wallet themselves (no maintainer key needed).
43
+
44
+ Examples:
45
+
46
+ # Create wallet and generate operator (recommended)
47
+ traia-iatp create-iatp-wallet --owner-key 0x... --create-operator --wallet-name "My Server"
48
+
49
+ # Create wallet with existing operator
50
+ traia-iatp create-iatp-wallet --owner-key 0x... --operator-address 0x... --wallet-type AGENT
51
+ """
52
+ try:
53
+ console.print("\n🔧 Creating IATPWallet...\n", style="bold")
54
+
55
+ result = create_iatp_wallet(
56
+ owner_private_key=owner_key,
57
+ operator_address=operator_address,
58
+ create_operator=create_operator,
59
+ wallet_name=wallet_name,
60
+ wallet_type=wallet_type,
61
+ wallet_description=wallet_description,
62
+ network=network,
63
+ rpc_url=rpc_url,
64
+ maintainer_private_key=None # Regular developers don't have maintainer key
65
+ )
66
+
67
+ # Display results
68
+ console.print("\n" + "="*80, style="green")
69
+ console.print("✅ IATPWallet Created Successfully!", style="bold green")
70
+ console.print("="*80 + "\n", style="green")
71
+
72
+ # Create table for results
73
+ table = Table(title="Wallet Information", show_header=False)
74
+ table.add_column("Field", style="cyan")
75
+ table.add_column("Value", style="white")
76
+
77
+ table.add_row("Wallet Address", result['wallet_address'])
78
+ table.add_row("Owner", result['owner_address'])
79
+ table.add_row("Operator", result['operator_address'])
80
+ table.add_row("Network", result['network'])
81
+ table.add_row("Transaction", result['transaction_hash'])
82
+
83
+ if 'operator_private_key' in result:
84
+ table.add_row("Operator Private Key", result['operator_private_key'])
85
+
86
+ console.print(table)
87
+
88
+ # Save to file if requested
89
+ if output:
90
+ with open(output, 'w') as f:
91
+ json.dump(result, f, indent=2)
92
+ console.print(f"\n💾 Wallet info saved to: {output}", style="green")
93
+
94
+ # Show next steps
95
+ console.print("\n📝 Next Steps:", style="bold")
96
+ console.print("1. Save your credentials securely (especially operator private key)")
97
+ console.print("2. Fund the wallet with USDC for payments")
98
+ console.print("3. Set environment variables:")
99
+ console.print(f" export IATP_WALLET_ADDRESS={result['wallet_address']}")
100
+ if 'operator_private_key' in result:
101
+ console.print(f" export OPERATOR_PRIVATE_KEY={result['operator_private_key']}")
102
+ console.print("4. Start building with IATP!\n")
103
+
104
+ except Exception as e:
105
+ console.print(f"\n❌ Error: {e}", style="bold red")
106
+ import traceback
107
+ console.print(traceback.format_exc(), style="red")
108
+ raise typer.Exit(code=1)
109
+
110
+
27
111
  @app.command()
28
112
  def create_agency(
29
113
  name: str = typer.Option(..., "--name", "-n", help="Name of the utility agency"),
@@ -438,7 +522,7 @@ def example_crew():
438
522
  # Example: Using utility agencies in a CrewAI crew
439
523
 
440
524
  from crewai import Agent, Crew, Task
441
- from iatp import create_utility_agency_tools
525
+ from traia_iatp import create_utility_agency_tools
442
526
 
443
527
  # Find and create tools from utility agencies
444
528
  tools = create_utility_agency_tools(
@@ -1,10 +1,35 @@
1
- """IATP client module for A2A integration."""
1
+ """IATP client module for A2A integration with lazy loading."""
2
2
 
3
- from .a2a_client import UtilityAgencyTool, create_utility_agency_tools
4
- from .crewai_a2a_tools import A2AToolSchema
3
+ from typing import TYPE_CHECKING
4
+
5
+ # Type hints for IDEs and type checkers (not loaded at runtime)
6
+ if TYPE_CHECKING:
7
+ from .a2a_client import UtilityAgencyTool, create_utility_agency_tools
8
+ from .crewai_a2a_tools import A2AToolSchema
9
+
10
+ # Lazy imports to avoid loading CrewAI unless needed
11
+ _LAZY_IMPORTS = {
12
+ "UtilityAgencyTool": ".a2a_client",
13
+ "create_utility_agency_tools": ".a2a_client",
14
+ "A2AToolSchema": ".crewai_a2a_tools",
15
+ }
5
16
 
6
17
  __all__ = [
7
18
  "UtilityAgencyTool",
8
19
  "create_utility_agency_tools",
9
20
  "A2AToolSchema",
10
21
  ]
22
+
23
+
24
+ def __getattr__(name: str):
25
+ """Lazy import mechanism to load modules only when accessed."""
26
+ if name in _LAZY_IMPORTS:
27
+ from importlib import import_module
28
+ module_path = _LAZY_IMPORTS[name]
29
+ module = import_module(module_path, package=__package__)
30
+ attr = getattr(module, name)
31
+ # Cache the imported attribute
32
+ globals()[name] = attr
33
+ return attr
34
+
35
+ raise AttributeError(f"module '{__name__}' has no attribute '{name}'")
@@ -8,6 +8,7 @@ from datetime import datetime
8
8
  import json
9
9
  import httpx
10
10
  import uuid
11
+ import os
11
12
  from contextlib import asynccontextmanager
12
13
  import httpcore
13
14
  from enum import Enum
@@ -32,7 +33,7 @@ _thread_local = threading.local()
32
33
 
33
34
  class A2AToolSchema(BaseModel):
34
35
  """Input schema for A2A tools."""
35
- request: str = Field(description="The request or query to send to the A2A agent")
36
+ request: str = Field(description="The request or query to send to the A2A agent. Send only 'request' key when using this tool")
36
37
 
37
38
 
38
39
  class A2AToolConfig(BaseModel):
@@ -83,8 +84,28 @@ class A2ATool(BaseTool):
83
84
  logger.info(f"Tool name: {self.name}, Endpoint: {self.config.endpoint}")
84
85
 
85
86
  try:
86
- # Create a fresh httpx client for this request
87
- async with httpx.AsyncClient(
87
+ # Check if D402 payment credentials are available from environment
88
+ # Use D402_CLIENT_OPERATOR_PRIVATE_KEY for client-side payments
89
+ payment_private_key = os.getenv("D402_CLIENT_OPERATOR_PRIVATE_KEY") or os.getenv("EVM_PRIVATE_KEY")
90
+ wallet_address = os.getenv("D402_CLIENT_WALLET_ADDRESS")
91
+
92
+ # Create httpx client with D402 payment support if credentials available
93
+ if payment_private_key:
94
+ from eth_account import Account
95
+ from ..d402.clients.httpx import d402HttpxClient
96
+
97
+ operator_key = payment_private_key if payment_private_key.startswith("0x") else f"0x{payment_private_key}"
98
+ operator_account = Account.from_key(operator_key)
99
+
100
+ logger.info(f"Using D402 payment client for A2A tool")
101
+ httpx_client = d402HttpxClient(
102
+ operator_account,
103
+ wallet_address=wallet_address,
104
+ timeout=self.config.timeout
105
+ )
106
+ else:
107
+ logger.info(f"No D402 credentials, using standard httpx client")
108
+ httpx_client = httpx.AsyncClient(
88
109
  timeout=httpx.Timeout(
89
110
  connect=5.0,
90
111
  read=self.config.timeout,
@@ -92,7 +113,9 @@ class A2ATool(BaseTool):
92
113
  pool=5.0
93
114
  ),
94
115
  http2=True
95
- ) as httpx_client:
116
+ )
117
+
118
+ async with httpx_client:
96
119
 
97
120
  # Resolve agent card
98
121
  card_resolver = A2ACardResolver(
@@ -101,20 +124,17 @@ class A2ATool(BaseTool):
101
124
  )
102
125
  agent_card = await card_resolver.get_agent_card()
103
126
  logger.info(f"Resolved agent card for: {agent_card.name}")
127
+ logger.info(f"Agent card URL: {agent_card.url if hasattr(agent_card, 'url') else 'N/A'}")
104
128
 
105
- # Patch the agent card URL to use the actual endpoint
106
- if hasattr(agent_card, 'url'):
107
- from a2a.types import AgentCard
108
- agent_card_dict = agent_card.model_dump()
109
- agent_card_dict['url'] = self.config.endpoint
110
- agent_card = AgentCard(**agent_card_dict)
129
+ # Use the URL from agent card (don't override it)
130
+ # The agent card knows the correct A2A endpoint
111
131
 
112
132
  # Create A2A client
113
- iatp_endpoint = self.config.iatp_endpoint or self.config.endpoint
133
+ iatp_endpoint = self.config.iatp_endpoint or agent_card.url
114
134
  a2a_client = A2AClient(
115
135
  httpx_client=httpx_client,
116
136
  agent_card=agent_card,
117
- url=iatp_endpoint
137
+ url=agent_card.url # Use agent card's URL (includes /a2a for utility agents)
118
138
  )
119
139
 
120
140
  # Create message