xproof 0.2.2__tar.gz → 0.2.4__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.
- {xproof-0.2.2 → xproof-0.2.4}/PKG-INFO +3 -1
- {xproof-0.2.2 → xproof-0.2.4}/pyproject.toml +4 -1
- {xproof-0.2.2 → xproof-0.2.4}/xproof/__init__.py +1 -1
- {xproof-0.2.2 → xproof-0.2.4}/xproof/client.py +30 -1
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/__init__.py +5 -0
- xproof-0.2.4/xproof/integrations/fetchai.py +398 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof.egg-info/PKG-INFO +3 -1
- {xproof-0.2.2 → xproof-0.2.4}/xproof.egg-info/SOURCES.txt +1 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof.egg-info/requires.txt +3 -0
- {xproof-0.2.2 → xproof-0.2.4}/LICENSE +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/README.md +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/setup.cfg +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/tests/test_client.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/tests/test_integration.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/exceptions.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/autogen.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/crewai.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/deerflow.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/langchain.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/llamaindex.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/integrations/openai_agents.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/models.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/py.typed +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof/utils.py +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof.egg-info/dependency_links.txt +0 -0
- {xproof-0.2.2 → xproof-0.2.4}/xproof.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xproof
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Python SDK for xProof — blockchain-anchored proof-of-existence for AI agents on MultiversX
|
|
5
5
|
Author-email: xProof <contact@xproof.app>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -37,6 +37,8 @@ Requires-Dist: pyautogen>=0.2.0; extra == "autogen"
|
|
|
37
37
|
Provides-Extra: openai-agents
|
|
38
38
|
Requires-Dist: openai-agents>=0.0.3; extra == "openai-agents"
|
|
39
39
|
Provides-Extra: deerflow
|
|
40
|
+
Provides-Extra: fetchai
|
|
41
|
+
Requires-Dist: uagents>=0.9.0; extra == "fetchai"
|
|
40
42
|
Dynamic: license-file
|
|
41
43
|
|
|
42
44
|
# xproof
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "xproof"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.4"
|
|
8
8
|
description = "Python SDK for xProof — blockchain-anchored proof-of-existence for AI agents on MultiversX"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -50,6 +50,9 @@ openai-agents = [
|
|
|
50
50
|
"openai-agents>=0.0.3",
|
|
51
51
|
]
|
|
52
52
|
deerflow = []
|
|
53
|
+
fetchai = [
|
|
54
|
+
"uagents>=0.9.0",
|
|
55
|
+
]
|
|
53
56
|
|
|
54
57
|
[project.urls]
|
|
55
58
|
Homepage = "https://xproof.app"
|
|
@@ -17,7 +17,7 @@ from .exceptions import (
|
|
|
17
17
|
from .models import BatchResult, Certification, PricingInfo, RegistrationResult
|
|
18
18
|
from .utils import hash_file
|
|
19
19
|
|
|
20
|
-
__version__ = "0.
|
|
20
|
+
__version__ = "0.2.4"
|
|
21
21
|
|
|
22
22
|
DEFAULT_BASE_URL = "https://xproof.app"
|
|
23
23
|
DEFAULT_TIMEOUT = 30
|
|
@@ -378,6 +378,35 @@ class XProofClient:
|
|
|
378
378
|
)
|
|
379
379
|
return data
|
|
380
380
|
|
|
381
|
+
def get_context_drift(self, decision_id: str) -> Dict[str, Any]:
|
|
382
|
+
"""Detect execution context drift across a decision chain.
|
|
383
|
+
|
|
384
|
+
Compares ``model_hash``, ``tools_version``, ``strategy_snapshot``, and
|
|
385
|
+
``operator_scope`` between consecutive proofs in the chain. Returns a
|
|
386
|
+
coherence score and per-stage breakdown of which fields changed.
|
|
387
|
+
|
|
388
|
+
Args:
|
|
389
|
+
decision_id: The shared identifier linking proofs in the chain.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
A dictionary with:
|
|
393
|
+
|
|
394
|
+
- ``context_coherent`` (bool): True if no drift was detected.
|
|
395
|
+
- ``drift_score`` (float): 0.0 = fully coherent, 1.0 = total drift.
|
|
396
|
+
- ``fields_drifted`` (list[str]): Fields that changed at least once.
|
|
397
|
+
- ``fields_stable`` (list[str]): Fields present in all stages and unchanged.
|
|
398
|
+
- ``fields_absent`` (list[str]): Fields never populated in any stage.
|
|
399
|
+
- ``stages`` (list[dict]): Per-stage context with ``context_break``
|
|
400
|
+
and ``drifted_fields`` flags.
|
|
401
|
+
"""
|
|
402
|
+
from urllib.parse import quote
|
|
403
|
+
data = self._request(
|
|
404
|
+
"GET",
|
|
405
|
+
f"/api/context-drift/{quote(decision_id, safe='')}",
|
|
406
|
+
auth_required=False,
|
|
407
|
+
)
|
|
408
|
+
return data
|
|
409
|
+
|
|
381
410
|
def batch_certify(
|
|
382
411
|
self,
|
|
383
412
|
files: List[Dict[str, Any]],
|
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
"""Fetch.ai uAgents integration for automatic xProof certification.
|
|
2
|
+
|
|
3
|
+
Wraps uAgent message handlers and interval tasks to anchor the 4W audit
|
|
4
|
+
trail (Who, What, When, Why) on MultiversX mainnet before and after every
|
|
5
|
+
agent action — without modifying application logic.
|
|
6
|
+
|
|
7
|
+
Quickstart::
|
|
8
|
+
|
|
9
|
+
from uagents import Agent, Context
|
|
10
|
+
from xproof.integrations.fetchai import xproof_handler, XProofuAgentMiddleware
|
|
11
|
+
|
|
12
|
+
agent = Agent(name="research-agent", seed="my-seed")
|
|
13
|
+
middleware = XProofuAgentMiddleware(api_key="pm_...", agent_name="research-agent")
|
|
14
|
+
|
|
15
|
+
@agent.on_message(model=QueryMessage)
|
|
16
|
+
@xproof_handler(middleware)
|
|
17
|
+
async def handle_query(ctx: Context, sender: str, msg: QueryMessage):
|
|
18
|
+
response = await do_research(msg.query)
|
|
19
|
+
await ctx.send(sender, ResponseMessage(result=response))
|
|
20
|
+
|
|
21
|
+
Compatible with uAgents >= 0.9.x.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
import functools
|
|
25
|
+
import hashlib
|
|
26
|
+
import json
|
|
27
|
+
import uuid
|
|
28
|
+
from datetime import datetime, timezone
|
|
29
|
+
from typing import Any, Callable, Dict, List, Optional
|
|
30
|
+
|
|
31
|
+
from ..client import XProofClient
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _hash_data(data: Any) -> str:
|
|
35
|
+
"""Stable SHA-256 of any JSON-serialisable value."""
|
|
36
|
+
serialized = json.dumps(data, sort_keys=True, default=str)
|
|
37
|
+
return hashlib.sha256(serialized.encode()).hexdigest()
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _now_iso() -> str:
|
|
41
|
+
return datetime.now(timezone.utc).isoformat()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class XProofuAgentMiddleware:
|
|
45
|
+
"""Central xProof certification middleware for a uAgent.
|
|
46
|
+
|
|
47
|
+
Instantiate once per agent, then pass it to :func:`xproof_handler`
|
|
48
|
+
or call :meth:`certify_incoming` / :meth:`certify_outgoing` directly.
|
|
49
|
+
|
|
50
|
+
Args:
|
|
51
|
+
api_key: xProof API key (``pm_...``). Ignored when *client* is given.
|
|
52
|
+
client: Pre-configured :class:`~xproof.client.XProofClient`.
|
|
53
|
+
agent_name: Used as WHO in the 4W metadata. Defaults to ``"uagent"``.
|
|
54
|
+
certify_incoming: Certify the incoming message (the WHY). Default ``True``.
|
|
55
|
+
certify_outgoing: Certify the outgoing response (the WHAT). Default ``True``.
|
|
56
|
+
batch_mode: Buffer certifications and flush with :meth:`flush`. Default ``False``.
|
|
57
|
+
|
|
58
|
+
Example::
|
|
59
|
+
|
|
60
|
+
from xproof.integrations.fetchai import XProofuAgentMiddleware
|
|
61
|
+
|
|
62
|
+
middleware = XProofuAgentMiddleware(
|
|
63
|
+
api_key="pm_...",
|
|
64
|
+
agent_name="trading-agent",
|
|
65
|
+
)
|
|
66
|
+
proof = middleware.certify_incoming(
|
|
67
|
+
message={"query": "What is the BTC price?"},
|
|
68
|
+
sender="agent1abcd",
|
|
69
|
+
context="Market data query",
|
|
70
|
+
)
|
|
71
|
+
print(proof["proof_id"])
|
|
72
|
+
"""
|
|
73
|
+
|
|
74
|
+
def __init__(
|
|
75
|
+
self,
|
|
76
|
+
api_key: str = "",
|
|
77
|
+
client: Optional[XProofClient] = None,
|
|
78
|
+
agent_name: str = "uagent",
|
|
79
|
+
certify_incoming: bool = True,
|
|
80
|
+
certify_outgoing: bool = True,
|
|
81
|
+
batch_mode: bool = False,
|
|
82
|
+
) -> None:
|
|
83
|
+
self.client = client or XProofClient(api_key=api_key)
|
|
84
|
+
self.agent_name = agent_name
|
|
85
|
+
self.certify_incoming = certify_incoming
|
|
86
|
+
self.certify_outgoing = certify_outgoing
|
|
87
|
+
self.batch_mode = batch_mode
|
|
88
|
+
self._pending: List[Dict[str, Any]] = []
|
|
89
|
+
|
|
90
|
+
def _certify(
|
|
91
|
+
self,
|
|
92
|
+
file_hash: str,
|
|
93
|
+
file_name: str,
|
|
94
|
+
action_type: str,
|
|
95
|
+
context: str,
|
|
96
|
+
extra_metadata: Optional[Dict[str, Any]] = None,
|
|
97
|
+
decision_id: Optional[str] = None,
|
|
98
|
+
) -> Optional[Dict[str, Any]]:
|
|
99
|
+
metadata: Dict[str, Any] = {
|
|
100
|
+
"who": self.agent_name,
|
|
101
|
+
"what": file_hash,
|
|
102
|
+
"when": _now_iso(),
|
|
103
|
+
"why": context,
|
|
104
|
+
"action_type": action_type,
|
|
105
|
+
"framework": "fetchai-uagents",
|
|
106
|
+
}
|
|
107
|
+
if decision_id:
|
|
108
|
+
metadata["decision_id"] = decision_id
|
|
109
|
+
if extra_metadata:
|
|
110
|
+
metadata.update(extra_metadata)
|
|
111
|
+
|
|
112
|
+
entry = {
|
|
113
|
+
"file_hash": file_hash,
|
|
114
|
+
"file_name": file_name,
|
|
115
|
+
"author": self.agent_name,
|
|
116
|
+
"metadata": metadata,
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if self.batch_mode:
|
|
120
|
+
self._pending.append(entry)
|
|
121
|
+
return {"queued": True, "file_hash": file_hash}
|
|
122
|
+
|
|
123
|
+
cert = self.client.certify_hash(
|
|
124
|
+
file_hash=file_hash,
|
|
125
|
+
file_name=file_name,
|
|
126
|
+
author=self.agent_name,
|
|
127
|
+
metadata=metadata,
|
|
128
|
+
)
|
|
129
|
+
return {
|
|
130
|
+
"proof_id": cert.id,
|
|
131
|
+
"file_hash": cert.file_hash,
|
|
132
|
+
"transaction_hash": cert.transaction_hash,
|
|
133
|
+
"verify_url": f"https://xproof.app/proof/{cert.id}",
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
def certify_incoming(
|
|
137
|
+
self,
|
|
138
|
+
message: Any,
|
|
139
|
+
sender: str = "unknown",
|
|
140
|
+
context: str = "Incoming uAgent message",
|
|
141
|
+
decision_id: Optional[str] = None,
|
|
142
|
+
) -> Optional[Dict[str, Any]]:
|
|
143
|
+
"""Certify an incoming message as WHY (trigger / justification).
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
message: The incoming message object or dict.
|
|
147
|
+
sender: Sender address for traceability metadata.
|
|
148
|
+
context: Human-readable description of the trigger.
|
|
149
|
+
decision_id: Shared ID linking this WHY to its WHAT pair.
|
|
150
|
+
|
|
151
|
+
Returns:
|
|
152
|
+
Dict with ``proof_id``, ``file_hash``, ``transaction_hash``,
|
|
153
|
+
``verify_url``; or ``None`` if *certify_incoming* is disabled.
|
|
154
|
+
"""
|
|
155
|
+
if not self.certify_incoming:
|
|
156
|
+
return None
|
|
157
|
+
|
|
158
|
+
msg_dict = (
|
|
159
|
+
message.__dict__ if hasattr(message, "__dict__") else
|
|
160
|
+
{"content": str(message)}
|
|
161
|
+
)
|
|
162
|
+
msg_hash = _hash_data({"sender": sender, "message": msg_dict})
|
|
163
|
+
|
|
164
|
+
return self._certify(
|
|
165
|
+
file_hash=msg_hash,
|
|
166
|
+
file_name=f"incoming-{self.agent_name}-{msg_hash[:8]}.json",
|
|
167
|
+
action_type="message_received",
|
|
168
|
+
context=context,
|
|
169
|
+
extra_metadata={"sender": sender},
|
|
170
|
+
decision_id=decision_id,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def certify_outgoing(
|
|
174
|
+
self,
|
|
175
|
+
response: Any,
|
|
176
|
+
recipient: str = "unknown",
|
|
177
|
+
context: str = "uAgent response",
|
|
178
|
+
decision_id: Optional[str] = None,
|
|
179
|
+
confidence_level: Optional[float] = None,
|
|
180
|
+
) -> Optional[Dict[str, Any]]:
|
|
181
|
+
"""Certify an outgoing response as WHAT (the output to prove).
|
|
182
|
+
|
|
183
|
+
Args:
|
|
184
|
+
response: The response object or dict to hash and certify.
|
|
185
|
+
recipient: Destination address for traceability metadata.
|
|
186
|
+
context: Human-readable description of the output.
|
|
187
|
+
decision_id: Shared ID linking this WHAT to its WHY pair.
|
|
188
|
+
confidence_level: Optional float 0.0-1.0 (agent self-reported confidence).
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
Dict with ``proof_id``, ``file_hash``, ``transaction_hash``,
|
|
192
|
+
``verify_url``; or ``None`` if *certify_outgoing* is disabled.
|
|
193
|
+
"""
|
|
194
|
+
if not self.certify_outgoing:
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
resp_dict = (
|
|
198
|
+
response.__dict__ if hasattr(response, "__dict__") else
|
|
199
|
+
{"content": str(response)}
|
|
200
|
+
)
|
|
201
|
+
resp_hash = _hash_data({"recipient": recipient, "response": resp_dict})
|
|
202
|
+
|
|
203
|
+
extra: Dict[str, Any] = {"recipient": recipient}
|
|
204
|
+
if confidence_level is not None:
|
|
205
|
+
extra["confidence_level"] = float(confidence_level)
|
|
206
|
+
|
|
207
|
+
return self._certify(
|
|
208
|
+
file_hash=resp_hash,
|
|
209
|
+
file_name=f"outgoing-{self.agent_name}-{resp_hash[:8]}.json",
|
|
210
|
+
action_type="message_sent",
|
|
211
|
+
context=context,
|
|
212
|
+
extra_metadata=extra,
|
|
213
|
+
decision_id=decision_id,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
def certify_action(
|
|
217
|
+
self,
|
|
218
|
+
action_name: str,
|
|
219
|
+
inputs: Any,
|
|
220
|
+
outputs: Any,
|
|
221
|
+
why: str = "",
|
|
222
|
+
confidence_level: Optional[float] = None,
|
|
223
|
+
) -> Dict[str, Any]:
|
|
224
|
+
"""Certify a complete agent action as a WHY+WHAT pair.
|
|
225
|
+
|
|
226
|
+
Creates two linked proofs sharing a ``decision_id`` — the canonical
|
|
227
|
+
xProof dual-certification pattern for verifiable agent accountability.
|
|
228
|
+
|
|
229
|
+
Args:
|
|
230
|
+
action_name: Descriptive name of the action (used in file names).
|
|
231
|
+
inputs: Input data / trigger (hashed as WHY).
|
|
232
|
+
outputs: Output data / result (hashed as WHAT).
|
|
233
|
+
why: Human-readable mandate or justification.
|
|
234
|
+
confidence_level: Optional float 0.0-1.0.
|
|
235
|
+
|
|
236
|
+
Returns:
|
|
237
|
+
Dict with ``decision_id``, ``why_proof`` and ``what_proof`` dicts.
|
|
238
|
+
|
|
239
|
+
Example::
|
|
240
|
+
|
|
241
|
+
result = middleware.certify_action(
|
|
242
|
+
action_name="price-lookup",
|
|
243
|
+
inputs={"query": "BTC/USDT"},
|
|
244
|
+
outputs={"price": 67800.0},
|
|
245
|
+
why="Market price requested by trading strategy",
|
|
246
|
+
confidence_level=0.95,
|
|
247
|
+
)
|
|
248
|
+
print(result["why_proof"]["proof_id"])
|
|
249
|
+
print(result["what_proof"]["proof_id"])
|
|
250
|
+
"""
|
|
251
|
+
decision_id = str(uuid.uuid4())
|
|
252
|
+
inputs_hash = _hash_data(inputs)
|
|
253
|
+
outputs_hash = _hash_data(outputs)
|
|
254
|
+
|
|
255
|
+
why_extra: Dict[str, Any] = {"action_name": action_name}
|
|
256
|
+
if confidence_level is not None:
|
|
257
|
+
why_extra["confidence_level"] = float(confidence_level)
|
|
258
|
+
|
|
259
|
+
why_proof = self._certify(
|
|
260
|
+
file_hash=inputs_hash,
|
|
261
|
+
file_name=f"why-{action_name}-{inputs_hash[:8]}.json",
|
|
262
|
+
action_type="decision",
|
|
263
|
+
context=why or f"Reasoning before {action_name}",
|
|
264
|
+
extra_metadata=why_extra,
|
|
265
|
+
decision_id=decision_id,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
what_proof = self._certify(
|
|
269
|
+
file_hash=outputs_hash,
|
|
270
|
+
file_name=f"what-{action_name}-{outputs_hash[:8]}.json",
|
|
271
|
+
action_type="output",
|
|
272
|
+
context=f"Output of {action_name}",
|
|
273
|
+
extra_metadata={"action_name": action_name},
|
|
274
|
+
decision_id=decision_id,
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
return {
|
|
278
|
+
"decision_id": decision_id,
|
|
279
|
+
"why_proof": why_proof,
|
|
280
|
+
"what_proof": what_proof,
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
def flush(self) -> Optional[Dict[str, Any]]:
|
|
284
|
+
"""Send all pending certifications in a single batch.
|
|
285
|
+
|
|
286
|
+
Only relevant when *batch_mode* is ``True``.
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
The batch API response dict, or ``None`` if the queue was empty.
|
|
290
|
+
"""
|
|
291
|
+
if not self._pending:
|
|
292
|
+
return None
|
|
293
|
+
result = self.client.batch_certify(self._pending)
|
|
294
|
+
self._pending.clear()
|
|
295
|
+
return result
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
def xproof_handler(
|
|
299
|
+
middleware: XProofuAgentMiddleware,
|
|
300
|
+
incoming_context: str = "Incoming uAgent message",
|
|
301
|
+
outgoing_context: str = "uAgent response",
|
|
302
|
+
) -> Callable:
|
|
303
|
+
"""Decorator that wraps a uAgent ``on_message`` handler with xProof certification.
|
|
304
|
+
|
|
305
|
+
Certifies the incoming message (WHY) before the handler runs, then
|
|
306
|
+
certifies the response (WHAT) if the handler returns a value.
|
|
307
|
+
|
|
308
|
+
Both proofs share a ``decision_id`` so the full reasoning chain is
|
|
309
|
+
verifiable on-chain.
|
|
310
|
+
|
|
311
|
+
Args:
|
|
312
|
+
middleware: A configured :class:`XProofuAgentMiddleware` instance.
|
|
313
|
+
incoming_context: Description attached to the WHY proof.
|
|
314
|
+
outgoing_context: Description attached to the WHAT proof.
|
|
315
|
+
|
|
316
|
+
Example::
|
|
317
|
+
|
|
318
|
+
from uagents import Agent, Context
|
|
319
|
+
from xproof.integrations.fetchai import XProofuAgentMiddleware, xproof_handler
|
|
320
|
+
|
|
321
|
+
agent = Agent(name="research-agent", seed="test-seed")
|
|
322
|
+
xp = XProofuAgentMiddleware(api_key="pm_...", agent_name="research-agent")
|
|
323
|
+
|
|
324
|
+
@agent.on_message(model=Query)
|
|
325
|
+
@xproof_handler(xp, incoming_context="Research query received")
|
|
326
|
+
async def handle_query(ctx: Context, sender: str, msg: Query):
|
|
327
|
+
result = await run_research(msg.topic)
|
|
328
|
+
return result # returned value is certified as WHAT
|
|
329
|
+
"""
|
|
330
|
+
def decorator(fn: Callable) -> Callable:
|
|
331
|
+
@functools.wraps(fn)
|
|
332
|
+
async def wrapper(ctx: Any, sender: str, msg: Any) -> Any:
|
|
333
|
+
decision_id = str(uuid.uuid4())
|
|
334
|
+
|
|
335
|
+
middleware.certify_incoming(
|
|
336
|
+
message=msg,
|
|
337
|
+
sender=sender,
|
|
338
|
+
context=incoming_context,
|
|
339
|
+
decision_id=decision_id,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
result = await fn(ctx, sender, msg)
|
|
343
|
+
|
|
344
|
+
if result is not None:
|
|
345
|
+
middleware.certify_outgoing(
|
|
346
|
+
response=result,
|
|
347
|
+
recipient=sender,
|
|
348
|
+
context=outgoing_context,
|
|
349
|
+
decision_id=decision_id,
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
return result
|
|
353
|
+
return wrapper
|
|
354
|
+
return decorator
|
|
355
|
+
|
|
356
|
+
|
|
357
|
+
def wrap_agent(
|
|
358
|
+
agent: Any,
|
|
359
|
+
api_key: str = "",
|
|
360
|
+
client: Optional[XProofClient] = None,
|
|
361
|
+
agent_name: Optional[str] = None,
|
|
362
|
+
certify_incoming: bool = True,
|
|
363
|
+
certify_outgoing: bool = True,
|
|
364
|
+
batch_mode: bool = False,
|
|
365
|
+
) -> "XProofuAgentMiddleware":
|
|
366
|
+
"""Convenience function — creates middleware bound to a uAgent instance.
|
|
367
|
+
|
|
368
|
+
Reads ``agent.name`` automatically so you don't have to specify it.
|
|
369
|
+
|
|
370
|
+
Args:
|
|
371
|
+
agent: A uAgents ``Agent`` instance.
|
|
372
|
+
api_key: xProof API key. Ignored when *client* is provided.
|
|
373
|
+
client: Pre-configured :class:`~xproof.client.XProofClient`.
|
|
374
|
+
agent_name: Override the name used in 4W metadata.
|
|
375
|
+
certify_incoming: Certify incoming messages. Default ``True``.
|
|
376
|
+
certify_outgoing: Certify outgoing responses. Default ``True``.
|
|
377
|
+
batch_mode: Buffer certifications for batch sending. Default ``False``.
|
|
378
|
+
|
|
379
|
+
Returns:
|
|
380
|
+
A ready-to-use :class:`XProofuAgentMiddleware` instance.
|
|
381
|
+
|
|
382
|
+
Example::
|
|
383
|
+
|
|
384
|
+
from uagents import Agent
|
|
385
|
+
from xproof.integrations.fetchai import wrap_agent
|
|
386
|
+
|
|
387
|
+
agent = Agent(name="price-oracle", seed="secret")
|
|
388
|
+
xp = wrap_agent(agent, api_key="pm_...")
|
|
389
|
+
"""
|
|
390
|
+
name = agent_name or getattr(agent, "name", "uagent")
|
|
391
|
+
return XProofuAgentMiddleware(
|
|
392
|
+
api_key=api_key,
|
|
393
|
+
client=client,
|
|
394
|
+
agent_name=name,
|
|
395
|
+
certify_incoming=certify_incoming,
|
|
396
|
+
certify_outgoing=certify_outgoing,
|
|
397
|
+
batch_mode=batch_mode,
|
|
398
|
+
)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xproof
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.4
|
|
4
4
|
Summary: Python SDK for xProof — blockchain-anchored proof-of-existence for AI agents on MultiversX
|
|
5
5
|
Author-email: xProof <contact@xproof.app>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -37,6 +37,8 @@ Requires-Dist: pyautogen>=0.2.0; extra == "autogen"
|
|
|
37
37
|
Provides-Extra: openai-agents
|
|
38
38
|
Requires-Dist: openai-agents>=0.0.3; extra == "openai-agents"
|
|
39
39
|
Provides-Extra: deerflow
|
|
40
|
+
Provides-Extra: fetchai
|
|
41
|
+
Requires-Dist: uagents>=0.9.0; extra == "fetchai"
|
|
40
42
|
Dynamic: license-file
|
|
41
43
|
|
|
42
44
|
# xproof
|
|
@@ -18,6 +18,7 @@ xproof/integrations/__init__.py
|
|
|
18
18
|
xproof/integrations/autogen.py
|
|
19
19
|
xproof/integrations/crewai.py
|
|
20
20
|
xproof/integrations/deerflow.py
|
|
21
|
+
xproof/integrations/fetchai.py
|
|
21
22
|
xproof/integrations/langchain.py
|
|
22
23
|
xproof/integrations/llamaindex.py
|
|
23
24
|
xproof/integrations/openai_agents.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|