crewai-true402 0.1.0__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.
@@ -0,0 +1,5 @@
1
+ dist/
2
+ build/
3
+ *.egg-info/
4
+ __pycache__/
5
+ *.pyc
@@ -0,0 +1,7 @@
1
+ MIT No Attribution
2
+
3
+ Copyright 2026 true402
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,88 @@
1
+ Metadata-Version: 2.4
2
+ Name: crewai-true402
3
+ Version: 0.1.0
4
+ Summary: true402 tools for CrewAI — pay-per-call on-chain rug/honeypot & address safety for Base AI agents over x402 (USDC, no account, no API key).
5
+ Project-URL: Homepage, https://true402.dev
6
+ Project-URL: Source, https://github.com/true402/crewai-true402
7
+ Project-URL: OpenAPI, https://true402.dev/openapi.json
8
+ Author-email: true402 <contact@true402.dev>
9
+ License: MIT
10
+ License-File: LICENSE
11
+ Keywords: agent-tools,ai-agent,base,crewai,crewai-tools,crypto,defi,honeypot,rug-check,token-safety,web3,x402
12
+ Requires-Python: >=3.10
13
+ Requires-Dist: eth-account>=0.11
14
+ Requires-Dist: pydantic>=2.0
15
+ Requires-Dist: requests>=2.28
16
+ Provides-Extra: crewai
17
+ Requires-Dist: crewai>=0.30; extra == 'crewai'
18
+ Description-Content-Type: text/markdown
19
+
20
+ # crewai-true402
21
+
22
+ **[true402](https://true402.dev) tools for [CrewAI](https://www.crewai.com)** — give a Base trading agent a pre-trade **rug/honeypot check** it pays for per call over [x402](https://x402.org) (USDC on Base). No accounts, no API keys — the wallet is the identity. The safety checks have a **free daily trial**, so the tools work out of the box with no wallet configured.
23
+
24
+ ## Install
25
+
26
+ ```bash
27
+ pip install crewai-true402
28
+ ```
29
+
30
+ ## Use
31
+
32
+ ```python
33
+ from crewai import Agent
34
+ from crewai_true402 import true402_tools
35
+
36
+ # Reads PAYER_PRIVATE_KEY from the env (a Base wallet holding a little USDC).
37
+ # Omit the key to rely on the free daily trial for the safety stalls.
38
+ tools = true402_tools()
39
+
40
+ trader = Agent(
41
+ role="Base memecoin trader",
42
+ goal="Only buy tokens that pass an on-chain safety check",
43
+ tools=tools,
44
+ backstory="You never ape into a token before rug-checking it.",
45
+ )
46
+ ```
47
+
48
+ The agent gets four tools:
49
+
50
+ | Tool | What | Price |
51
+ |------|------|-------|
52
+ | `true402_token_report` | Composite **avoid/caution/ok** verdict — honeypot buy/sell simulation + liquidity + ownership + recent rug activity. Call **before buying**. | ~$0.01 |
53
+ | `true402_token_safety` | Structural safety score 0–100 + flags (honeypot sim, liquidity, mint/ownership). | ~$0.005 |
54
+ | `true402_address_safety` | Profile + risk for any address before you send/approve/call it (EOA vs contract, balances, proxy detection). | ~$0.005 |
55
+ | `true402_deployer_check` | Deployer wallet reputation — age, contracts shipped, fresh-throwaway flag — to catch serial ruggers. | ~$0.008 |
56
+
57
+ ## Configuration
58
+
59
+ `true402_tools()` reads the environment, or pass a `PayOpts`:
60
+
61
+ ```python
62
+ from crewai_true402 import true402_tools, PayOpts
63
+
64
+ tools = true402_tools(PayOpts(
65
+ payer_private_key="0x…", # a Base wallet with a little USDC (gas is sponsored; USDC only)
66
+ max_amount_usd=0.10, # hard per-call ceiling — refuses to sign a 402 demanding more
67
+ ))
68
+ ```
69
+
70
+ | Env var | Default | Meaning |
71
+ |---------|---------|---------|
72
+ | `PAYER_PRIVATE_KEY` | — | Base wallet key that signs x402 payments (needs USDC, not ETH). Unset → free trial only. |
73
+ | `TRUE402_BASE_URL` | `https://true402.dev/api` | Override to point at a self-hosted instance. |
74
+ | `BASE_RPC_URL` | `https://mainnet.base.org` | Base RPC for the balance pre-check. |
75
+
76
+ ## Safety
77
+
78
+ The client **refuses to sign** anything that isn't USDC-on-Base within `max_amount_usd` (default $0.10) — so a rogue or compromised endpoint can't make your agent authorize an unexpected asset, network, or amount. The private key is used only to sign locally; it never leaves the process.
79
+
80
+ ## Links
81
+
82
+ - Live check in your browser: <https://true402.dev/check>
83
+ - API reference: <https://true402.dev/docs/api> · OpenAPI: <https://true402.dev/openapi.json>
84
+ - Also available: [LangChain](https://www.npmjs.com/package/@true402.dev/langchain) · [MCP server](https://www.npmjs.com/package/@true402.dev/mcp-server) · [CLI](https://www.npmjs.com/package/@true402.dev/rugcheck)
85
+
86
+ ## License
87
+
88
+ MIT
@@ -0,0 +1,69 @@
1
+ # crewai-true402
2
+
3
+ **[true402](https://true402.dev) tools for [CrewAI](https://www.crewai.com)** — give a Base trading agent a pre-trade **rug/honeypot check** it pays for per call over [x402](https://x402.org) (USDC on Base). No accounts, no API keys — the wallet is the identity. The safety checks have a **free daily trial**, so the tools work out of the box with no wallet configured.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install crewai-true402
9
+ ```
10
+
11
+ ## Use
12
+
13
+ ```python
14
+ from crewai import Agent
15
+ from crewai_true402 import true402_tools
16
+
17
+ # Reads PAYER_PRIVATE_KEY from the env (a Base wallet holding a little USDC).
18
+ # Omit the key to rely on the free daily trial for the safety stalls.
19
+ tools = true402_tools()
20
+
21
+ trader = Agent(
22
+ role="Base memecoin trader",
23
+ goal="Only buy tokens that pass an on-chain safety check",
24
+ tools=tools,
25
+ backstory="You never ape into a token before rug-checking it.",
26
+ )
27
+ ```
28
+
29
+ The agent gets four tools:
30
+
31
+ | Tool | What | Price |
32
+ |------|------|-------|
33
+ | `true402_token_report` | Composite **avoid/caution/ok** verdict — honeypot buy/sell simulation + liquidity + ownership + recent rug activity. Call **before buying**. | ~$0.01 |
34
+ | `true402_token_safety` | Structural safety score 0–100 + flags (honeypot sim, liquidity, mint/ownership). | ~$0.005 |
35
+ | `true402_address_safety` | Profile + risk for any address before you send/approve/call it (EOA vs contract, balances, proxy detection). | ~$0.005 |
36
+ | `true402_deployer_check` | Deployer wallet reputation — age, contracts shipped, fresh-throwaway flag — to catch serial ruggers. | ~$0.008 |
37
+
38
+ ## Configuration
39
+
40
+ `true402_tools()` reads the environment, or pass a `PayOpts`:
41
+
42
+ ```python
43
+ from crewai_true402 import true402_tools, PayOpts
44
+
45
+ tools = true402_tools(PayOpts(
46
+ payer_private_key="0x…", # a Base wallet with a little USDC (gas is sponsored; USDC only)
47
+ max_amount_usd=0.10, # hard per-call ceiling — refuses to sign a 402 demanding more
48
+ ))
49
+ ```
50
+
51
+ | Env var | Default | Meaning |
52
+ |---------|---------|---------|
53
+ | `PAYER_PRIVATE_KEY` | — | Base wallet key that signs x402 payments (needs USDC, not ETH). Unset → free trial only. |
54
+ | `TRUE402_BASE_URL` | `https://true402.dev/api` | Override to point at a self-hosted instance. |
55
+ | `BASE_RPC_URL` | `https://mainnet.base.org` | Base RPC for the balance pre-check. |
56
+
57
+ ## Safety
58
+
59
+ The client **refuses to sign** anything that isn't USDC-on-Base within `max_amount_usd` (default $0.10) — so a rogue or compromised endpoint can't make your agent authorize an unexpected asset, network, or amount. The private key is used only to sign locally; it never leaves the process.
60
+
61
+ ## Links
62
+
63
+ - Live check in your browser: <https://true402.dev/check>
64
+ - API reference: <https://true402.dev/docs/api> · OpenAPI: <https://true402.dev/openapi.json>
65
+ - Also available: [LangChain](https://www.npmjs.com/package/@true402.dev/langchain) · [MCP server](https://www.npmjs.com/package/@true402.dev/mcp-server) · [CLI](https://www.npmjs.com/package/@true402.dev/rugcheck)
66
+
67
+ ## License
68
+
69
+ MIT
@@ -0,0 +1,26 @@
1
+ """true402 tools for CrewAI — pay-per-call on-chain rug/honeypot & address safety for Base AI agents
2
+ over x402 (USDC on Base, no account, no API key; the wallet is the identity).
3
+
4
+ from crewai_true402 import true402_tools
5
+ tools = true402_tools()
6
+ """
7
+ from .tools import (
8
+ AddressSafetyTool,
9
+ DeployerCheckTool,
10
+ TokenReportTool,
11
+ TokenSafetyTool,
12
+ true402_tools,
13
+ )
14
+ from .x402 import PayOpts, pay_stall, sign_payment
15
+
16
+ __version__ = "0.1.0"
17
+ __all__ = [
18
+ "true402_tools",
19
+ "TokenReportTool",
20
+ "TokenSafetyTool",
21
+ "AddressSafetyTool",
22
+ "DeployerCheckTool",
23
+ "PayOpts",
24
+ "pay_stall",
25
+ "sign_payment",
26
+ ]
@@ -0,0 +1,100 @@
1
+ """true402 tools for CrewAI — pay-per-call on-chain safety for Base agents over x402.
2
+
3
+ from crewai_true402 import true402_tools
4
+ tools = true402_tools() # reads PAYER_PRIVATE_KEY from the env
5
+
6
+ agent = Agent(role="Trader", tools=tools, ...)
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ from typing import Optional, Type
12
+
13
+ from crewai.tools import BaseTool
14
+ from pydantic import BaseModel, Field
15
+
16
+ from .x402 import PayOpts, pay_stall
17
+
18
+
19
+ class _TokenInput(BaseModel):
20
+ token: str = Field(..., description="A Base ERC-20 token contract address (0x…)")
21
+
22
+
23
+ class _AddressInput(BaseModel):
24
+ address: str = Field(..., description="Any Base address (0x…) — an EOA or a contract")
25
+
26
+
27
+ class _StallTool(BaseTool):
28
+ """Base for a true402 stall exposed as a CrewAI tool."""
29
+
30
+ path: str
31
+ input_key: str
32
+ opts: PayOpts
33
+
34
+ def _run(self, **kwargs) -> str:
35
+ value = kwargs.get(self.input_key)
36
+ result = pay_stall(self.path, {self.input_key: value}, self.opts)
37
+ return json.dumps(result)
38
+
39
+
40
+ class TokenReportTool(_StallTool):
41
+ name: str = "true402_token_report"
42
+ description: str = (
43
+ "Pre-trade rug/honeypot check for a Base ERC-20: a composite avoid/caution/ok verdict from an "
44
+ "on-chain buy/sell honeypot simulation, liquidity depth, ownership/mint inspection, and recent "
45
+ "rug activity. Call BEFORE buying a token. ~$0.01 USDC over x402."
46
+ )
47
+ args_schema: Type[BaseModel] = _TokenInput
48
+ path: str = "/v1/base/token-report"
49
+ input_key: str = "token"
50
+
51
+
52
+ class TokenSafetyTool(_StallTool):
53
+ name: str = "true402_token_safety"
54
+ description: str = (
55
+ "Structural safety score (0–100) + flags for a Base ERC-20: honeypot simulation, liquidity, "
56
+ "mint/ownership/blacklist. Lighter than token_report. ~$0.005 USDC over x402."
57
+ )
58
+ args_schema: Type[BaseModel] = _TokenInput
59
+ path: str = "/v1/token-safety"
60
+ input_key: str = "token"
61
+
62
+
63
+ class AddressSafetyTool(_StallTool):
64
+ name: str = "true402_address_safety"
65
+ description: str = (
66
+ "Profile + risk for any Base address before you send to / approve / call it: EOA-vs-contract, "
67
+ "ETH+USDC balance, activity, ownership, and upgradeable-proxy (EIP-1967) detection. "
68
+ "~$0.005 USDC over x402."
69
+ )
70
+ args_schema: Type[BaseModel] = _AddressInput
71
+ path: str = "/v1/base/address-safety"
72
+ input_key: str = "address"
73
+
74
+
75
+ class DeployerCheckTool(_StallTool):
76
+ name: str = "true402_deployer_check"
77
+ description: str = (
78
+ "Deployer reputation for a Base token: resolves who created it and that wallet's track record "
79
+ "(age, contracts shipped, fresh-throwaway flag) to catch serial ruggers a structural check "
80
+ "can't see. ~$0.008 USDC over x402."
81
+ )
82
+ args_schema: Type[BaseModel] = _TokenInput
83
+ path: str = "/v1/base/deployer-check"
84
+ input_key: str = "token"
85
+
86
+
87
+ def true402_tools(opts: Optional[PayOpts] = None) -> list[BaseTool]:
88
+ """The four true402 safety tools, ready to hand to a CrewAI Agent.
89
+
90
+ Pass a PayOpts, or leave None to read PAYER_PRIVATE_KEY / TRUE402_BASE_URL / BASE_RPC_URL from the
91
+ environment. Stalls with a free daily trial (token safety/report, address safety) work even with no
92
+ wallet configured — they return a real result until the trial is exhausted, then require payment.
93
+ """
94
+ o = opts or PayOpts.from_env()
95
+ return [
96
+ TokenReportTool(opts=o),
97
+ TokenSafetyTool(opts=o),
98
+ AddressSafetyTool(opts=o),
99
+ DeployerCheckTool(opts=o),
100
+ ]
@@ -0,0 +1,169 @@
1
+ """Pay any true402 stall over x402 and return its JSON.
2
+
3
+ The whole protocol, in one function: POST → 402 with payment terms → sign an EIP-3009 USDC
4
+ authorization → retry with an X-PAYMENT header → 200. No accounts, no API keys; the wallet is the
5
+ identity. USDC on Base, gas sponsored by the facilitator (the payer needs only USDC, not ETH).
6
+
7
+ Safety: the client REFUSES to sign anything that isn't USDC-on-Base within a caller-set cap, so a
8
+ rogue/compromised endpoint (or a MITM past TLS) can't make the agent authorize an unexpected
9
+ asset/network or an excessive amount.
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import json
14
+ import os
15
+ import secrets
16
+ import time
17
+ from dataclasses import dataclass
18
+ from typing import Any
19
+
20
+ import requests
21
+ from eth_account import Account
22
+ from eth_account.messages import encode_typed_data
23
+
24
+ BASE_USDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
25
+ BASE_NETWORK = "eip155:8453"
26
+ BASE_CHAIN_ID = 8453
27
+ DEFAULT_BASE_URL = "https://true402.dev/api"
28
+ DEFAULT_RPC_URL = "https://mainnet.base.org"
29
+ _BALANCE_OF_SELECTOR = "0x70a08231"
30
+
31
+
32
+ @dataclass
33
+ class PayOpts:
34
+ """Configuration for paying true402 stalls."""
35
+
36
+ payer_private_key: str
37
+ """A Base wallet private key holding a little USDC (the payer)."""
38
+ base_url: str = DEFAULT_BASE_URL
39
+ rpc_url: str = DEFAULT_RPC_URL
40
+ max_amount_usd: float = 0.10
41
+ """Hard ceiling, in USDC, on a single signed payment. The client refuses a 402 demanding more."""
42
+ timeout: float = 30.0
43
+
44
+ @classmethod
45
+ def from_env(cls, **overrides: Any) -> "PayOpts":
46
+ """Build from PAYER_PRIVATE_KEY / TRUE402_BASE_URL / BASE_RPC_URL env vars."""
47
+ key = overrides.pop("payer_private_key", None) or os.environ.get("PAYER_PRIVATE_KEY", "")
48
+ return cls(
49
+ payer_private_key=key,
50
+ base_url=overrides.pop("base_url", None) or os.environ.get("TRUE402_BASE_URL", DEFAULT_BASE_URL),
51
+ rpc_url=overrides.pop("rpc_url", None) or os.environ.get("BASE_RPC_URL", DEFAULT_RPC_URL),
52
+ **overrides,
53
+ )
54
+
55
+
56
+ def _usdc_balance(rpc_url: str, holder: str, timeout: float) -> int:
57
+ data = _BALANCE_OF_SELECTOR + holder[2:].rjust(64, "0")
58
+ body = {"jsonrpc": "2.0", "id": 1, "method": "eth_call", "params": [{"to": BASE_USDC, "data": data}, "latest"]}
59
+ r = requests.post(rpc_url, json=body, timeout=timeout, headers={"content-type": "application/json"})
60
+ r.raise_for_status()
61
+ return int(r.json()["result"], 16)
62
+
63
+
64
+ def sign_payment(accept: dict, opts: PayOpts) -> str:
65
+ """Sign an EIP-3009 authorization for the given 402 `accepts[]` entry → base64 X-PAYMENT value."""
66
+ key = opts.payer_private_key
67
+ if not key:
68
+ raise ValueError("no payer_private_key set — cannot pay (set PAYER_PRIVATE_KEY or PayOpts.payer_private_key)")
69
+ if not key.startswith("0x"):
70
+ key = "0x" + key
71
+ account = Account.from_key(key)
72
+
73
+ network = accept.get("network")
74
+ if network and network != BASE_NETWORK:
75
+ raise ValueError(f'unexpected payment network "{network}" (expected {BASE_NETWORK}) — refusing to sign')
76
+ asset = accept.get("asset", "")
77
+ if asset.lower() != BASE_USDC.lower():
78
+ raise ValueError(f"unexpected payment asset {asset} (expected Base USDC) — refusing to sign")
79
+
80
+ value = int(accept.get("amount") or accept.get("maxAmountRequired") or "0")
81
+ cap_atomic = round(opts.max_amount_usd * 1e6)
82
+ if value > cap_atomic:
83
+ raise ValueError(f"402 demands {value} USDC base units, over the ${opts.max_amount_usd} cap — refusing to sign")
84
+
85
+ held = _usdc_balance(opts.rpc_url, account.address, opts.timeout)
86
+ if held < value:
87
+ raise ValueError(f"payer {account.address} holds {held} < {value} USDC base units — fund it")
88
+
89
+ now = int(time.time())
90
+ valid_before = now + int(accept.get("maxTimeoutSeconds") or 120)
91
+ nonce = "0x" + secrets.token_hex(32)
92
+ extra = accept.get("extra") or {}
93
+ authorization = {
94
+ "from": account.address,
95
+ "to": accept["payTo"],
96
+ "value": value,
97
+ "validAfter": now - 60,
98
+ "validBefore": valid_before,
99
+ "nonce": bytes.fromhex(nonce[2:]),
100
+ }
101
+ signable = encode_typed_data(
102
+ domain_data={
103
+ "name": extra.get("name", "USD Coin"),
104
+ "version": extra.get("version", "2"),
105
+ "chainId": BASE_CHAIN_ID,
106
+ "verifyingContract": BASE_USDC,
107
+ },
108
+ message_types={
109
+ "TransferWithAuthorization": [
110
+ {"name": "from", "type": "address"},
111
+ {"name": "to", "type": "address"},
112
+ {"name": "value", "type": "uint256"},
113
+ {"name": "validAfter", "type": "uint256"},
114
+ {"name": "validBefore", "type": "uint256"},
115
+ {"name": "nonce", "type": "bytes32"},
116
+ ],
117
+ },
118
+ message_data=authorization,
119
+ )
120
+ signature = Account.sign_message(signable, key).signature.hex()
121
+ if not signature.startswith("0x"):
122
+ signature = "0x" + signature
123
+
124
+ payment = {
125
+ "x402Version": 2,
126
+ "scheme": "exact",
127
+ "network": network,
128
+ "payload": {
129
+ "signature": signature,
130
+ "authorization": {
131
+ "from": authorization["from"],
132
+ "to": authorization["to"],
133
+ "value": str(value),
134
+ "validAfter": str(authorization["validAfter"]),
135
+ "validBefore": str(authorization["validBefore"]),
136
+ "nonce": nonce,
137
+ },
138
+ },
139
+ }
140
+ import base64
141
+
142
+ return base64.b64encode(json.dumps(payment).encode()).decode()
143
+
144
+
145
+ def pay_stall(path: str, payload: dict, opts: PayOpts) -> Any:
146
+ """POST `payload` to a true402 stall path (e.g. '/v1/base/token-report'), paying over x402 if asked.
147
+
148
+ If the first response is 200 (a free-trial call), returns it without paying. If it's 402, signs and
149
+ retries. Raises on any other status or on a refused/insufficient payment.
150
+ """
151
+ url = opts.base_url.rstrip("/") + path
152
+ headers = {"content-type": "application/json"}
153
+ first = requests.post(url, json=payload, headers=headers, timeout=opts.timeout)
154
+ if first.status_code == 200:
155
+ return first.json() # served free (free trial) — no payment needed
156
+ if first.status_code != 402:
157
+ raise RuntimeError(f"expected HTTP 402 from {path}, got {first.status_code}: {first.text[:200]}")
158
+
159
+ challenge = first.json()
160
+ accepts = challenge.get("accepts") or []
161
+ accept = next((a for a in accepts if a.get("scheme") == "exact"), None)
162
+ if not accept:
163
+ raise RuntimeError('no x402 "exact" payment requirement in the 402')
164
+
165
+ x_payment = sign_payment(accept, opts)
166
+ paid = requests.post(url, json=payload, headers={**headers, "X-PAYMENT": x_payment}, timeout=opts.timeout)
167
+ if paid.status_code != 200:
168
+ raise RuntimeError(f"paid request to {path} failed (HTTP {paid.status_code}): {paid.text[:200]}")
169
+ return paid.json()
@@ -0,0 +1,29 @@
1
+ [build-system]
2
+ requires = ["hatchling"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "crewai-true402"
7
+ version = "0.1.0"
8
+ description = "true402 tools for CrewAI — pay-per-call on-chain rug/honeypot & address safety for Base AI agents over x402 (USDC, no account, no API key)."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ keywords = ["crewai", "crewai-tools", "x402", "base", "rug-check", "honeypot", "token-safety", "crypto", "ai-agent", "agent-tools", "defi", "web3"]
13
+ authors = [{ name = "true402", email = "contact@true402.dev" }]
14
+ dependencies = [
15
+ "requests>=2.28",
16
+ "eth-account>=0.11",
17
+ "pydantic>=2.0",
18
+ ]
19
+
20
+ [project.optional-dependencies]
21
+ crewai = ["crewai>=0.30"]
22
+
23
+ [project.urls]
24
+ Homepage = "https://true402.dev"
25
+ Source = "https://github.com/true402/crewai-true402"
26
+ "OpenAPI" = "https://true402.dev/openapi.json"
27
+
28
+ [tool.hatch.build.targets.wheel]
29
+ packages = ["crewai_true402"]