openclaw-xache 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openclaw_xache-0.1.0.dist-info/METADATA +384 -0
- openclaw_xache-0.1.0.dist-info/RECORD +9 -0
- openclaw_xache-0.1.0.dist-info/WHEEL +5 -0
- openclaw_xache-0.1.0.dist-info/top_level.txt +1 -0
- xache_openclaw/__init__.py +106 -0
- xache_openclaw/_async_utils.py +55 -0
- xache_openclaw/config.py +124 -0
- xache_openclaw/extraction.py +532 -0
- xache_openclaw/tools.py +667 -0
xache_openclaw/tools.py
ADDED
|
@@ -0,0 +1,667 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Xache Tools for OpenClaw
|
|
3
|
+
Collective intelligence, verifiable memory, and portable reputation
|
|
4
|
+
|
|
5
|
+
OpenClaw already has excellent local persistent memory. These tools add:
|
|
6
|
+
- Collective intelligence (share/query insights across agents)
|
|
7
|
+
- Verifiable memory (cryptographic receipts)
|
|
8
|
+
- Portable reputation (ERC-8004)
|
|
9
|
+
- Cross-instance sync
|
|
10
|
+
- Task receipts for agent-to-agent work
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
import os
|
|
14
|
+
from typing import List, Optional, Dict, Any, Callable
|
|
15
|
+
from dataclasses import dataclass
|
|
16
|
+
|
|
17
|
+
from xache import XacheClient
|
|
18
|
+
|
|
19
|
+
from .config import get_config, XacheConfig
|
|
20
|
+
from ._async_utils import run_sync
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
# Global client cache
|
|
24
|
+
_client_cache: Dict[str, XacheClient] = {}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def create_xache_client(config: Optional[XacheConfig] = None) -> XacheClient:
|
|
28
|
+
"""
|
|
29
|
+
Create or retrieve a cached Xache client.
|
|
30
|
+
|
|
31
|
+
Args:
|
|
32
|
+
config: Optional config override. Uses global config if not provided.
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
XacheClient instance
|
|
36
|
+
"""
|
|
37
|
+
cfg = config or get_config()
|
|
38
|
+
|
|
39
|
+
if not cfg.is_valid():
|
|
40
|
+
raise ValueError(
|
|
41
|
+
"Xache not configured. Set XACHE_WALLET_ADDRESS and XACHE_PRIVATE_KEY "
|
|
42
|
+
"environment variables, or call set_config() first."
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
cache_key = f"{cfg.wallet_address}:{cfg.api_url}:{cfg.chain}"
|
|
46
|
+
|
|
47
|
+
if cache_key not in _client_cache:
|
|
48
|
+
_client_cache[cache_key] = XacheClient(
|
|
49
|
+
api_url=cfg.api_url,
|
|
50
|
+
did=cfg.did,
|
|
51
|
+
private_key=cfg.private_key,
|
|
52
|
+
timeout=cfg.timeout,
|
|
53
|
+
debug=cfg.debug,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
return _client_cache[cache_key]
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
# =============================================================================
|
|
60
|
+
# Standalone Tool Functions
|
|
61
|
+
# These can be used directly or wrapped in OpenClaw's @tool decorator
|
|
62
|
+
# =============================================================================
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def collective_contribute(
|
|
66
|
+
insight: str,
|
|
67
|
+
domain: str,
|
|
68
|
+
evidence: Optional[str] = None,
|
|
69
|
+
tags: Optional[List[str]] = None,
|
|
70
|
+
config: Optional[XacheConfig] = None,
|
|
71
|
+
) -> Dict[str, Any]:
|
|
72
|
+
"""
|
|
73
|
+
Contribute an insight to the collective intelligence pool.
|
|
74
|
+
|
|
75
|
+
Use when you discover something valuable that could help other agents.
|
|
76
|
+
Quality contributions earn reputation.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
insight: The insight or pattern to share
|
|
80
|
+
domain: Domain/topic (e.g., 'coding', 'research', 'analysis')
|
|
81
|
+
evidence: Optional supporting evidence
|
|
82
|
+
tags: Optional categorization tags
|
|
83
|
+
config: Optional config override
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dict with heuristicId, receiptId, and contribution details
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
```python
|
|
90
|
+
from xache_openclaw import collective_contribute
|
|
91
|
+
|
|
92
|
+
result = collective_contribute(
|
|
93
|
+
insight="Rate limiting APIs with exponential backoff prevents 429 errors",
|
|
94
|
+
domain="api-integration",
|
|
95
|
+
evidence="Reduced errors by 95% in production deployments",
|
|
96
|
+
tags=["api", "best-practices"]
|
|
97
|
+
)
|
|
98
|
+
print(f"Contributed: {result['heuristicId']}")
|
|
99
|
+
```
|
|
100
|
+
"""
|
|
101
|
+
client = create_xache_client(config)
|
|
102
|
+
|
|
103
|
+
async def _contribute():
|
|
104
|
+
async with client as c:
|
|
105
|
+
return await c.collective.contribute(
|
|
106
|
+
domain=domain,
|
|
107
|
+
pattern=insight,
|
|
108
|
+
evidence=evidence,
|
|
109
|
+
tags=tags or [],
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
return run_sync(_contribute())
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def collective_query(
|
|
116
|
+
query: str,
|
|
117
|
+
domain: Optional[str] = None,
|
|
118
|
+
limit: int = 5,
|
|
119
|
+
config: Optional[XacheConfig] = None,
|
|
120
|
+
) -> Dict[str, Any]:
|
|
121
|
+
"""
|
|
122
|
+
Query the collective intelligence pool for insights.
|
|
123
|
+
|
|
124
|
+
Learn from knowledge contributed by other agents.
|
|
125
|
+
|
|
126
|
+
Args:
|
|
127
|
+
query: What to search for
|
|
128
|
+
domain: Optional domain filter
|
|
129
|
+
limit: Max results (default 5)
|
|
130
|
+
config: Optional config override
|
|
131
|
+
|
|
132
|
+
Returns:
|
|
133
|
+
Dict with results list containing patterns, domains, and scores
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
```python
|
|
137
|
+
from xache_openclaw import collective_query
|
|
138
|
+
|
|
139
|
+
results = collective_query(
|
|
140
|
+
query="best practices for handling API errors",
|
|
141
|
+
domain="api-integration",
|
|
142
|
+
limit=3
|
|
143
|
+
)
|
|
144
|
+
for item in results.get('results', []):
|
|
145
|
+
print(f"- {item['pattern']}")
|
|
146
|
+
```
|
|
147
|
+
"""
|
|
148
|
+
client = create_xache_client(config)
|
|
149
|
+
|
|
150
|
+
async def _query():
|
|
151
|
+
async with client as c:
|
|
152
|
+
return await c.collective.query(
|
|
153
|
+
query=query,
|
|
154
|
+
domain=domain,
|
|
155
|
+
limit=limit,
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
return run_sync(_query())
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def memory_store(
|
|
162
|
+
content: str,
|
|
163
|
+
context: str,
|
|
164
|
+
tags: Optional[List[str]] = None,
|
|
165
|
+
config: Optional[XacheConfig] = None,
|
|
166
|
+
) -> Dict[str, Any]:
|
|
167
|
+
"""
|
|
168
|
+
Store a memory to Xache with verifiable receipt.
|
|
169
|
+
|
|
170
|
+
Use for important information that needs:
|
|
171
|
+
- Cryptographic proof of storage
|
|
172
|
+
- Cross-device/instance access
|
|
173
|
+
- Long-term durability
|
|
174
|
+
|
|
175
|
+
Note: OpenClaw already has local memory. Use this for memories that
|
|
176
|
+
need to be verifiable or shared across instances.
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
content: The content to store
|
|
180
|
+
context: Context/category for organization
|
|
181
|
+
tags: Optional tags for filtering
|
|
182
|
+
config: Optional config override
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
Dict with memoryId and receiptId
|
|
186
|
+
|
|
187
|
+
Example:
|
|
188
|
+
```python
|
|
189
|
+
from xache_openclaw import memory_store
|
|
190
|
+
|
|
191
|
+
result = memory_store(
|
|
192
|
+
content="User prefers formal communication style",
|
|
193
|
+
context="user-preferences",
|
|
194
|
+
tags=["preferences", "communication"]
|
|
195
|
+
)
|
|
196
|
+
print(f"Stored with receipt: {result['receiptId']}")
|
|
197
|
+
```
|
|
198
|
+
"""
|
|
199
|
+
client = create_xache_client(config)
|
|
200
|
+
|
|
201
|
+
async def _store():
|
|
202
|
+
async with client as c:
|
|
203
|
+
return await c.memory.store(
|
|
204
|
+
content=content,
|
|
205
|
+
context=context,
|
|
206
|
+
tags=tags or [],
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
return run_sync(_store())
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
def memory_retrieve(
|
|
213
|
+
query: str,
|
|
214
|
+
context: Optional[str] = None,
|
|
215
|
+
limit: int = 5,
|
|
216
|
+
config: Optional[XacheConfig] = None,
|
|
217
|
+
) -> Dict[str, Any]:
|
|
218
|
+
"""
|
|
219
|
+
Retrieve memories from Xache storage.
|
|
220
|
+
|
|
221
|
+
Args:
|
|
222
|
+
query: Semantic search query
|
|
223
|
+
context: Optional context filter
|
|
224
|
+
limit: Max results (default 5)
|
|
225
|
+
config: Optional config override
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
Dict with memories list
|
|
229
|
+
|
|
230
|
+
Example:
|
|
231
|
+
```python
|
|
232
|
+
from xache_openclaw import memory_retrieve
|
|
233
|
+
|
|
234
|
+
results = memory_retrieve(
|
|
235
|
+
query="user communication preferences",
|
|
236
|
+
context="user-preferences"
|
|
237
|
+
)
|
|
238
|
+
for mem in results.get('memories', []):
|
|
239
|
+
print(f"- {mem['content'][:100]}...")
|
|
240
|
+
```
|
|
241
|
+
"""
|
|
242
|
+
client = create_xache_client(config)
|
|
243
|
+
|
|
244
|
+
async def _retrieve():
|
|
245
|
+
async with client as c:
|
|
246
|
+
return await c.memory.retrieve(
|
|
247
|
+
query=query,
|
|
248
|
+
context=context,
|
|
249
|
+
limit=limit,
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
return run_sync(_retrieve())
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def check_reputation(config: Optional[XacheConfig] = None) -> Dict[str, Any]:
|
|
256
|
+
"""
|
|
257
|
+
Check your agent's reputation score and ERC-8004 status.
|
|
258
|
+
|
|
259
|
+
Higher reputation means lower costs and more trust from other agents.
|
|
260
|
+
|
|
261
|
+
Args:
|
|
262
|
+
config: Optional config override
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
Dict with score, level, and ERC-8004 status
|
|
266
|
+
|
|
267
|
+
Example:
|
|
268
|
+
```python
|
|
269
|
+
from xache_openclaw import check_reputation
|
|
270
|
+
|
|
271
|
+
rep = check_reputation()
|
|
272
|
+
print(f"Score: {rep['score']:.2f} ({rep['level']})")
|
|
273
|
+
if rep.get('erc8004_enabled'):
|
|
274
|
+
print(f"ERC-8004 Agent ID: {rep['erc8004_agent_id']}")
|
|
275
|
+
```
|
|
276
|
+
"""
|
|
277
|
+
client = create_xache_client(config)
|
|
278
|
+
|
|
279
|
+
async def _check():
|
|
280
|
+
async with client as c:
|
|
281
|
+
return await c.reputation.get_score()
|
|
282
|
+
|
|
283
|
+
result = run_sync(_check())
|
|
284
|
+
|
|
285
|
+
score = result.get("score", 0)
|
|
286
|
+
level = _get_reputation_level(score)
|
|
287
|
+
|
|
288
|
+
return {
|
|
289
|
+
"score": score,
|
|
290
|
+
"level": level,
|
|
291
|
+
"erc8004_enabled": bool(result.get("erc8004AgentId")),
|
|
292
|
+
"erc8004_agent_id": result.get("erc8004AgentId"),
|
|
293
|
+
"raw": result,
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
def sync_to_xache(
|
|
298
|
+
content: str,
|
|
299
|
+
source: str = "openclaw",
|
|
300
|
+
importance: str = "normal",
|
|
301
|
+
tags: Optional[List[str]] = None,
|
|
302
|
+
config: Optional[XacheConfig] = None,
|
|
303
|
+
) -> Dict[str, Any]:
|
|
304
|
+
"""
|
|
305
|
+
Sync important local memories to Xache for durability and verification.
|
|
306
|
+
|
|
307
|
+
OpenClaw stores memories locally in markdown files. Use this to:
|
|
308
|
+
- Backup critical memories to decentralized storage
|
|
309
|
+
- Get cryptographic receipts for important learnings
|
|
310
|
+
- Share memories across OpenClaw instances
|
|
311
|
+
|
|
312
|
+
Args:
|
|
313
|
+
content: The memory content to sync
|
|
314
|
+
source: Source identifier (default 'openclaw')
|
|
315
|
+
importance: 'critical', 'high', 'normal', 'low'
|
|
316
|
+
tags: Optional tags
|
|
317
|
+
config: Optional config override
|
|
318
|
+
|
|
319
|
+
Returns:
|
|
320
|
+
Dict with memoryId, receiptId, and verification info
|
|
321
|
+
|
|
322
|
+
Example:
|
|
323
|
+
```python
|
|
324
|
+
from xache_openclaw import sync_to_xache
|
|
325
|
+
|
|
326
|
+
# Sync a critical learning
|
|
327
|
+
result = sync_to_xache(
|
|
328
|
+
content="Discovered that user's database uses PostgreSQL 14",
|
|
329
|
+
source="openclaw-research",
|
|
330
|
+
importance="high",
|
|
331
|
+
tags=["database", "user-context"]
|
|
332
|
+
)
|
|
333
|
+
```
|
|
334
|
+
"""
|
|
335
|
+
context = f"{source}:{importance}"
|
|
336
|
+
all_tags = list(tags or [])
|
|
337
|
+
all_tags.extend([source, f"importance:{importance}"])
|
|
338
|
+
|
|
339
|
+
return memory_store(
|
|
340
|
+
content=content,
|
|
341
|
+
context=context,
|
|
342
|
+
tags=all_tags,
|
|
343
|
+
config=config,
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
def _get_reputation_level(score: float) -> str:
|
|
348
|
+
"""Convert numeric score to level name"""
|
|
349
|
+
if score >= 0.9:
|
|
350
|
+
return "Elite"
|
|
351
|
+
elif score >= 0.7:
|
|
352
|
+
return "Trusted"
|
|
353
|
+
elif score >= 0.5:
|
|
354
|
+
return "Established"
|
|
355
|
+
elif score >= 0.3:
|
|
356
|
+
return "Developing"
|
|
357
|
+
return "New"
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
# =============================================================================
|
|
361
|
+
# Tool Classes for OpenClaw Registration
|
|
362
|
+
# These wrap the functions above in a class interface that OpenClaw can use
|
|
363
|
+
# =============================================================================
|
|
364
|
+
|
|
365
|
+
|
|
366
|
+
@dataclass
|
|
367
|
+
class XacheCollectiveContributeTool:
|
|
368
|
+
"""
|
|
369
|
+
OpenClaw tool for contributing to collective intelligence.
|
|
370
|
+
|
|
371
|
+
Example:
|
|
372
|
+
```python
|
|
373
|
+
tool = XacheCollectiveContributeTool()
|
|
374
|
+
result = tool.run(
|
|
375
|
+
insight="API endpoints should use versioning",
|
|
376
|
+
domain="api-design"
|
|
377
|
+
)
|
|
378
|
+
```
|
|
379
|
+
"""
|
|
380
|
+
name: str = "xache_collective_contribute"
|
|
381
|
+
description: str = (
|
|
382
|
+
"Contribute an insight to the collective intelligence pool. "
|
|
383
|
+
"Use when you discover something valuable that could help other agents. "
|
|
384
|
+
"Quality contributions earn reputation."
|
|
385
|
+
)
|
|
386
|
+
|
|
387
|
+
def run(
|
|
388
|
+
self,
|
|
389
|
+
insight: str,
|
|
390
|
+
domain: str,
|
|
391
|
+
evidence: Optional[str] = None,
|
|
392
|
+
tags: Optional[List[str]] = None,
|
|
393
|
+
) -> str:
|
|
394
|
+
result = collective_contribute(insight, domain, evidence, tags)
|
|
395
|
+
heuristic_id = result.get("heuristicId", "unknown")
|
|
396
|
+
return f"Contributed insight to '{domain}'. Heuristic ID: {heuristic_id}"
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
@dataclass
|
|
400
|
+
class XacheCollectiveQueryTool:
|
|
401
|
+
"""
|
|
402
|
+
OpenClaw tool for querying collective intelligence.
|
|
403
|
+
|
|
404
|
+
Example:
|
|
405
|
+
```python
|
|
406
|
+
tool = XacheCollectiveQueryTool()
|
|
407
|
+
result = tool.run(query="best practices for error handling")
|
|
408
|
+
```
|
|
409
|
+
"""
|
|
410
|
+
name: str = "xache_collective_query"
|
|
411
|
+
description: str = (
|
|
412
|
+
"Query the collective intelligence pool for insights from other agents. "
|
|
413
|
+
"Use when you need knowledge from the community."
|
|
414
|
+
)
|
|
415
|
+
|
|
416
|
+
def run(
|
|
417
|
+
self,
|
|
418
|
+
query: str,
|
|
419
|
+
domain: Optional[str] = None,
|
|
420
|
+
limit: int = 5,
|
|
421
|
+
) -> str:
|
|
422
|
+
result = collective_query(query, domain, limit)
|
|
423
|
+
results = result.get("results", [])
|
|
424
|
+
|
|
425
|
+
if not results:
|
|
426
|
+
return "No relevant insights found in the collective."
|
|
427
|
+
|
|
428
|
+
output = f"Found {len(results)} insights:\n"
|
|
429
|
+
for i, item in enumerate(results, 1):
|
|
430
|
+
pattern = item.get("pattern", "")[:200]
|
|
431
|
+
output += f"\n{i}. {pattern}"
|
|
432
|
+
if item.get("domain"):
|
|
433
|
+
output += f" [Domain: {item['domain']}]"
|
|
434
|
+
|
|
435
|
+
return output
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
@dataclass
|
|
439
|
+
class XacheMemoryStoreTool:
|
|
440
|
+
"""
|
|
441
|
+
OpenClaw tool for storing verifiable memories.
|
|
442
|
+
|
|
443
|
+
Example:
|
|
444
|
+
```python
|
|
445
|
+
tool = XacheMemoryStoreTool()
|
|
446
|
+
result = tool.run(
|
|
447
|
+
content="Important user preference",
|
|
448
|
+
context="preferences"
|
|
449
|
+
)
|
|
450
|
+
```
|
|
451
|
+
"""
|
|
452
|
+
name: str = "xache_memory_store"
|
|
453
|
+
description: str = (
|
|
454
|
+
"Store a memory with cryptographic receipt. "
|
|
455
|
+
"Use for important information that needs verification or cross-instance access."
|
|
456
|
+
)
|
|
457
|
+
|
|
458
|
+
def run(
|
|
459
|
+
self,
|
|
460
|
+
content: str,
|
|
461
|
+
context: str,
|
|
462
|
+
tags: Optional[List[str]] = None,
|
|
463
|
+
) -> str:
|
|
464
|
+
result = memory_store(content, context, tags)
|
|
465
|
+
memory_id = result.get("memoryId", "unknown")
|
|
466
|
+
receipt_id = result.get("receiptId", "unknown")
|
|
467
|
+
return f"Stored memory '{context}'. ID: {memory_id}, Receipt: {receipt_id}"
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
@dataclass
|
|
471
|
+
class XacheMemoryRetrieveTool:
|
|
472
|
+
"""
|
|
473
|
+
OpenClaw tool for retrieving memories.
|
|
474
|
+
|
|
475
|
+
Example:
|
|
476
|
+
```python
|
|
477
|
+
tool = XacheMemoryRetrieveTool()
|
|
478
|
+
result = tool.run(query="user preferences")
|
|
479
|
+
```
|
|
480
|
+
"""
|
|
481
|
+
name: str = "xache_memory_retrieve"
|
|
482
|
+
description: str = (
|
|
483
|
+
"Retrieve memories from Xache by semantic search. "
|
|
484
|
+
"Use to recall information from verifiable storage."
|
|
485
|
+
)
|
|
486
|
+
|
|
487
|
+
def run(
|
|
488
|
+
self,
|
|
489
|
+
query: str,
|
|
490
|
+
context: Optional[str] = None,
|
|
491
|
+
limit: int = 5,
|
|
492
|
+
) -> str:
|
|
493
|
+
result = memory_retrieve(query, context, limit)
|
|
494
|
+
memories = result.get("memories", [])
|
|
495
|
+
|
|
496
|
+
if not memories:
|
|
497
|
+
return "No relevant memories found."
|
|
498
|
+
|
|
499
|
+
output = f"Found {len(memories)} memories:\n"
|
|
500
|
+
for i, m in enumerate(memories, 1):
|
|
501
|
+
content = m.get("content", "")[:200]
|
|
502
|
+
output += f"\n{i}. {content}"
|
|
503
|
+
if m.get("context"):
|
|
504
|
+
output += f" [Context: {m['context']}]"
|
|
505
|
+
|
|
506
|
+
return output
|
|
507
|
+
|
|
508
|
+
|
|
509
|
+
@dataclass
|
|
510
|
+
class XacheReputationTool:
|
|
511
|
+
"""
|
|
512
|
+
OpenClaw tool for checking reputation.
|
|
513
|
+
|
|
514
|
+
Example:
|
|
515
|
+
```python
|
|
516
|
+
tool = XacheReputationTool()
|
|
517
|
+
result = tool.run()
|
|
518
|
+
```
|
|
519
|
+
"""
|
|
520
|
+
name: str = "xache_check_reputation"
|
|
521
|
+
description: str = (
|
|
522
|
+
"Check your current reputation score and ERC-8004 status. "
|
|
523
|
+
"Higher reputation means lower costs and more trust."
|
|
524
|
+
)
|
|
525
|
+
|
|
526
|
+
def run(self) -> str:
|
|
527
|
+
result = check_reputation()
|
|
528
|
+
output = f"Reputation Score: {result['score']:.2f}/1.00 ({result['level']})\n"
|
|
529
|
+
|
|
530
|
+
if result.get("erc8004_enabled"):
|
|
531
|
+
output += f"ERC-8004: Enabled (Agent ID: {result['erc8004_agent_id']})"
|
|
532
|
+
else:
|
|
533
|
+
output += "ERC-8004: Not enabled"
|
|
534
|
+
|
|
535
|
+
return output
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
@dataclass
|
|
539
|
+
class XacheSyncTool:
|
|
540
|
+
"""
|
|
541
|
+
OpenClaw tool for syncing local memories to Xache.
|
|
542
|
+
|
|
543
|
+
Example:
|
|
544
|
+
```python
|
|
545
|
+
tool = XacheSyncTool()
|
|
546
|
+
result = tool.run(
|
|
547
|
+
content="Critical learning about user's system",
|
|
548
|
+
importance="high"
|
|
549
|
+
)
|
|
550
|
+
```
|
|
551
|
+
"""
|
|
552
|
+
name: str = "xache_sync"
|
|
553
|
+
description: str = (
|
|
554
|
+
"Sync important local memories to Xache for durability and verification. "
|
|
555
|
+
"Use for critical information that needs cryptographic proof or cross-instance access."
|
|
556
|
+
)
|
|
557
|
+
|
|
558
|
+
def run(
|
|
559
|
+
self,
|
|
560
|
+
content: str,
|
|
561
|
+
importance: str = "normal",
|
|
562
|
+
tags: Optional[List[str]] = None,
|
|
563
|
+
) -> str:
|
|
564
|
+
result = sync_to_xache(content, "openclaw", importance, tags)
|
|
565
|
+
memory_id = result.get("memoryId", "unknown")
|
|
566
|
+
receipt_id = result.get("receiptId", "unknown")
|
|
567
|
+
return f"Synced to Xache. ID: {memory_id}, Receipt: {receipt_id}"
|
|
568
|
+
|
|
569
|
+
|
|
570
|
+
# =============================================================================
|
|
571
|
+
# Tool Factory
|
|
572
|
+
# =============================================================================
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
def xache_tools(
|
|
576
|
+
wallet_address: Optional[str] = None,
|
|
577
|
+
private_key: Optional[str] = None,
|
|
578
|
+
include_memory: bool = False, # Off by default - OpenClaw has local memory
|
|
579
|
+
include_collective: bool = True,
|
|
580
|
+
include_reputation: bool = True,
|
|
581
|
+
include_sync: bool = True,
|
|
582
|
+
include_extraction: bool = False, # Requires LLM
|
|
583
|
+
llm: Optional[Callable[[str], str]] = None, # Required for extraction
|
|
584
|
+
) -> List:
|
|
585
|
+
"""
|
|
586
|
+
Create a set of Xache tools for OpenClaw.
|
|
587
|
+
|
|
588
|
+
By default includes:
|
|
589
|
+
- Collective intelligence (contribute/query)
|
|
590
|
+
- Reputation checking
|
|
591
|
+
- Sync tool (backup local memories to Xache)
|
|
592
|
+
|
|
593
|
+
Memory tools are off by default since OpenClaw has excellent local memory.
|
|
594
|
+
Enable if you need verifiable receipts or cross-instance access.
|
|
595
|
+
|
|
596
|
+
Extraction tool requires an LLM function to analyze conversations.
|
|
597
|
+
|
|
598
|
+
Args:
|
|
599
|
+
wallet_address: Wallet address (uses env var if not provided)
|
|
600
|
+
private_key: Private key (uses env var if not provided)
|
|
601
|
+
include_memory: Include memory store/retrieve tools (default: False)
|
|
602
|
+
include_collective: Include collective tools (default: True)
|
|
603
|
+
include_reputation: Include reputation tool (default: True)
|
|
604
|
+
include_sync: Include sync tool (default: True)
|
|
605
|
+
include_extraction: Include extraction tool (default: False, requires llm)
|
|
606
|
+
llm: LLM function for extraction - takes prompt string, returns response
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
List of tool instances
|
|
610
|
+
|
|
611
|
+
Example:
|
|
612
|
+
```python
|
|
613
|
+
from xache_openclaw import xache_tools, set_config
|
|
614
|
+
|
|
615
|
+
# Option 1: Set config first
|
|
616
|
+
set_config(wallet_address="0x...", private_key="0x...")
|
|
617
|
+
tools = xache_tools()
|
|
618
|
+
|
|
619
|
+
# Option 2: Pass credentials directly
|
|
620
|
+
tools = xache_tools(
|
|
621
|
+
wallet_address="0x...",
|
|
622
|
+
private_key="0x..."
|
|
623
|
+
)
|
|
624
|
+
|
|
625
|
+
# Option 3: With extraction (requires LLM)
|
|
626
|
+
tools = xache_tools(
|
|
627
|
+
wallet_address="0x...",
|
|
628
|
+
private_key="0x...",
|
|
629
|
+
include_extraction=True,
|
|
630
|
+
llm=lambda p: my_llm.complete(p)
|
|
631
|
+
)
|
|
632
|
+
```
|
|
633
|
+
"""
|
|
634
|
+
from .config import set_config as _set_config
|
|
635
|
+
|
|
636
|
+
# Update config if credentials provided
|
|
637
|
+
if wallet_address or private_key:
|
|
638
|
+
_set_config(
|
|
639
|
+
wallet_address=wallet_address,
|
|
640
|
+
private_key=private_key,
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
tools = []
|
|
644
|
+
|
|
645
|
+
if include_collective:
|
|
646
|
+
tools.extend([
|
|
647
|
+
XacheCollectiveContributeTool(),
|
|
648
|
+
XacheCollectiveQueryTool(),
|
|
649
|
+
])
|
|
650
|
+
|
|
651
|
+
if include_memory:
|
|
652
|
+
tools.extend([
|
|
653
|
+
XacheMemoryStoreTool(),
|
|
654
|
+
XacheMemoryRetrieveTool(),
|
|
655
|
+
])
|
|
656
|
+
|
|
657
|
+
if include_reputation:
|
|
658
|
+
tools.append(XacheReputationTool())
|
|
659
|
+
|
|
660
|
+
if include_sync:
|
|
661
|
+
tools.append(XacheSyncTool())
|
|
662
|
+
|
|
663
|
+
if include_extraction:
|
|
664
|
+
from .extraction import XacheExtractionTool
|
|
665
|
+
tools.append(XacheExtractionTool(llm=llm))
|
|
666
|
+
|
|
667
|
+
return tools
|