basedagents 0.1.2__tar.gz → 0.2.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basedagents
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Python SDK for basedagents.ai — cryptographic identity and reputation registry for AI agents
5
5
  Author: basedagents.ai
6
6
  License: MIT
@@ -40,22 +40,47 @@ pip install basedagents
40
40
 
41
41
  ## Quick start
42
42
 
43
+ One call. Idempotent. Safe to run on every startup.
44
+
43
45
  ```python
44
- from basedagents import generate_keypair, RegistryClient
46
+ from basedagents import register_or_load
47
+
48
+ agent_id = register_or_load(
49
+ name="my-research-agent",
50
+ description="Searches the web and summarizes findings.",
51
+ capabilities=["reasoning", "web-search"],
52
+ skills=[{"name": "langchain", "registry": "pypi"}],
53
+ contact_endpoint="https://my-agent.example.com", # optional
54
+ )
55
+ print(agent_id) # ag_...
56
+ ```
45
57
 
46
- keypair = generate_keypair()
58
+ - First run: generates a keypair, solves proof-of-work, registers.
59
+ - Every run after: loads the keypair, verifies registration, returns `agent_id` immediately.
60
+ - Keypair saved at `~/.basedagents/keys/<name>-keypair.json`.
47
61
 
48
- with RegistryClient() as client:
49
- agent = client.register(keypair, {
50
- "name": "MyAgent",
51
- "description": "Does useful things.",
52
- "capabilities": ["reasoning", "code"],
53
- "protocols": ["https", "mcp"],
54
- "skills": [
55
- {"name": "langchain", "registry": "pypi"},
56
- ],
57
- })
58
- print(agent["agent_id"]) # ag_...
62
+ ## LangChain
63
+
64
+ Auto-detects capabilities and skills from your agent's tools:
65
+
66
+ ```python
67
+ from langchain.agents import AgentExecutor, create_react_agent
68
+ from langchain_openai import ChatOpenAI
69
+ from langchain_community.tools.tavily_search import TavilySearchResults
70
+ from basedagents.integrations.langchain import register_langchain_agent
71
+
72
+ llm = ChatOpenAI(model="gpt-4o")
73
+ tools = [TavilySearchResults(max_results=3)]
74
+ agent = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools)
75
+
76
+ agent_id = register_langchain_agent(
77
+ agent,
78
+ name="my-research-agent",
79
+ description="Searches the web and summarizes findings.",
80
+ contact_endpoint="https://my-agent.example.com",
81
+ )
82
+ # → detects skills: langchain, langchain-openai, langchain-community
83
+ # → detects capabilities: web-search
59
84
  ```
60
85
 
61
86
  ## CLI
@@ -71,27 +96,36 @@ basedagents whois Hans
71
96
  basedagents validate
72
97
  ```
73
98
 
74
- ## Signing requests
99
+ ## Low-level API
75
100
 
76
101
  ```python
77
- from basedagents import generate_keypair
78
- from basedagents.auth import build_headers
79
- import httpx, json
102
+ from basedagents import generate_keypair, RegistryClient
80
103
 
81
104
  keypair = generate_keypair()
82
- body = json.dumps({"target_id": "ag_...", "result": "pass", ...})
83
105
 
84
- headers = build_headers(keypair, "POST", "/v1/verify/submit", body)
85
- httpx.post("https://api.basedagents.ai/v1/verify/submit", content=body, headers=headers)
106
+ with RegistryClient() as client:
107
+ agent = client.register(keypair, {
108
+ "name": "MyAgent",
109
+ "description": "Does useful things.",
110
+ "capabilities": ["reasoning", "code"],
111
+ "protocols": ["https", "mcp"],
112
+ "skills": [{"name": "langchain", "registry": "pypi"}],
113
+ })
114
+ print(agent["agent_id"]) # ag_...
86
115
  ```
87
116
 
88
- ## Load a saved keypair
117
+ ## Signing requests manually
89
118
 
90
119
  ```python
120
+ from basedagents.auth import build_headers
91
121
  from basedagents.keypair import AgentKeypair
92
122
  from pathlib import Path
123
+ import httpx, json
93
124
 
94
125
  keypair = AgentKeypair.load(Path("~/.basedagents/keys/myagent-keypair.json").expanduser())
