agentverse-sdk 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.
- agentverse_sdk-0.1.0/.gitignore +41 -0
- agentverse_sdk-0.1.0/DEVELOPER.md +430 -0
- agentverse_sdk-0.1.0/PKG-INFO +50 -0
- agentverse_sdk-0.1.0/README.md +23 -0
- agentverse_sdk-0.1.0/agentverse_sdk/__init__.py +3 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/__init__.py +0 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/av.py +160 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/config.py +4 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/events.py +210 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/helpers.py +5 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/logger.py +76 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/starlette.py +120 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/storage.py +70 -0
- agentverse_sdk-0.1.0/agentverse_sdk/_common/types.py +234 -0
- agentverse_sdk-0.1.0/agentverse_sdk/a2a/__init__.py +3 -0
- agentverse_sdk-0.1.0/agentverse_sdk/a2a/_app.py +266 -0
- agentverse_sdk-0.1.0/agentverse_sdk/a2a/content.py +212 -0
- agentverse_sdk-0.1.0/agentverse_sdk/a2a/profile.py +90 -0
- agentverse_sdk-0.1.0/agentverse_sdk/langgraph/__init__.py +3 -0
- agentverse_sdk-0.1.0/agentverse_sdk/langgraph/__main__.py +142 -0
- agentverse_sdk-0.1.0/agentverse_sdk/langgraph/_app.py +415 -0
- agentverse_sdk-0.1.0/agentverse_sdk/langgraph/config.py +21 -0
- agentverse_sdk-0.1.0/agentverse_sdk/langgraph/content.py +244 -0
- agentverse_sdk-0.1.0/agentverse_sdk/langgraph/profile.py +70 -0
- agentverse_sdk-0.1.0/pyproject.toml +70 -0
- agentverse_sdk-0.1.0/tests/conftest.py +29 -0
- agentverse_sdk-0.1.0/tests/test_langchain_content.py +769 -0
- agentverse_sdk-0.1.0/tests/test_registration.py +68 -0
- agentverse_sdk-0.1.0/tests/test_storage.py +125 -0
- agentverse_sdk-0.1.0/uagents_core.log +0 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# IDEs
|
|
2
|
+
.idea/
|
|
3
|
+
.DS_Store
|
|
4
|
+
|
|
5
|
+
# Data
|
|
6
|
+
*.sqlite*
|
|
7
|
+
|
|
8
|
+
# Python Specific
|
|
9
|
+
__pycache__
|
|
10
|
+
*.py[cgo]
|
|
11
|
+
*.egg-info/
|
|
12
|
+
.venv/
|
|
13
|
+
.pnpm-store/
|
|
14
|
+
|
|
15
|
+
# docker secrets
|
|
16
|
+
.env
|
|
17
|
+
# but allow test env files
|
|
18
|
+
!.env.test
|
|
19
|
+
|
|
20
|
+
# Cursor personal (machine-specific, not shared)
|
|
21
|
+
.cursor/rules/personal/
|
|
22
|
+
.cursor/commands/personal/
|
|
23
|
+
|
|
24
|
+
# vscode
|
|
25
|
+
.vscode/
|
|
26
|
+
.history/
|
|
27
|
+
# misc
|
|
28
|
+
.__untracked__
|
|
29
|
+
|
|
30
|
+
# vagrant
|
|
31
|
+
.vagrant/
|
|
32
|
+
|
|
33
|
+
# AVCTL Build directory
|
|
34
|
+
build/
|
|
35
|
+
|
|
36
|
+
# Goreleaser build directory
|
|
37
|
+
dist/
|
|
38
|
+
|
|
39
|
+
# ignore old mailbox-app folder
|
|
40
|
+
/ui/mailbox-app/# Lint fix verification
|
|
41
|
+
*.code-workspace
|
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Agentverse SDK — Developer Guide
|
|
2
|
+
|
|
3
|
+
## Package Info
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **PyPI name** | `agentverse-sdk` |
|
|
8
|
+
| **Location** | `agentverse-core/pkg/agentverse-sdk/` (migrated from `uAgents/uagents-core/uagents_core/agentverse/sdk/`) |
|
|
9
|
+
| **Source package** | `agentverse_sdk` |
|
|
10
|
+
| **Core dependency** | `uagents-core` (external PyPI package — provides identity, envelope, chat protocol types) |
|
|
11
|
+
|
|
12
|
+
### Public API
|
|
13
|
+
|
|
14
|
+
```python
|
|
15
|
+
from agentverse_sdk.a2a import init # A2A adapter
|
|
16
|
+
from agentverse_sdk.langgraph import init # LangGraph adapter
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
pip install agentverse-sdk[a2a] # A2A adapter
|
|
23
|
+
pip install agentverse-sdk[langgraph] # LangGraph adapter
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
For local development (from monorepo root):
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install -e "pkg/agentverse-sdk[a2a,langgraph,dev]"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Objective
|
|
35
|
+
|
|
36
|
+
Connect any AI agent framework to [Agentverse](https://agentverse.ai) with zero user-facing configuration beyond a single URI string. The SDK:
|
|
37
|
+
|
|
38
|
+
1. **Registers** the agent with Agentverse on startup.
|
|
39
|
+
2. **Receives** chat messages via a Starlette POST endpoint (`/av/chat`).
|
|
40
|
+
3. **Delegates** work to the underlying framework (LangGraph, A2A, etc.).
|
|
41
|
+
4. **Replies** with the framework's output, converted to the chat protocol.
|
|
42
|
+
5. **Reports** lifecycle events (start/stop) and errors to the Agentverse Events API.
|
|
43
|
+
|
|
44
|
+
The user's experience is: call `init("agentverse://...")` and the SDK handles everything else invisibly.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Philosophy
|
|
49
|
+
|
|
50
|
+
| Principle | Meaning |
|
|
51
|
+
|-----------|---------|
|
|
52
|
+
| **Silent by default** | The SDK never prints, raises, or disrupts the host application. Failures are reported to Agentverse and swallowed. |
|
|
53
|
+
| **Graceful degradation** | If init fails, the underlying framework still runs unpatched. A broken SDK must never break the user's agent. |
|
|
54
|
+
| **Single point of truth** | The agent URI encodes identity, Agentverse host, and optional log level. No env vars, config files, or scattered state. |
|
|
55
|
+
| **Wrapper, not framework** | The SDK wraps — it doesn't own the event loop, server, or application lifecycle. It hooks into Starlette lifespans and routes. |
|
|
56
|
+
| **Observability via events** | All errors, state transitions, and lifecycle signals are dispatched to Agentverse's Events API. Logging is developer-only (hidden unless `?log=LEVEL` is set on the URI). |
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Architecture
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
┌──────────────────────────────────────────────────────┐
|
|
64
|
+
│ User's Agent Application (LangGraph / A2A / ...) │
|
|
65
|
+
└────────────────────────┬─────────────────────────────┘
|
|
66
|
+
│ wraps
|
|
67
|
+
┌────────────────────────▼─────────────────────────────┐
|
|
68
|
+
│ Adapter Module (langgraph/ or a2a/) │
|
|
69
|
+
│ - init() → parse URI, store _ctx │
|
|
70
|
+
│ - Application → register, add /av/chat route │
|
|
71
|
+
│ - _chat() → validate, ack, dispatch to bg │
|
|
72
|
+
│ - _process_bg() → call framework, convert, reply │
|
|
73
|
+
└────────────────────────┬─────────────────────────────┘
|
|
74
|
+
│ uses
|
|
75
|
+
┌────────────────────────▼─────────────────────────────┐
|
|
76
|
+
│ _common/ │
|
|
77
|
+
│ - av.py → HTTP transport (register, send) │
|
|
78
|
+
│ - events.py → error handling decorators │
|
|
79
|
+
│ - starlette.py→ request parsing, lifespan wiring │
|
|
80
|
+
│ - types.py → AgentUri, AgentContext, events │
|
|
81
|
+
│ - config.py → shared constants │
|
|
82
|
+
│ - logger.py → dual-audience logging │
|
|
83
|
+
│ - helpers.py → utc_now() │
|
|
84
|
+
└──────────────────────────────────────────────────────┘
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
## Invariants
|
|
90
|
+
|
|
91
|
+
These must hold in every adapter. Violating any of them is a bug.
|
|
92
|
+
|
|
93
|
+
1. **Init never raises.** URI parsing failure → `log_sdk` + return. Everything else → `handle_init_errors` (suppress + report).
|
|
94
|
+
2. **`_ctx.agent is None` means init failed.** All downstream code must guard on this and fall through to unpatched behavior.
|
|
95
|
+
3. **`_chat()` returns `200 {}` or raises `HTTPException`.** Validation failures (bad envelope, wrong target) raise `HTTPException` with an appropriate status code. Successful requests return `200 {}` immediately — all processing (ack, framework call, reply) happens in a `BackgroundTask`.
|
|
96
|
+
4. **Every background error produces a reply.** The sender must always receive either a real reply or an error message — never silence. If sending the reply itself fails, push a `"user"` event instead (the sender cannot be reached, but the failure must still be visible on the agent dashboard).
|
|
97
|
+
5. **Error handling is structural, not inline.** Decorators (`report_error_starlette`, `report_error_reply`) and context managers (`handle_init_errors`, `chat_error_on_fail`) own all error paths. Business logic never has bare try/except.
|
|
98
|
+
6. **Error dispatch is self-guarded.** Any code that runs inside an `except` block and can itself fail must be wrapped in its own try/except. These are last-line-of-defense paths.
|
|
99
|
+
7. **Content extraction is pure.** `content.py` modules raise on failure — they never catch, log, or dispatch. The calling decorator handles everything.
|
|
100
|
+
8. **The user never sees SDK internals.** No prints, no stack traces, no log output unless developer logging is explicitly enabled.
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Request Processing Flow
|
|
105
|
+
|
|
106
|
+
Both adapters follow the same pipeline. Framework-specific steps are marked.
|
|
107
|
+
|
|
108
|
+
```
|
|
109
|
+
Incoming POST /av/chat
|
|
110
|
+
│
|
|
111
|
+
▼
|
|
112
|
+
┌─ _chat() ──────────────────────────────────── @report_error_starlette ─┐
|
|
113
|
+
│ 1. Parse envelope from JSON body │
|
|
114
|
+
│ 2. Verify envelope signature (if enabled) │
|
|
115
|
+
│ 3. Validate target address matches this agent │
|
|
116
|
+
│ 4. Deserialize into ChatMessage or ChatAcknowledgement │
|
|
117
|
+
│ 5. If ChatAcknowledgement → return 200 {} (no-op) │
|
|
118
|
+
│ 6. Return 200 {} with BackgroundTask → _process_bg() │
|
|
119
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
120
|
+
│
|
|
121
|
+
▼
|
|
122
|
+
┌─ _process_bg() ────────────────────────────── @report_error_reply ─────┐
|
|
123
|
+
│ 1. Send ChatAcknowledgement to sender │
|
|
124
|
+
│ 2. If message is StartSessionContent only → return (no-op) │
|
|
125
|
+
│ 3. Extract text from ChatMessage │
|
|
126
|
+
│ 4. Call framework: │
|
|
127
|
+
│ • LangGraph: POST /runs/wait via ASGI transport → single response │
|
|
128
|
+
│ • A2A: on_message_send_stream() → async event stream │
|
|
129
|
+
│ 5. Convert framework output to list[AgentContent]: │
|
|
130
|
+
│ • LangGraph: extract_ai_content(response_dict) │
|
|
131
|
+
│ • A2A: extract_content(event) per event │
|
|
132
|
+
│ 6. If no content produced → substitute DEFAULT_EMPTY_RESPONSE_TEXT │
|
|
133
|
+
│ 7. Send ChatMessage reply to sender │
|
|
134
|
+
└─────────────────────────────────────────────────────────────────────────┘
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Key Differences Between Adapters
|
|
138
|
+
|
|
139
|
+
| Aspect | LangGraph | A2A |
|
|
140
|
+
|--------|-----------|-----|
|
|
141
|
+
| Framework call | Single HTTP POST via ASGI transport | Async generator (streaming events) |
|
|
142
|
+
| Session handling | Maps session → LangGraph thread_id (uuid5 hash) | Maps session → A2A contextId |
|
|
143
|
+
| Reply cadence | One reply per request | One reply per content-bearing event |
|
|
144
|
+
| Empty fallback | In `_send_reply` via `content or [fallback]` | Triggered when `is_task_complete` and nothing was sent |
|
|
145
|
+
| Registration timing | During lifespan startup (env vars not ready at build time) | During `__init__` (server env is ready) |
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## Error Handling
|
|
150
|
+
|
|
151
|
+
### The Decorator Stack
|
|
152
|
+
|
|
153
|
+
```
|
|
154
|
+
handle_init_errors(uri) → sync context manager, init phase
|
|
155
|
+
catches → dispatches event → suppresses
|
|
156
|
+
|
|
157
|
+
report_error_starlette(ctx) → async decorator, HTTP handlers
|
|
158
|
+
catches → dispatches event → re-raises as HTTPException(500)
|
|
159
|
+
(HTTPException passes through unchanged for custom HTTP errors)
|
|
160
|
+
|
|
161
|
+
report_error_reply(ctx) → async decorator, background processors
|
|
162
|
+
catches ChatProcessingError → dispatches event → sends error reply
|
|
163
|
+
catches Exception → dispatches event → sends generic error reply
|
|
164
|
+
|
|
165
|
+
chat_error_on_fail(msg) → async context manager, inside @report_error_reply
|
|
166
|
+
catches → raises ChatProcessingError (which the outer decorator handles)
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Error Flow Diagram
|
|
170
|
+
|
|
171
|
+
```
|
|
172
|
+
Business logic raises
|
|
173
|
+
│
|
|
174
|
+
├── Inside chat_error_on_fail?
|
|
175
|
+
│ └── Wraps as ChatProcessingError(custom_msg) → bubbles up
|
|
176
|
+
│
|
|
177
|
+
▼
|
|
178
|
+
report_error_reply catches
|
|
179
|
+
│
|
|
180
|
+
├── ChatProcessingError
|
|
181
|
+
│ ├── Has .exc? → dispatch exception event + send .reply_text to user
|
|
182
|
+
│ └── No .exc → dispatch message event + send .reply_text to user
|
|
183
|
+
│
|
|
184
|
+
└── Any other Exception
|
|
185
|
+
└── dispatch exception event + send DEFAULT_ERROR_REPLY to user
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### `chat_error_on_fail` Categories
|
|
189
|
+
|
|
190
|
+
| Usage | `category` | `include_exc` | Rationale |
|
|
191
|
+
|-------|-----------|---------------|-----------|
|
|
192
|
+
| Sending ack/reply (network) | `"user"` | `False` | Network failures aren't system bugs; don't attach traceback to event |
|
|
193
|
+
| Parsing/extracting content | `"system"` | `True` (default) | SDK code failed; full traceback needed for debugging |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Common Helpers Reference
|
|
198
|
+
|
|
199
|
+
### `av.py` — Agentverse Transport
|
|
200
|
+
|
|
201
|
+
| Function | Purpose |
|
|
202
|
+
|----------|---------|
|
|
203
|
+
| `generate_agent_auth_token(identity)` | Create a signed attestation token valid for 2 minutes |
|
|
204
|
+
| `register_to_agentverse_sync(request, headers, config)` | Sync HTTP POST to register agent. Raises on failure (caller catches). |
|
|
205
|
+
| `send_message_to_agent(dest, msg, sender, ...)` | Resolve destination via Almanac, send envelope. Async. Raises on failure. |
|
|
206
|
+
| `set_agent_status(identity, active, config)` | Report online/offline to Almanac. Async. |
|
|
207
|
+
| `verify_envelope(envelope)` | Check signature. Returns False on any failure. User addresses always pass. |
|
|
208
|
+
| `_post_data(url, data, ...)` | Async httpx POST. Raises on non-2xx. |
|
|
209
|
+
| `_post_data_sync(url, data, ...)` | Sync requests POST. Raises on non-2xx. Used only for event dispatch. |
|
|
210
|
+
|
|
211
|
+
### `events.py` — Error Handling Machinery
|
|
212
|
+
|
|
213
|
+
| Symbol | Purpose |
|
|
214
|
+
|--------|---------|
|
|
215
|
+
| `handle_init_errors(uri)` | Context manager: catch → report → suppress. For init and build phases. |
|
|
216
|
+
| `report_error(ctx, category, reraise)` | Base decorator: catch → dispatch event → optionally re-raise. |
|
|
217
|
+
| `report_error_starlette(ctx)` | HTTP decorator: report_error(reraise=True) + convert to 500. |
|
|
218
|
+
| `report_error_reply(ctx)` | Background decorator: catch → dispatch → send error reply to sender. |
|
|
219
|
+
| `chat_error_on_fail(msg, category, include_exc)` | Context manager: catch → raise ChatProcessingError. Use inside @report_error_reply. |
|
|
220
|
+
| `ChatProcessingError(msg, category, exc)` | Custom exception to control error reply text. Like HTTPException for background tasks. |
|
|
221
|
+
| `dispatch_event(agent, events)` | Sync POST to `/v1/events`. Raises on failure. |
|
|
222
|
+
| `dispatch_event_safe(agent, events)` | Same but swallows failures. Use in except blocks. |
|
|
223
|
+
|
|
224
|
+
### `starlette.py` — HTTP Layer
|
|
225
|
+
|
|
226
|
+
| Function | Purpose |
|
|
227
|
+
|----------|---------|
|
|
228
|
+
| `parse_chat_message_from_request(request, verify, address)` | Validate envelope + deserialize to ChatMessage or ChatAcknowledgement. Raises HTTPException on any failure. |
|
|
229
|
+
| `setup_agent_status_lifespan(existing)` | Wrap an existing lifespan with start/stop status reporting. |
|
|
230
|
+
| `set_app_state(app, state)` | Attach AgentStarletteState to `app.state.agent`. |
|
|
231
|
+
|
|
232
|
+
### `types.py` — Core Data Types
|
|
233
|
+
|
|
234
|
+
| Type | Role |
|
|
235
|
+
|------|------|
|
|
236
|
+
| `AgentUri` | Parsed URI: key, name, agentverse config, identity (cached). Frozen Pydantic model. |
|
|
237
|
+
| `AgentOptions` | Runtime options (`verify_envelope`, `track_interactions`). Pydantic model. |
|
|
238
|
+
| `AgentverseAgent` | Combines URI + profile + metadata + options. Pydantic model. |
|
|
239
|
+
| `AgentContext` | Mutable runtime state (dataclass). Holds `agent: AgentverseAgent | None`. |
|
|
240
|
+
| `AgentStarletteState` | Attached to app.state. Holds key + agentverse config. Dataclass with cached identity. |
|
|
241
|
+
| `AgentBatchEvents` | Event payload for `/v1/events`. Factory methods: `from_exception()`, `from_message()`. |
|
|
242
|
+
|
|
243
|
+
### `config.py` — Constants
|
|
244
|
+
|
|
245
|
+
| Constant | Value | Purpose |
|
|
246
|
+
|----------|-------|---------|
|
|
247
|
+
| `DEFAULT_AGENTVERSE_CHAT_ENDPOINT` | `"/av/chat"` | Route path for incoming messages |
|
|
248
|
+
| `DEFAULT_HTTP_REQUESTS_TIMEOUT` | `10` (seconds) | Timeout for outbound HTTP calls |
|
|
249
|
+
| `AGENT_AUTH_TOKEN_VALIDITY` | `120` (seconds) | Token lifetime |
|
|
250
|
+
| `DEFAULT_EMPTY_RESPONSE_TEXT` | `"Agent returned no response."` | Fallback when framework produces no content |
|
|
251
|
+
|
|
252
|
+
By default, SDK agents register as **proxy agents** (`track_interactions=True` on `AgentOptions`): hub stores the chat URL as `redirect_url` and Almanac publishes `agentverse.proxy_endpoint`. Senders hit `/v2/agents/proxy/submit`, hub records `ProxyAgentInteractionEvent`, then redirects to the chat URL. Opt out with `AgentOptions(track_interactions=False)`.
|
|
253
|
+
|
|
254
|
+
### `logger.py` — Logging
|
|
255
|
+
|
|
256
|
+
| Symbol | Purpose |
|
|
257
|
+
|--------|---------|
|
|
258
|
+
| `logger` | Standard Python logger (`"agentverse-sdk"`). Level CRITICAL by default (hidden). |
|
|
259
|
+
| `log_sdk(msg)` | Emits at level 99 (displays as WARNING). Always visible. Reserved for critical user-facing messages. |
|
|
260
|
+
| `configure(level)` | Enables developer logging at the given level. Called when URI has `?log=DEBUG`. |
|
|
261
|
+
|
|
262
|
+
---
|
|
263
|
+
|
|
264
|
+
## Implementing a New Adapter
|
|
265
|
+
|
|
266
|
+
Follow this checklist when adding support for a new framework:
|
|
267
|
+
|
|
268
|
+
### 1. Module Structure
|
|
269
|
+
|
|
270
|
+
```
|
|
271
|
+
agentverse_sdk/your_framework/
|
|
272
|
+
__init__.py # re-exports init(), Application class
|
|
273
|
+
_app.py # init(), Application class
|
|
274
|
+
config.py # Framework-specific constants (ports, URLs, timeouts)
|
|
275
|
+
content.py # Framework output → list[AgentContent] conversion
|
|
276
|
+
profile.py # Build RegistrationRequest from framework metadata
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### 2. Required Components
|
|
280
|
+
|
|
281
|
+
```python
|
|
282
|
+
from dataclasses import dataclass
|
|
283
|
+
from agentverse_sdk._common.types import AgentContext
|
|
284
|
+
|
|
285
|
+
# If you need extra state beyond AgentContext.agent:
|
|
286
|
+
@dataclass
|
|
287
|
+
class YourFrameworkContext(AgentContext):
|
|
288
|
+
config: YourConfig | None = None
|
|
289
|
+
|
|
290
|
+
_ctx = YourFrameworkContext()
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### 3. `init(agent_uri_str, ...)` Function
|
|
294
|
+
|
|
295
|
+
```python
|
|
296
|
+
def init(agent: str, *, profile=None, metadata=None, disable_message_auth=False):
|
|
297
|
+
# 1. Parse URI (outside handle_init_errors — report malformed URI via log_sdk)
|
|
298
|
+
try:
|
|
299
|
+
uri = AgentUri.from_str(agent)
|
|
300
|
+
except Exception as e:
|
|
301
|
+
log_sdk(FAILED_INIT_ERROR_FORMAT.format(f"malformed agent URI: {e}"))
|
|
302
|
+
return
|
|
303
|
+
|
|
304
|
+
# 2. Configure logging if URI has ?log=LEVEL
|
|
305
|
+
if uri.log_level is not None:
|
|
306
|
+
configure(uri.log_level)
|
|
307
|
+
|
|
308
|
+
# 3. Everything else inside handle_init_errors (suppresses + reports)
|
|
309
|
+
with handle_init_errors(uri):
|
|
310
|
+
_ctx.agent = AgentverseAgent(uri=uri, profile=profile, ...)
|
|
311
|
+
_ctx.config = YourConfig(...)
|
|
312
|
+
# Framework-specific patching/instrumentation
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### 4. Application Class Pattern
|
|
316
|
+
|
|
317
|
+
```python
|
|
318
|
+
class YourApplication:
|
|
319
|
+
def register(self):
|
|
320
|
+
# Build RegistrationRequest, call register_to_agentverse_sync
|
|
321
|
+
# Raises on failure — caller wraps in handle_init_errors
|
|
322
|
+
...
|
|
323
|
+
|
|
324
|
+
def build(self) -> Starlette:
|
|
325
|
+
# Guard: if _ctx.agent is None or _ctx.config is None → return original app
|
|
326
|
+
# Wrap lifespan with setup_agent_status_lifespan
|
|
327
|
+
# Add POST /av/chat route → self._chat
|
|
328
|
+
# Attach AgentStarletteState via set_app_state
|
|
329
|
+
...
|
|
330
|
+
|
|
331
|
+
@report_error_starlette(_ctx)
|
|
332
|
+
async def _chat(self, request: Request) -> Response:
|
|
333
|
+
# parse_chat_message_from_request → if ack, return 200
|
|
334
|
+
# return 200 with BackgroundTask → self._process_bg
|
|
335
|
+
...
|
|
336
|
+
|
|
337
|
+
@report_error_reply(_ctx, "user")
|
|
338
|
+
async def _process_bg(self, env: Envelope, msg: ChatMessage):
|
|
339
|
+
# chat_error_on_fail("Failed to send ack") → send ack
|
|
340
|
+
# if StartSessionContent only → return
|
|
341
|
+
# chat_error_on_fail("Failed to parse...") → call framework + extract content
|
|
342
|
+
# chat_error_on_fail("Failed to send reply") → send reply (with empty fallback)
|
|
343
|
+
...
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
### 5. Content Extraction (`content.py`)
|
|
347
|
+
|
|
348
|
+
- **Input**: Framework-specific response (dict, event stream, etc.) + `agent_uri: AgentUri`
|
|
349
|
+
- **Output**: `list[AgentContent]` (TextContent, ResourceContent)
|
|
350
|
+
- **Async**: Content functions are async (storage upload requires it).
|
|
351
|
+
- **Rules**:
|
|
352
|
+
- Raise on unrecoverable failure (the calling decorator handles it).
|
|
353
|
+
- Never drop data. Use data: URIs for binary, JSON serialization for structured data.
|
|
354
|
+
- Handle each content type with explicit isinstance/type checks.
|
|
355
|
+
- Return `[]` for genuinely empty responses (the adapter handles the fallback).
|
|
356
|
+
- For operations with graceful fallbacks (e.g. storage upload), use the `_safe`
|
|
357
|
+
variant of the helper (e.g. `upload_to_storage_safe`). The safe helper handles
|
|
358
|
+
logging and system event dispatch internally.
|
|
359
|
+
|
|
360
|
+
---
|
|
361
|
+
|
|
362
|
+
## Known Issues & Improvement Opportunities
|
|
363
|
+
|
|
364
|
+
### Design Improvements to Consider
|
|
365
|
+
|
|
366
|
+
1. **Extract common background processing** — Both adapters share identical logic for: send ack → check StartSession → [framework-specific] → send reply. The shared prefix/suffix could be a base class method or a helper function, with only the framework call as the varying step.
|
|
367
|
+
|
|
368
|
+
2. **Testable Application classes** — Currently `_ctx` is a module-level global, making unit testing require module-level state manipulation. Consider accepting context as a constructor parameter (with module-level default) so tests can inject isolated state.
|
|
369
|
+
|
|
370
|
+
3. **Content fallback in common** — Both adapters implement `content or [TextContent(text=DEFAULT_EMPTY_RESPONSE_TEXT)]` independently. This could be a shared `ensure_content(content: list[AgentContent]) -> list[AgentContent]` helper in common.
|
|
371
|
+
|
|
372
|
+
4. **Rate limiting / backoff** — Event dispatch (`dispatch_event`) has no retry or backoff. If the Events API is temporarily down, events are silently lost. Consider a simple bounded queue with retry (similar to Sentry's telemetry buffer pattern).
|
|
373
|
+
|
|
374
|
+
5. **Structured event metadata** — Currently errors are dispatched with just exception + traceback. Adding structured metadata (adapter name, framework version, message_id being processed) would improve Agentverse-side debugging.
|
|
375
|
+
|
|
376
|
+
---
|
|
377
|
+
|
|
378
|
+
## Logging & Events
|
|
379
|
+
|
|
380
|
+
### Event Categories
|
|
381
|
+
|
|
382
|
+
| Category | Audience | Dashboard visibility |
|
|
383
|
+
|----------|----------|---------------------|
|
|
384
|
+
| `"system"` | Agentverse/SDK developers only | Internal monitoring — users never see these |
|
|
385
|
+
| `"user"` | End users | Visible on the user's agent dashboard |
|
|
386
|
+
|
|
387
|
+
Three entities produce or are affected by errors:
|
|
388
|
+
|
|
389
|
+
1. **System** — the Agentverse platform and SDK infrastructure.
|
|
390
|
+
2. **User** — the agent developer using Agentverse services.
|
|
391
|
+
3. **Sender** — external agents interacting with the user's agent.
|
|
392
|
+
|
|
393
|
+
**Decision rule:** `"user"` events for anything related to the user or sender. Everything else is `"system"`.
|
|
394
|
+
|
|
395
|
+
**Use `"system"` events for:** infrastructure degradation the SDK handles gracefully (storage upload failures, transient service errors) and SDK bugs. These let the Agentverse team detect problems without requiring users to share logs. Users never see these.
|
|
396
|
+
|
|
397
|
+
**Use `"user"` events for:** errors caused by the user's own code (tool failures, unhandled exceptions in the framework) **and** errors originating from sender agents (malformed messages, invalid envelopes). Reporting sender-side errors gives the user a clear record of where the issue occurred, helping all parties diagnose problems faster.
|
|
398
|
+
|
|
399
|
+
### Logging Channels
|
|
400
|
+
|
|
401
|
+
| Audience | API | Visibility | Use for |
|
|
402
|
+
|----------|-----|-----------|---------|
|
|
403
|
+
| End user | `log_sdk(msg)` | Always visible (level 99) | Init errors only: URI parse failures, events API unreachable during init |
|
|
404
|
+
| Developer | `logger.debug/info/error` | Hidden unless `?log=LEVEL` | Registration, sender addresses, dispatch outcomes |
|
|
405
|
+
| Agentverse team | `dispatch_event_safe(uri, event, "system")` | Internal dashboard | Graceful degradations, service health signals |
|
|
406
|
+
|
|
407
|
+
### Graceful Degradation Pattern
|
|
408
|
+
|
|
409
|
+
When a non-critical operation fails but the SDK can continue with a fallback:
|
|
410
|
+
|
|
411
|
+
```python
|
|
412
|
+
except Exception as e:
|
|
413
|
+
logger.error("Storage upload failed: %s", e)
|
|
414
|
+
dispatch_event_safe(
|
|
415
|
+
agent_uri,
|
|
416
|
+
AgentBatchEvents.from_exception(e, "", "system"),
|
|
417
|
+
)
|
|
418
|
+
# proceed with fallback (e.g. data: URI)
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
This combination gives: developer logs for local debugging + system events for Agentverse-side monitoring — without requiring the user to do anything.
|
|
422
|
+
|
|
423
|
+
**Never log:**
|
|
424
|
+
- Raw Request objects (useless repr)
|
|
425
|
+
- Info the ASGI server already prints (method, path, status)
|
|
426
|
+
- Secrets, keys, or full URIs
|
|
427
|
+
|
|
428
|
+
**Always log:**
|
|
429
|
+
- What the SDK does that's invisible to the framework (registration, ack sent, reply dispatched)
|
|
430
|
+
- Error context inside except blocks (but only at `error` level)
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentverse-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Agentverse SDK — connect any AI agent framework to Agentverse
|
|
5
|
+
Project-URL: homepage, https://fetch.ai
|
|
6
|
+
Project-URL: repository, https://github.com/fetchai/agentverse
|
|
7
|
+
Author-email: "Fetch.ai" <developer@fetch.ai>
|
|
8
|
+
License: Apache 2.0
|
|
9
|
+
Requires-Python: <4.0,>=3.10
|
|
10
|
+
Requires-Dist: httpx<0.29.0,>=0.28.1
|
|
11
|
+
Requires-Dist: pydantic<3.0,>=2.8
|
|
12
|
+
Requires-Dist: requests<3.0,>=2.32.3
|
|
13
|
+
Requires-Dist: starlette<1.0,>=0.37.0
|
|
14
|
+
Requires-Dist: uagents-core<0.5.0,>=0.4.5
|
|
15
|
+
Provides-Extra: a2a
|
|
16
|
+
Requires-Dist: a2a-sdk<0.4.0,>=0.3.20; extra == 'a2a'
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: pytest-asyncio<1,>=0.24; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest<9,>=8.0; extra == 'dev'
|
|
20
|
+
Requires-Dist: python-dotenv<2.0,>=1.0.0; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff<0.12,>=0.11.0; extra == 'dev'
|
|
22
|
+
Provides-Extra: langgraph
|
|
23
|
+
Requires-Dist: langgraph-api<1.0,>=0.2.0; (python_version >= '3.11') and extra == 'langgraph'
|
|
24
|
+
Requires-Dist: langgraph-cli<1.0,>=0.4.0; (python_version >= '3.11') and extra == 'langgraph'
|
|
25
|
+
Requires-Dist: python-dotenv<2.0,>=1.0.0; (python_version >= '3.11') and extra == 'langgraph'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# agentverse-sdk
|
|
29
|
+
|
|
30
|
+
Connect any AI agent framework to [Agentverse](https://agentverse.ai) with a single `init()` call.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# For A2A agents
|
|
36
|
+
pip install agentverse-sdk[a2a]
|
|
37
|
+
|
|
38
|
+
# For LangGraph agents
|
|
39
|
+
pip install agentverse-sdk[langgraph]
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Quick start
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
from agentverse_sdk.a2a import init
|
|
46
|
+
|
|
47
|
+
init("agentverse://your-agent-key@agentverse.ai/your-agent")
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
See [DEVELOPER.md](DEVELOPER.md) for architecture and adapter implementation guide.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# agentverse-sdk
|
|
2
|
+
|
|
3
|
+
Connect any AI agent framework to [Agentverse](https://agentverse.ai) with a single `init()` call.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# For A2A agents
|
|
9
|
+
pip install agentverse-sdk[a2a]
|
|
10
|
+
|
|
11
|
+
# For LangGraph agents
|
|
12
|
+
pip install agentverse-sdk[langgraph]
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```python
|
|
18
|
+
from agentverse_sdk.a2a import init
|
|
19
|
+
|
|
20
|
+
init("agentverse://your-agent-key@agentverse.ai/your-agent")
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
See [DEVELOPER.md](DEVELOPER.md) for architecture and adapter implementation guide.
|
|
File without changes
|