126
+ body = json.dumps({"target_id": "ag_...", "result": "pass"})
127
+ headers = build_headers(keypair, "POST", "/v1/verify/submit", body)
128
+ httpx.post("https://api.basedagents.ai/v1/verify/submit", content=body, headers=headers)
95
129
  ```
96
130
 
97
131
  ## Links
@@ -0,0 +1,106 @@
1
+ # basedagents
2
+
3
+ Python SDK for [basedagents.ai](https://basedagents.ai) — cryptographic identity and reputation registry for AI agents.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ pip install basedagents
9
+ ```
10
+
11
+ ## Quick start
12
+
13
+ One call. Idempotent. Safe to run on every startup.
14
+
15
+ ```python
16
+ from basedagents import register_or_load
17
+
18
+ agent_id = register_or_load(
19
+ name="my-research-agent",
20
+ description="Searches the web and summarizes findings.",
21
+ capabilities=["reasoning", "web-search"],
22
+ skills=[{"name": "langchain", "registry": "pypi"}],
23
+ contact_endpoint="https://my-agent.example.com", # optional
24
+ )
25
+ print(agent_id) # ag_...
26
+ ```
27
+
28
+ - First run: generates a keypair, solves proof-of-work, registers.
29
+ - Every run after: loads the keypair, verifies registration, returns `agent_id` immediately.
30
+ - Keypair saved at `~/.basedagents/keys/<name>-keypair.json`.
31
+
32
+ ## LangChain
33
+
34
+ Auto-detects capabilities and skills from your agent's tools:
35
+
36
+ ```python
37
+ from langchain.agents import AgentExecutor, create_react_agent
38
+ from langchain_openai import ChatOpenAI
39
+ from langchain_community.tools.tavily_search import TavilySearchResults
40
+ from basedagents.integrations.langchain import register_langchain_agent
41
+
42
+ llm = ChatOpenAI(model="gpt-4o")
43
+ tools = [TavilySearchResults(max_results=3)]
44
+ agent = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools)
45
+
46
+ agent_id = register_langchain_agent(
47
+ agent,
48
+ name="my-research-agent",
49
+ description="Searches the web and summarizes findings.",
50
+ contact_endpoint="https://my-agent.example.com",
51
+ )
52
+ # → detects skills: langchain, langchain-openai, langchain-community
53
+ # → detects capabilities: web-search
54
+ ```
55
+
56
+ ## CLI
57
+
58
+ ```bash
59
+ # Register from a manifest file
60
+ basedagents register --manifest ./agent.manifest.json
61
+
62
+ # Look up an agent
63
+ basedagents whois Hans
64
+
65
+ # Verify your keypair against the registry
66
+ basedagents validate
67
+ ```
68
+
69
+ ## Low-level API
70
+
71
+ ```python
72
+ from basedagents import generate_keypair, RegistryClient
73
+
74
+ keypair = generate_keypair()
75
+
76
+ with RegistryClient() as client:
77
+ agent = client.register(keypair, {
78
+ "name": "MyAgent",
79
+ "description": "Does useful things.",
80
+ "capabilities": ["reasoning", "code"],
81
+ "protocols": ["https", "mcp"],
82
+ "skills": [{"name": "langchain", "registry": "pypi"}],
83
+ })
84
+ print(agent["agent_id"]) # ag_...
85
+ ```
86
+
87
+ ## Signing requests manually
88
+
89
+ ```python
90
+ from basedagents.auth import build_headers
91
+ from basedagents.keypair import AgentKeypair
92
+ from pathlib import Path
93
+ import httpx, json
94
+
95
+ keypair = AgentKeypair.load(Path("~/.basedagents/keys/myagent-keypair.json").expanduser())
96
+ body = json.dumps({"target_id": "ag_...", "result": "pass"})
97
+ headers = build_headers(keypair, "POST", "/v1/verify/submit", body)
98
+ httpx.post("https://api.basedagents.ai/v1/verify/submit", content=body, headers=headers)
99
+ ```
100
+
101
+ ## Links
102
+
103
+ - [basedagents.ai](https://basedagents.ai)
104
+ - [API docs](https://api.basedagents.ai/docs)
105
+ - [GitHub](https://github.com/maxfain/basedagents)
106
+ - [npm SDK](https://www.npmjs.com/package/basedagents)
@@ -0,0 +1,46 @@
1
+ """
2
+ basedagents — Python SDK for basedagents.ai
3
+
4
+ Cryptographic identity and reputation registry for AI agents.
5
+
6
+ Quick start (idiomatic):
7
+ from basedagents import register_or_load
8
+
9
+ agent_id = register_or_load(
10
+ name="MyAgent",
11
+ description="Does useful things.",
12
+ capabilities=["reasoning", "code"],
13
+ )
14
+
15
+ LangChain:
16
+ from basedagents.integrations.langchain import register_langchain_agent
17
+
18
+ agent_id = register_langchain_agent(
19
+ executor, # AgentExecutor or list of BaseTool
20
+ name="MyAgent",
21
+ description="Researches topics and writes reports.",
22
+ )
23
+
24
+ Low-level:
25
+ from basedagents import generate_keypair, RegistryClient
26
+
27
+ keypair = generate_keypair()
28
+ with RegistryClient() as client:
29
+ agent = client.register(keypair, {"name": "MyAgent", ...})
30
+ print(agent["agent_id"])
31
+ """
32
+ from .keypair import AgentKeypair, generate as generate_keypair, from_private_key_hex
33
+ from .client import RegistryClient, BasedAgentsError
34
+ from .auth import build_headers as build_auth_headers
35
+ from .easy import register_or_load
36
+
37
+ __version__ = "0.2.0"
38
+ __all__ = [
39
+ "register_or_load",
40
+ "AgentKeypair",
41
+ "RegistryClient",
42
+ "BasedAgentsError",
43
+ "generate_keypair",
44
+ "from_private_key_hex",
45
+ "build_auth_headers",
46
+ ]
@@ -14,7 +14,7 @@ import sys
14
14
  from pathlib import Path
15
15
 
16
16
  API_URL = "https://api.basedagents.ai"
17
- VERSION = "0.1.2"
17
+ VERSION = "0.2.0"
18
18
 
19
19
 
20
20
  def _print_err(msg: str) -> None:
@@ -0,0 +1,142 @@
1
+ """
2
+ Ergonomic one-call registration for agents that don't want the ceremony.
3
+
4
+ Usage:
5
+ from basedagents import register_or_load
6
+
7
+ agent_id = register_or_load(
8
+ name="my-trading-agent",
9
+ description="Analyzes stock trends.",
10
+ capabilities=["reasoning", "data-analysis"],
11
+ skills=[{"name": "langchain", "registry": "pypi"}],
12
+ contact_endpoint="https://my-agent.example.com",
13
+ )
14
+ """
15
+ from __future__ import annotations
16
+
17
+ import re
18
+ import sys
19
+ from pathlib import Path
20
+ from typing import Any
21
+
22
+ from .client import RegistryClient, BasedAgentsError
23
+ from .keypair import AgentKeypair, generate as generate_keypair
24
+
25
+ _DEFAULT_KEYS_DIR = Path.home() / ".basedagents" / "keys"
26
+
27
+
28
+ def _slug(name: str) -> str:
29
+ """Convert agent name to a safe filename slug."""
30
+ return re.sub(r"[^a-z0-9]+", "-", name.lower()).strip("-")
31
+
32
+
33
+ def register_or_load(
34
+ name: str,
35
+ description: str = "",
36
+ capabilities: list[str] | None = None,
37
+ protocols: list[str] | None = None,
38
+ skills: list[dict[str, str]] | None = None,
39
+ contact_endpoint: str | None = None,
40
+ organization: str | None = None,
41
+ version: str | None = None,
42
+ tags: list[str] | None = None,
43
+ keypair_path: Path | str | None = None,
44
+ api_url: str | None = None,
45
+ verbose: bool = True,
46
+ ) -> str:
47
+ """
48
+ Idempotent agent registration. Safe to call on every startup.
49
+
50
+ - If the keypair file already exists AND the agent is registered: returns agent_id immediately.
51
+ - If keypair exists but agent is not registered (e.g. first run after keypair creation): registers.
52
+ - If no keypair file: generates one, registers, saves it.
53
+
54
+ Args:
55
+ name: Unique agent name (globally unique on basedagents.ai)
56
+ description: What the agent does
57
+ capabilities: List of capability strings (e.g. ["reasoning", "code"])
58
+ protocols: Supported protocols (e.g. ["https", "mcp"]). Defaults to ["https"]
59
+ skills: Declared tool dependencies e.g. [{"name": "langchain", "registry": "pypi"}]
60
+ contact_endpoint: HTTP(S) URL where this agent can be reached for verification probes
61
+ organization: Optional org name
62
+ version: Optional version string
63
+ tags: Optional tags for discovery
64
+ keypair_path: Override path for the keypair JSON file.
65
+ Defaults to ~/.basedagents/keys/<name-slug>-keypair.json
66
+ api_url: Override API base URL. Defaults to BASEDAGENTS_API env var or api.basedagents.ai
67
+ verbose: Print progress to stderr (default True)
68
+
69
+ Returns:
70
+ agent_id string (e.g. "ag_...")
71
+ """
72
+ def _log(msg: str) -> None:
73
+ if verbose:
74
+ print(f"[basedagents] {msg}", file=sys.stderr)
75
+
76
+ slug = _slug(name)
77
+ path = Path(keypair_path).expanduser() if keypair_path else _DEFAULT_KEYS_DIR / f"{slug}-keypair.json"
78
+
79
+ from .client import DEFAULT_API_URL
80
+ base_url = api_url or DEFAULT_API_URL
81
+
82
+ with RegistryClient(api_url=base_url) as client:
83
+ # Load or generate keypair
84
+ if path.exists():
85
+ keypair = AgentKeypair.load(path)
86
+ _log(f"Loaded keypair from {path}")
87
+
88
+ # Check if already registered
89
+ if keypair.agent_id:
90
+ try:
91
+ agent = client.get_agent(keypair.agent_id)
92
+ _log(f"Already registered: {agent['name']} ({keypair.agent_id})")
93
+ return keypair.agent_id
94
+ except BasedAgentsError as e:
95
+ if e.status == 404:
96
+ _log("Keypair found but agent not in registry — registering...")
97
+ else:
98
+ raise
99
+ else:
100
+ _log("No keypair found — generating...")
101
+ keypair = generate_keypair()
102
+ _log(f"Generated keypair (public key: {keypair.public_key_b58[:16]}...)")
103
+
104
+ # Build profile
105
+ profile: dict[str, Any] = {
106
+ "name": name,
107
+ "description": description,
108
+ "capabilities": capabilities or [],
109
+ "protocols": protocols or ["https"],
110
+ }
111
+ if skills:
112
+ profile["skills"] = skills
113
+ if contact_endpoint:
114
+ profile["contact_endpoint"] = contact_endpoint
115
+ if organization:
116
+ profile["organization"] = organization
117
+ if version:
118
+ profile["version"] = version
119
+ if tags:
120
+ profile["tags"] = tags
121
+
122
+ # Register with progress reporting
123
+ _log("Solving proof-of-work...")
124
+ last_reported = [0]
125
+
126
+ def on_progress(attempts: int) -> None:
127
+ if attempts - last_reported[0] >= 500_000:
128
+ _log(f" {attempts:,} attempts...")
129
+ last_reported[0] = attempts
130
+
131
+ result = client.register(keypair, profile, on_progress=on_progress)
132
+ agent_id: str = result["agent_id"]
133
+
134
+ # Persist keypair with agent_id stamped in
135
+ from .keypair import from_private_key_hex as _from_hex
136
+ import dataclasses
137
+ keypair = dataclasses.replace(keypair, agent_id=agent_id)
138
+ keypair.save(path)
139
+ _log(f"Registered! agent_id={agent_id}")
140
+ _log(f"Keypair saved to {path}")
141
+
142
+ return agent_id
File without changes
@@ -0,0 +1,224 @@
1
+ """
2
+ LangChain integration for basedagents.
3
+
4
+ Introspects a LangChain AgentExecutor (or tool list) and auto-populates
5
+ the capabilities and skills fields for registration.
6
+
7
+ Usage:
8
+ from langchain.agents import AgentExecutor
9
+ from basedagents.integrations.langchain import register_langchain_agent
10
+
11
+ agent_id = register_langchain_agent(
12
+ executor,
13
+ name="my-research-agent",
14
+ description="Searches the web and summarizes findings.",
15
+ contact_endpoint="https://my-agent.example.com",
16
+ )
17
+ """
18
+ from __future__ import annotations
19
+
20
+ from typing import TYPE_CHECKING, Any
21
+
22
+ if TYPE_CHECKING:
23
+ # Avoid hard dep on langchain at import time
24
+ try:
25
+ from langchain.agents import AgentExecutor
26
+ from langchain_core.tools import BaseTool
27
+ except ImportError:
28
+ AgentExecutor = Any # type: ignore
29
+ BaseTool = Any # type: ignore
30
+
31
+
32
+ # ── Tool name → PyPI package mapping ──────────────────────────────────────────
33
+ # Maps LangChain tool class names and common tool names to their PyPI packages.
34
+ _TOOL_TO_PYPI: dict[str, str] = {
35
+ # LangChain core
36
+ "langchain": "langchain",
37
+ "langchainhub": "langchainhub",
38
+ # LLM providers
39
+ "ChatOpenAI": "langchain-openai",
40
+ "OpenAI": "langchain-openai",
41
+ "ChatAnthropic": "langchain-anthropic",
42
+ "ChatGoogleGenerativeAI": "langchain-google-genai",
43
+ "ChatMistralAI": "langchain-mistralai",
44
+ "ChatGroq": "langchain-groq",
45
+ "ChatOllama": "langchain-ollama",
46
+ "ChatCohere": "langchain-cohere",
47
+ # Search tools
48
+ "TavilySearchResults": "langchain-community",
49
+ "DuckDuckGoSearchRun": "langchain-community",
50
+ "GoogleSearchAPIWrapper": "langchain-community",
51
+ "SerpAPIWrapper": "langchain-community",
52
+ "BingSearchAPIWrapper": "langchain-community",
53
+ "BraveSearch": "langchain-community",
54
+ # Code tools
55
+ "PythonREPLTool": "langchain-experimental",
56
+ "ShellTool": "langchain-community",
57
+ # Data / DB
58
+ "SQLDatabaseToolkit": "langchain-community",
59
+ "PandasDataFrameAgent": "langchain-experimental",
60
+ "SparkDataFrameAgent": "langchain-experimental",
61
+ # File tools
62
+ "ReadFileTool": "langchain-community",
63
+ "WriteFileTool": "langchain-community",
64
+ # Vector stores
65
+ "Chroma": "langchain-chroma",
66
+ "FAISS": "langchain-community",
67
+ "Pinecone": "langchain-pinecone",
68
+ "Weaviate": "langchain-weaviate",
69
+ # Memory
70
+ "ConversationBufferMemory": "langchain",
71
+ "ConversationSummaryMemory": "langchain",
72
+ # Agents SDK
73
+ "create_react_agent": "langchain",
74
+ "create_openai_tools_agent": "langchain",
75
+ "AgentExecutor": "langchain",
76
+ }
77
+
78
+ # ── Tool name → capabilities mapping ─────────────────────────────────────────
79
+ _TOOL_TO_CAPABILITIES: dict[str, list[str]] = {
80
+ "TavilySearchResults": ["web-search"],
81
+ "DuckDuckGoSearchRun": ["web-search"],
82
+ "GoogleSearchAPIWrapper": ["web-search"],
83
+ "SerpAPIWrapper": ["web-search"],
84
+ "BingSearchAPIWrapper": ["web-search"],
85
+ "BraveSearch": ["web-search"],
86
+ "PythonREPLTool": ["code"],
87
+ "ShellTool": ["code", "system"],
88
+ "SQLDatabaseToolkit": ["data-analysis", "sql"],
89
+ "PandasDataFrameAgent": ["data-analysis"],
90
+ "ReadFileTool": ["file-access"],
91
+ "WriteFileTool": ["file-access"],
92
+ "WikipediaQueryRun": ["web-search", "knowledge"],
93
+ "ArxivQueryRun": ["web-search", "knowledge"],
94
+ "HumanInputRun": ["human-in-the-loop"],
95
+ "RequestsGetTool": ["http"],
96
+ "RequestsPostTool": ["http"],
97
+ }
98
+
99
+
100
+ def _extract_tools(agent_or_tools: Any) -> list[Any]:
101
+ """Extract tool list from AgentExecutor or raw list."""
102
+ if isinstance(agent_or_tools, list):
103
+ return agent_or_tools
104
+ # AgentExecutor has .tools attribute
105
+ tools = getattr(agent_or_tools, "tools", None)
106
+ if tools is not None:
107
+ return list(tools)
108
+ return []
109
+
110
+
111
+ def extract_profile(
112
+ agent_or_tools: Any,
113
+ extra_capabilities: list[str] | None = None,
114
+ extra_skills: list[dict[str, str]] | None = None,
115
+ ) -> dict[str, Any]:
116
+ """
117
+ Introspect a LangChain AgentExecutor or tool list and return a partial
118
+ profile dict with auto-detected capabilities and skills.
119
+
120
+ You can merge this with your own fields:
121
+ profile = extract_profile(agent, extra_capabilities=["reasoning"])
122
+ profile.update({"name": "MyAgent", "description": "..."})
123
+ """
124
+ tools = _extract_tools(agent_or_tools)
125
+ capabilities: set[str] = set(extra_capabilities or [])
126
+ skills_seen: set[str] = set()
127
+ skills: list[dict[str, str]] = list(extra_skills or [])
128
+
129
+ # Always include base langchain skill
130
+ if tools and "langchain" not in skills_seen:
131
+ skills.append({"name": "langchain", "registry": "pypi"})
132
+ skills_seen.add("langchain")
133
+
134
+ for tool in tools:
135
+ cls_name = type(tool).__name__
136
+ tool_name = getattr(tool, "name", cls_name)
137
+
138
+ # Capabilities
139
+ for key in (cls_name, tool_name):
140
+ for cap in _TOOL_TO_CAPABILITIES.get(key, []):
141
+ capabilities.add(cap)
142
+
143
+ # Skills — prefer class name lookup, fall back to tool name
144
+ pkg = _TOOL_TO_PYPI.get(cls_name) or _TOOL_TO_PYPI.get(tool_name)
145
+ if pkg and pkg not in skills_seen:
146
+ skills.append({"name": pkg, "registry": "pypi"})
147
+ skills_seen.add(pkg)
148
+
149
+ # Detect LLM package from agent if available
150
+ llm = getattr(agent_or_tools, "agent", None)
151
+ if llm:
152
+ llm_obj = getattr(llm, "llm", None) or getattr(llm, "llm_chain", None)
153
+ if llm_obj:
154
+ llm_cls = type(llm_obj).__name__
155
+ pkg = _TOOL_TO_PYPI.get(llm_cls)
156
+ if pkg and pkg not in skills_seen:
157
+ skills.append({"name": pkg, "registry": "pypi"})
158
+ skills_seen.add(pkg)
159
+
160
+ return {
161
+ "capabilities": sorted(capabilities),
162
+ "protocols": ["https"],
163
+ "skills": skills,
164
+ }
165
+
166
+
167
+ def register_langchain_agent(
168
+ agent_or_tools: Any,
169
+ name: str,
170
+ description: str = "",
171
+ contact_endpoint: str | None = None,
172
+ organization: str | None = None,
173
+ version: str | None = None,
174
+ tags: list[str] | None = None,
175
+ extra_capabilities: list[str] | None = None,
176
+ extra_skills: list[dict[str, str]] | None = None,
177
+ keypair_path: str | None = None,
178
+ api_url: str | None = None,
179
+ verbose: bool = True,
180
+ ) -> str:
181
+ """
182
+ Register a LangChain agent with basedagents.ai.
183
+
184
+ Introspects the agent's tools to auto-detect capabilities and skills.
185
+ Idempotent — safe to call on every startup.
186
+
187
+ Args:
188
+ agent_or_tools: LangChain AgentExecutor or list of BaseTool
189
+ name: Unique agent name
190
+ description: What the agent does
191
+ contact_endpoint: URL where the agent can be reached for verification
192
+ organization: Optional org name
193
+ version: Optional version string
194
+ tags: Optional tags (e.g. ["langchain", "research"])
195
+ extra_capabilities: Additional capabilities beyond auto-detected ones
196
+ extra_skills: Additional skills beyond auto-detected ones
197
+ keypair_path: Override keypair file location
198
+ api_url: Override API URL (defaults to BASEDAGENTS_API env or prod)
199
+ verbose: Print progress (default True)
200
+
201
+ Returns:
202
+ agent_id string
203
+ """
204
+ from ..easy import register_or_load
205
+
206
+ profile = extract_profile(agent_or_tools, extra_capabilities, extra_skills)
207
+
208
+ # Add "langchain" tag automatically
209
+ merged_tags = list(set(["langchain"] + (tags or [])))
210
+
211
+ return register_or_load(
212
+ name=name,
213
+ description=description,
214
+ capabilities=profile["capabilities"],
215
+ protocols=profile["protocols"],
216
+ skills=profile["skills"],
217
+ contact_endpoint=contact_endpoint,
218
+ organization=organization,
219
+ version=version,
220
+ tags=merged_tags,
221
+ keypair_path=keypair_path,
222
+ api_url=api_url,
223
+ verbose=verbose,
224
+ )
@@ -88,8 +88,15 @@ class AgentKeypair:
88
88
 
89
89
  @classmethod
90
90
  def load(cls, path: Path) -> "AgentKeypair":
91
+ import dataclasses
91
92
  data = json.loads(path.read_text())
92
- return from_private_key_hex(data["private_key_hex"])
93
+ kp = from_private_key_hex(data["private_key_hex"])
94
+ # Restore the saved agent_id (may differ from computed ag_<pubkey>
95
+ # only if the server assigned a different format — currently they match,
96
+ # but we preserve it explicitly for forward compatibility)
97
+ if "agent_id" in data:
98
+ kp = dataclasses.replace(kp, agent_id=data["agent_id"])
99
+ return kp
93
100
 
94
101
 
95
102
  def generate() -> AgentKeypair:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: basedagents
3
- Version: 0.1.2
3
+ Version: 0.2.0
4
4
  Summary: Python SDK for basedagents.ai — cryptographic identity and reputation registry for AI agents
5
5
  Author: basedagents.ai
6
6
  License: MIT
@@ -40,22 +40,47 @@ pip install basedagents
40
40
 
41
41
  ## Quick start
42
42
 
43
+ One call. Idempotent. Safe to run on every startup.
44
+
43
45
  ```python
44
- from basedagents import generate_keypair, RegistryClient
46
+ from basedagents import register_or_load
47
+
48
+ agent_id = register_or_load(
49
+ name="my-research-agent",
50
+ description="Searches the web and summarizes findings.",
51
+ capabilities=["reasoning", "web-search"],
52
+ skills=[{"name": "langchain", "registry": "pypi"}],
53
+ contact_endpoint="https://my-agent.example.com", # optional
54
+ )
55
+ print(agent_id) # ag_...
56
+ ```
45
57
 
46
- keypair = generate_keypair()
58
+ - First run: generates a keypair, solves proof-of-work, registers.
59
+ - Every run after: loads the keypair, verifies registration, returns `agent_id` immediately.
60
+ - Keypair saved at `~/.basedagents/keys/<name>-keypair.json`.
47
61
 
48
- with RegistryClient() as client:
49
- agent = client.register(keypair, {
50
- "name": "MyAgent",
51
- "description": "Does useful things.",
52
- "capabilities": ["reasoning", "code"],
53
- "protocols": ["https", "mcp"],
54
- "skills": [
55
- {"name": "langchain", "registry": "pypi"},
56
- ],
57
- })
58
- print(agent["agent_id"]) # ag_...
62
+ ## LangChain
63
+
64
+ Auto-detects capabilities and skills from your agent's tools:
65
+
66
+ ```python
67
+ from langchain.agents import AgentExecutor, create_react_agent
68
+ from langchain_openai import ChatOpenAI
69
+ from langchain_community.tools.tavily_search import TavilySearchResults
70
+ from basedagents.integrations.langchain import register_langchain_agent
71
+
72
+ llm = ChatOpenAI(model="gpt-4o")
73
+ tools = [TavilySearchResults(max_results=3)]
74
+ agent = AgentExecutor(agent=create_react_agent(llm, tools, prompt), tools=tools)
75
+
76
+ agent_id = register_langchain_agent(
77
+ agent,
78
+ name="my-research-agent",
79
+ description="Searches the web and summarizes findings.",
80
+ contact_endpoint="https://my-agent.example.com",
81
+ )
82
+ # → detects skills: langchain, langchain-openai, langchain-community
83
+ # → detects capabilities: web-search
59
84
  ```
60
85
 
61
86
  ## CLI
@@ -71,27 +96,36 @@ basedagents whois Hans
71
96
  basedagents validate
72
97
  ```
73
98
 
74
- ## Signing requests
99
+ ## Low-level API
75
100
 
76
101
  ```python
77
- from basedagents import generate_keypair
78
- from basedagents.auth import build_headers
79
- import httpx, json
102
+ from basedagents import generate_keypair, RegistryClient
80
103
 
81
104
  keypair = generate_keypair()
82
- body = json.dumps({"target_id": "ag_...", "result": "pass", ...})
83
105
 
84
- headers = build_headers(keypair, "POST", "/v1/verify/submit", body)
85
- httpx.post("https://api.basedagents.ai/v1/verify/submit", content=body, headers=headers)
106
+ with RegistryClient() as client:
107
+ agent = client.register(keypair, {
108
+ "name": "MyAgent",
109
+ "description": "Does useful things.",
110
+ "capabilities": ["reasoning", "code"],
111
+ "protocols": ["https", "mcp"],
112
+ "skills": [{"name": "langchain", "registry": "pypi"}],
113
+ })
114
+ print(agent["agent_id"]) # ag_...
86
115
  ```
87
116
 
88
- ## Load a saved keypair
117
+ ## Signing requests manually
89
118
 
90
119
  ```python
120
+ from basedagents.auth import build_headers
91
121
  from basedagents.keypair import AgentKeypair
92
122
  from pathlib import Path
123
+ import httpx, json
93
124
 
94
125
  keypair = AgentKeypair.load(Path("~/.basedagents/keys/myagent-keypair.json").expanduser())
126
+ body = json.dumps({"target_id": "ag_...", "result": "pass"})
127
+ headers = build_headers(keypair, "POST", "/v1/verify/submit", body)
128
+ httpx.post("https://api.basedagents.ai/v1/verify/submit", content=body, headers=headers)
95
129
  ```
96
130
 
97
131
  ## Links
@@ -4,6 +4,7 @@ basedagents/__init__.py
4
4
  basedagents/auth.py
5
5
  basedagents/cli.py
6
6
  basedagents/client.py
7
+ basedagents/easy.py
7
8
  basedagents/keypair.py
8
9
  basedagents/pow.py
9
10
  basedagents.egg-info/PKG-INFO
@@ -11,4 +12,6 @@ basedagents.egg-info/SOURCES.txt
11
12
  basedagents.egg-info/dependency_links.txt
12
13
  basedagents.egg-info/entry_points.txt
13
14
  basedagents.egg-info/requires.txt
14
- basedagents.egg-info/top_level.txt
15
+ basedagents.egg-info/top_level.txt
16
+ basedagents/integrations/__init__.py
17
+ basedagents/integrations/langchain.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "basedagents"
7
- version = "0.1.2"
7
+ version = "0.2.0"
8
8
  description = "Python SDK for basedagents.ai — cryptographic identity and reputation registry for AI agents"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -1,72 +0,0 @@
1
- # basedagents
2
-
3
- Python SDK for [basedagents.ai](https://basedagents.ai) — cryptographic identity and reputation registry for AI agents.
4
-
5
- ## Install
6
-
7
- ```bash
8
- pip install basedagents
9
- ```
10
-
11
- ## Quick start
12
-
13
- ```python
14
- from basedagents import generate_keypair, RegistryClient
15
-
16
- keypair = generate_keypair()
17
-
18
- with RegistryClient() as client:
19
- agent = client.register(keypair, {
20
- "name": "MyAgent",
21
- "description": "Does useful things.",
22
- "capabilities": ["reasoning", "code"],
23
- "protocols": ["https", "mcp"],
24
- "skills": [
25
- {"name": "langchain", "registry": "pypi"},
26
- ],
27
- })
28
- print(agent["agent_id"]) # ag_...
29
- ```
30
-
31
- ## CLI
32
-
33
- ```bash
34
- # Register from a manifest file
35
- basedagents register --manifest ./agent.manifest.json
36
-
37
- # Look up an agent
38
- basedagents whois Hans
39
-
40
- # Verify your keypair against the registry
41
- basedagents validate
42
- ```
43
-
44
- ## Signing requests
45
-
46
- ```python
47
- from basedagents import generate_keypair
48
- from basedagents.auth import build_headers
49
- import httpx, json
50
-
51
- keypair = generate_keypair()
52
- body = json.dumps({"target_id": "ag_...", "result": "pass", ...})
53
-
54
- headers = build_headers(keypair, "POST", "/v1/verify/submit", body)
55
- httpx.post("https://api.basedagents.ai/v1/verify/submit", content=body, headers=headers)
56
- ```
57
-
58
- ## Load a saved keypair
59
-
60
- ```python
61
- from basedagents.keypair import AgentKeypair
62
- from pathlib import Path
63
-
64
- keypair = AgentKeypair.load(Path("~/.basedagents/keys/myagent-keypair.json").expanduser())
65
- ```
66
-
67
- ## Links
68
-
69
- - [basedagents.ai](https://basedagents.ai)
70
- - [API docs](https://api.basedagents.ai/docs)
71
- - [GitHub](https://github.com/maxfain/basedagents)
72
- - [npm SDK](https://www.npmjs.com/package/basedagents)
@@ -1,31 +0,0 @@
1
- """
2
- basedagents — Python SDK for basedagents.ai
3
-
4
- Cryptographic identity and reputation registry for AI agents.
5
-
6
- Quick start:
7
- from basedagents import generate_keypair, RegistryClient
8
-
9
- keypair = generate_keypair()
10
- with RegistryClient() as client:
11
- agent = client.register(keypair, {
12
- "name": "MyAgent",
13
- "description": "Does useful things.",
14
- "capabilities": ["reasoning", "code"],
15
- "protocols": ["https"],
16
- })
17
- print(agent["agent_id"])
18
- """
19
- from .keypair import AgentKeypair, generate as generate_keypair, from_private_key_hex
20
- from .client import RegistryClient, BasedAgentsError
21
- from .auth import build_headers as build_auth_headers
22
-
23
- __version__ = "0.1.2"
24
- __all__ = [
25
- "AgentKeypair",
26
- "RegistryClient",
27
- "BasedAgentsError",
28
- "generate_keypair",
29
- "from_private_key_hex",
30
- "build_auth_headers",
31
- ]
File without changes