lians-sdk 0.1.3__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.
- lians_sdk-0.1.3/.gitignore +47 -0
- lians_sdk-0.1.3/PKG-INFO +146 -0
- lians_sdk-0.1.3/README.md +96 -0
- lians_sdk-0.1.3/lians/__init__.py +64 -0
- lians_sdk-0.1.3/lians/autogen_integration.py +287 -0
- lians_sdk-0.1.3/lians/client.py +600 -0
- lians_sdk-0.1.3/lians/crewai_integration.py +212 -0
- lians_sdk-0.1.3/lians/langchain_integration.py +286 -0
- lians_sdk-0.1.3/lians/langgraph_integration.py +263 -0
- lians_sdk-0.1.3/lians/local_client.py +657 -0
- lians_sdk-0.1.3/lians/mcp_server.py +419 -0
- lians_sdk-0.1.3/lians/openai_agents_integration.py +180 -0
- lians_sdk-0.1.3/lians/sync_client.py +429 -0
- lians_sdk-0.1.3/pyproject.toml +48 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
*.egg
|
|
6
|
+
.venv/
|
|
7
|
+
venv/
|
|
8
|
+
env/
|
|
9
|
+
.env
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
*.whl
|
|
13
|
+
|
|
14
|
+
# Test / coverage
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.coverage
|
|
17
|
+
htmlcov/
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.idea/
|
|
21
|
+
.vscode/
|
|
22
|
+
*.sublime-project
|
|
23
|
+
*.sublime-workspace
|
|
24
|
+
|
|
25
|
+
# OS
|
|
26
|
+
.DS_Store
|
|
27
|
+
Thumbs.db
|
|
28
|
+
|
|
29
|
+
# Windows binaries / assemblies
|
|
30
|
+
*.exe
|
|
31
|
+
*.winmd
|
|
32
|
+
*.dll
|
|
33
|
+
*.pdb
|
|
34
|
+
|
|
35
|
+
# Claude Code local settings
|
|
36
|
+
.claude/
|
|
37
|
+
|
|
38
|
+
# Internal working documents (not client-facing)
|
|
39
|
+
SCALE.md
|
|
40
|
+
BUILD.md
|
|
41
|
+
MARKET.md
|
|
42
|
+
|
|
43
|
+
# Personal files
|
|
44
|
+
*.pdf
|
|
45
|
+
|
|
46
|
+
# Node
|
|
47
|
+
node_modules/
|
lians_sdk-0.1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: lians-sdk
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: Financial-grade AI memory — bitemporal facts, SEC 17a-4 audit chain, GDPR crypto-shred
|
|
5
|
+
Project-URL: Homepage, https://github.com/ebeirne/Lians
|
|
6
|
+
Project-URL: Repository, https://github.com/ebeirne/Lians
|
|
7
|
+
Project-URL: Documentation, https://github.com/ebeirne/Lians#readme
|
|
8
|
+
License: Apache-2.0
|
|
9
|
+
Keywords: agents,ai,bitemporal,compliance,crewai,finance,langchain,langgraph,memory
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Intended Audience :: Financial and Insurance Industry
|
|
13
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
19
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
20
|
+
Requires-Python: >=3.10
|
|
21
|
+
Requires-Dist: httpx>=0.25
|
|
22
|
+
Provides-Extra: all
|
|
23
|
+
Requires-Dist: aiosqlite>=0.19; extra == 'all'
|
|
24
|
+
Requires-Dist: autogen-core>=0.4; extra == 'all'
|
|
25
|
+
Requires-Dist: crewai>=0.28; extra == 'all'
|
|
26
|
+
Requires-Dist: httpx>=0.27.0; extra == 'all'
|
|
27
|
+
Requires-Dist: langchain-core>=0.2; extra == 'all'
|
|
28
|
+
Requires-Dist: langgraph>=0.1; extra == 'all'
|
|
29
|
+
Requires-Dist: mcp>=1.0.0; extra == 'all'
|
|
30
|
+
Requires-Dist: openai-agents>=0.0.1; extra == 'all'
|
|
31
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'all'
|
|
32
|
+
Provides-Extra: autogen
|
|
33
|
+
Requires-Dist: autogen-core>=0.4; extra == 'autogen'
|
|
34
|
+
Provides-Extra: crewai
|
|
35
|
+
Requires-Dist: crewai>=0.28; extra == 'crewai'
|
|
36
|
+
Provides-Extra: langchain
|
|
37
|
+
Requires-Dist: langchain-core>=0.2; extra == 'langchain'
|
|
38
|
+
Provides-Extra: langgraph
|
|
39
|
+
Requires-Dist: langchain-core>=0.2; extra == 'langgraph'
|
|
40
|
+
Requires-Dist: langgraph>=0.1; extra == 'langgraph'
|
|
41
|
+
Provides-Extra: local
|
|
42
|
+
Requires-Dist: aiosqlite>=0.19; extra == 'local'
|
|
43
|
+
Requires-Dist: sqlalchemy>=2.0; extra == 'local'
|
|
44
|
+
Provides-Extra: mcp
|
|
45
|
+
Requires-Dist: httpx>=0.27.0; extra == 'mcp'
|
|
46
|
+
Requires-Dist: mcp>=1.0.0; extra == 'mcp'
|
|
47
|
+
Provides-Extra: openai-agents
|
|
48
|
+
Requires-Dist: openai-agents>=0.0.1; extra == 'openai-agents'
|
|
49
|
+
Description-Content-Type: text/markdown
|
|
50
|
+
|
|
51
|
+
# Lians (蓮)
|
|
52
|
+
|
|
53
|
+
**Financial-grade AI memory** — bitemporal facts, SEC 17a-4 audit chain, GDPR crypto-shred.
|
|
54
|
+
|
|
55
|
+
## Install
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install lians-sdk # HTTP client only
|
|
59
|
+
pip install lians-sdk[local] # + zero-setup SQLite mode (no server needed)
|
|
60
|
+
pip install lians-sdk[langchain] # + LangChain chat history & tools
|
|
61
|
+
pip install lians-sdk[langgraph] # + LangGraph node factories
|
|
62
|
+
pip install lians-sdk[crewai] # + CrewAI BaseTool wrappers
|
|
63
|
+
pip install lians-sdk[openai-agents] # + OpenAI Agents SDK tools
|
|
64
|
+
pip install lians-sdk[autogen] # + AutoGen v0.4 tools
|
|
65
|
+
pip install lians-sdk[all] # Everything
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Quickstart
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
from lians import LocalLiansClient
|
|
72
|
+
from datetime import datetime, timezone
|
|
73
|
+
|
|
74
|
+
mem = LocalLiansClient() # no server, no Docker, no API key
|
|
75
|
+
|
|
76
|
+
mem.add(
|
|
77
|
+
agent_id="analyst-1",
|
|
78
|
+
content="NVDA FY2026 revenue guidance raised to $40B",
|
|
79
|
+
event_time=datetime(2025, 11, 19, 16, tzinfo=timezone.utc),
|
|
80
|
+
metadata={"ticker": "NVDA", "metric": "revenue_guidance"},
|
|
81
|
+
importance=0.9,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
# Superseded facts are excluded at the DB layer — LLM never sees stale data
|
|
85
|
+
result = mem.recall(agent_id="analyst-1", query="NVDA revenue guidance")
|
|
86
|
+
|
|
87
|
+
# Point-in-time: what did we know on March 1?
|
|
88
|
+
result = mem.recall_at(
|
|
89
|
+
agent_id="analyst-1",
|
|
90
|
+
query="NVDA revenue guidance",
|
|
91
|
+
as_of=datetime(2025, 3, 1, tzinfo=timezone.utc),
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Extract memories directly from a conversation (like mem0.add(messages=[...]))
|
|
95
|
+
mem.add_from_messages(
|
|
96
|
+
agent_id="analyst-1",
|
|
97
|
+
messages=[
|
|
98
|
+
{"role": "user", "content": "What guidance did NVDA give?"},
|
|
99
|
+
{"role": "assistant", "content": "NVDA raised FY2026 revenue guidance to $40B."},
|
|
100
|
+
],
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## What makes Lians different
|
|
105
|
+
|
|
106
|
+
| Feature | Lians | mem0 | Graphiti/Zep |
|
|
107
|
+
|---------|------|------|-------------|
|
|
108
|
+
| Bitemporal model (event + ingestion time) | ✓ | ✗ | ✓ |
|
|
109
|
+
| Supersession (stale facts excluded at DB layer) | ✓ | ✗ | Partial |
|
|
110
|
+
| SEC 17a-4 tamper-evident audit chain | ✓ | ✗ | ✗ |
|
|
111
|
+
| GDPR crypto-shred with audit survival | ✓ | ✗ | ✗ |
|
|
112
|
+
| Information barriers (PostgreSQL RLS) | ✓ | ✗ | ✗ |
|
|
113
|
+
| Backtest contamination detection | ✓ | ✗ | ✗ |
|
|
114
|
+
|
|
115
|
+
## Framework integrations
|
|
116
|
+
|
|
117
|
+
```python
|
|
118
|
+
# LangChain
|
|
119
|
+
from lians.langchain_integration import LiansChatHistory, build_tools
|
|
120
|
+
|
|
121
|
+
# LangGraph
|
|
122
|
+
from lians.langgraph_integration import create_recall_node, create_remember_node
|
|
123
|
+
|
|
124
|
+
# CrewAI
|
|
125
|
+
from lians.crewai_integration import build_crewai_tools
|
|
126
|
+
|
|
127
|
+
# OpenAI Agents SDK
|
|
128
|
+
from lians.openai_agents_integration import build_openai_agent_tools
|
|
129
|
+
|
|
130
|
+
# AutoGen v0.4
|
|
131
|
+
from lians.autogen_integration import build_autogen_tools
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## Switching to hosted API
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
# Dev (local SQLite, no server)
|
|
138
|
+
from lians import LocalLiansClient
|
|
139
|
+
mem = LocalLiansClient()
|
|
140
|
+
|
|
141
|
+
# Production (self-hosted or managed)
|
|
142
|
+
from lians import LiansClient
|
|
143
|
+
mem = LiansClient(base_url="https://mem.yourfirm.internal", api_key="...")
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Full documentation: [github.com/ebeirne/Lians](https://github.com/ebeirne/Lians)
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Lians (蓮)
|
|
2
|
+
|
|
3
|
+
**Financial-grade AI memory** — bitemporal facts, SEC 17a-4 audit chain, GDPR crypto-shred.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install lians-sdk # HTTP client only
|
|
9
|
+
pip install lians-sdk[local] # + zero-setup SQLite mode (no server needed)
|
|
10
|
+
pip install lians-sdk[langchain] # + LangChain chat history & tools
|
|
11
|
+
pip install lians-sdk[langgraph] # + LangGraph node factories
|
|
12
|
+
pip install lians-sdk[crewai] # + CrewAI BaseTool wrappers
|
|
13
|
+
pip install lians-sdk[openai-agents] # + OpenAI Agents SDK tools
|
|
14
|
+
pip install lians-sdk[autogen] # + AutoGen v0.4 tools
|
|
15
|
+
pip install lians-sdk[all] # Everything
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Quickstart
|
|
19
|
+
|
|
20
|
+
```python
|
|
21
|
+
from lians import LocalLiansClient
|
|
22
|
+
from datetime import datetime, timezone
|
|
23
|
+
|
|
24
|
+
mem = LocalLiansClient() # no server, no Docker, no API key
|
|
25
|
+
|
|
26
|
+
mem.add(
|
|
27
|
+
agent_id="analyst-1",
|
|
28
|
+
content="NVDA FY2026 revenue guidance raised to $40B",
|
|
29
|
+
event_time=datetime(2025, 11, 19, 16, tzinfo=timezone.utc),
|
|
30
|
+
metadata={"ticker": "NVDA", "metric": "revenue_guidance"},
|
|
31
|
+
importance=0.9,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
# Superseded facts are excluded at the DB layer — LLM never sees stale data
|
|
35
|
+
result = mem.recall(agent_id="analyst-1", query="NVDA revenue guidance")
|
|
36
|
+
|
|
37
|
+
# Point-in-time: what did we know on March 1?
|
|
38
|
+
result = mem.recall_at(
|
|
39
|
+
agent_id="analyst-1",
|
|
40
|
+
query="NVDA revenue guidance",
|
|
41
|
+
as_of=datetime(2025, 3, 1, tzinfo=timezone.utc),
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
# Extract memories directly from a conversation (like mem0.add(messages=[...]))
|
|
45
|
+
mem.add_from_messages(
|
|
46
|
+
agent_id="analyst-1",
|
|
47
|
+
messages=[
|
|
48
|
+
{"role": "user", "content": "What guidance did NVDA give?"},
|
|
49
|
+
{"role": "assistant", "content": "NVDA raised FY2026 revenue guidance to $40B."},
|
|
50
|
+
],
|
|
51
|
+
)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## What makes Lians different
|
|
55
|
+
|
|
56
|
+
| Feature | Lians | mem0 | Graphiti/Zep |
|
|
57
|
+
|---------|------|------|-------------|
|
|
58
|
+
| Bitemporal model (event + ingestion time) | ✓ | ✗ | ✓ |
|
|
59
|
+
| Supersession (stale facts excluded at DB layer) | ✓ | ✗ | Partial |
|
|
60
|
+
| SEC 17a-4 tamper-evident audit chain | ✓ | ✗ | ✗ |
|
|
61
|
+
| GDPR crypto-shred with audit survival | ✓ | ✗ | ✗ |
|
|
62
|
+
| Information barriers (PostgreSQL RLS) | ✓ | ✗ | ✗ |
|
|
63
|
+
| Backtest contamination detection | ✓ | ✗ | ✗ |
|
|
64
|
+
|
|
65
|
+
## Framework integrations
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
# LangChain
|
|
69
|
+
from lians.langchain_integration import LiansChatHistory, build_tools
|
|
70
|
+
|
|
71
|
+
# LangGraph
|
|
72
|
+
from lians.langgraph_integration import create_recall_node, create_remember_node
|
|
73
|
+
|
|
74
|
+
# CrewAI
|
|
75
|
+
from lians.crewai_integration import build_crewai_tools
|
|
76
|
+
|
|
77
|
+
# OpenAI Agents SDK
|
|
78
|
+
from lians.openai_agents_integration import build_openai_agent_tools
|
|
79
|
+
|
|
80
|
+
# AutoGen v0.4
|
|
81
|
+
from lians.autogen_integration import build_autogen_tools
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## Switching to hosted API
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
# Dev (local SQLite, no server)
|
|
88
|
+
from lians import LocalLiansClient
|
|
89
|
+
mem = LocalLiansClient()
|
|
90
|
+
|
|
91
|
+
# Production (self-hosted or managed)
|
|
92
|
+
from lians import LiansClient
|
|
93
|
+
mem = LiansClient(base_url="https://mem.yourfirm.internal", api_key="...")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Full documentation: [github.com/ebeirne/Lians](https://github.com/ebeirne/Lians)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Lians Python SDK — financial-grade AI memory with compliance built in.
|
|
3
|
+
|
|
4
|
+
Three clients, same API surface:
|
|
5
|
+
|
|
6
|
+
LiansClient — synchronous HTTP client (scripts, CLIs)
|
|
7
|
+
AsyncLiansClient — async HTTP client (FastAPI, async frameworks)
|
|
8
|
+
LocalLiansClient — zero-setup local SQLite mode (prototyping, CI)
|
|
9
|
+
|
|
10
|
+
Convenience methods on all clients::
|
|
11
|
+
|
|
12
|
+
client.add(agent_id, content, event_time, metadata=...)
|
|
13
|
+
client.add_from_messages(agent_id, messages=[{"role": "assistant", "content": "..."}])
|
|
14
|
+
client.recall(agent_id, query, k=5)
|
|
15
|
+
client.recall_at(agent_id, query, as_of=datetime(...)) # point-in-time / compliance
|
|
16
|
+
client.snapshot(agent_id, as_of=datetime(...)) # full knowledge state at T
|
|
17
|
+
client.backtest_check(agent_id, simulation_as_of=...) # lookahead-bias detection
|
|
18
|
+
client.erase(subject_id, request_ref) # GDPR crypto-shred
|
|
19
|
+
|
|
20
|
+
Framework integrations (optional extras)::
|
|
21
|
+
|
|
22
|
+
# LangChain (chat history + StructuredTools)
|
|
23
|
+
from lians.langchain_integration import LiansChatHistory, build_tools
|
|
24
|
+
|
|
25
|
+
# LangGraph (node factory functions)
|
|
26
|
+
from lians.langgraph_integration import create_recall_node, create_remember_node
|
|
27
|
+
|
|
28
|
+
# CrewAI (BaseTool wrappers)
|
|
29
|
+
from lians.crewai_integration import build_crewai_tools
|
|
30
|
+
|
|
31
|
+
# OpenAI Agents SDK (FunctionTool wrappers)
|
|
32
|
+
from lians.openai_agents_integration import build_openai_agent_tools
|
|
33
|
+
|
|
34
|
+
# AutoGen v0.4 (FunctionTool) / v0.2 (ConversableAgent)
|
|
35
|
+
from lians.autogen_integration import build_autogen_tools, build_autogen_functions
|
|
36
|
+
|
|
37
|
+
Install with extras::
|
|
38
|
+
|
|
39
|
+
pip install lians-sdk[langchain] # LangChain chat history + tools
|
|
40
|
+
pip install lians-sdk[langgraph] # LangGraph node factories
|
|
41
|
+
pip install lians-sdk[crewai] # CrewAI BaseTool wrappers
|
|
42
|
+
pip install lians-sdk[openai-agents] # OpenAI Agents SDK FunctionTools
|
|
43
|
+
pip install lians-sdk[autogen] # AutoGen v0.4 FunctionTools
|
|
44
|
+
pip install lians-sdk[local] # LocalLiansClient (SQLite)
|
|
45
|
+
pip install lians-sdk[all] # Everything
|
|
46
|
+
"""
|
|
47
|
+
from .sync_client import LiansClient
|
|
48
|
+
from .client import AsyncLiansClient
|
|
49
|
+
from .local_client import LocalLiansClient
|
|
50
|
+
|
|
51
|
+
# Backward-compatibility aliases
|
|
52
|
+
AgentMemClient = LiansClient
|
|
53
|
+
AsyncAgentMemClient = AsyncLiansClient
|
|
54
|
+
LocalAgentMemClient = LocalLiansClient
|
|
55
|
+
|
|
56
|
+
__all__ = [
|
|
57
|
+
"LiansClient",
|
|
58
|
+
"AsyncLiansClient",
|
|
59
|
+
"LocalLiansClient",
|
|
60
|
+
# aliases
|
|
61
|
+
"AgentMemClient",
|
|
62
|
+
"AsyncAgentMemClient",
|
|
63
|
+
"LocalAgentMemClient",
|
|
64
|
+
]
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
"""
|
|
2
|
+
AutoGen v0.4 integration for Lians.
|
|
3
|
+
|
|
4
|
+
Provides function tools for AutoGen agents (autogen-agentchat >= 0.4 /
|
|
5
|
+
autogen-core >= 0.4). Works with both the ConversableAgent and the newer
|
|
6
|
+
AssistantAgent + function_tool pattern.
|
|
7
|
+
|
|
8
|
+
Install::
|
|
9
|
+
|
|
10
|
+
pip install lians[autogen]
|
|
11
|
+
# or: pip install autogen-agentchat autogen-core
|
|
12
|
+
|
|
13
|
+
Usage — AssistantAgent with function tools (AutoGen v0.4 async)::
|
|
14
|
+
|
|
15
|
+
from autogen_agentchat.agents import AssistantAgent
|
|
16
|
+
from autogen_ext.models import OpenAIChatCompletionClient
|
|
17
|
+
from lians import AsyncLiansClient
|
|
18
|
+
from lians.autogen_integration import build_autogen_tools
|
|
19
|
+
|
|
20
|
+
client = AsyncLiansClient(base_url="https://mem.firm.internal", api_key="...")
|
|
21
|
+
tools = build_autogen_tools(client, agent_id="equity-desk")
|
|
22
|
+
|
|
23
|
+
model_client = OpenAIChatCompletionClient(model="gpt-4o")
|
|
24
|
+
agent = AssistantAgent(
|
|
25
|
+
name="EquityAnalyst",
|
|
26
|
+
model_client=model_client,
|
|
27
|
+
tools=tools,
|
|
28
|
+
system_message="You are an equity analyst with persistent compliance-grade memory.",
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
Usage — ConversableAgent (AutoGen v0.2 / classic)::
|
|
32
|
+
|
|
33
|
+
from autogen import ConversableAgent
|
|
34
|
+
from lians import LocalLiansClient
|
|
35
|
+
from lians.autogen_integration import build_autogen_functions
|
|
36
|
+
|
|
37
|
+
client = LocalLiansClient()
|
|
38
|
+
functions, function_map = build_autogen_functions(client, agent_id="analyst")
|
|
39
|
+
|
|
40
|
+
agent = ConversableAgent(
|
|
41
|
+
name="analyst",
|
|
42
|
+
functions=functions,
|
|
43
|
+
function_map=function_map,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
Three tools are returned by build_autogen_tools():
|
|
47
|
+
|
|
48
|
+
- ``agentmem_remember`` — store a fact with event timestamp and metadata
|
|
49
|
+
- ``agentmem_recall`` — retrieve current facts by semantic search
|
|
50
|
+
- ``agentmem_recall_at`` — retrieve facts valid at a specific past date (compliance)
|
|
51
|
+
|
|
52
|
+
The ``agentmem_recall_at`` tool supports AutoGen multi-agent compliance workflows:
|
|
53
|
+
"What did the risk-assessment agent know before the trade was placed?" — with a
|
|
54
|
+
tamper-evident SHA-256 audit chain, not a probabilistic reconstruction.
|
|
55
|
+
"""
|
|
56
|
+
from __future__ import annotations
|
|
57
|
+
|
|
58
|
+
import asyncio
|
|
59
|
+
import json
|
|
60
|
+
from datetime import datetime
|
|
61
|
+
from typing import Any
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def build_autogen_tools(client: Any, agent_id: str) -> list:
|
|
65
|
+
"""
|
|
66
|
+
Return three AutoGen v0.4 FunctionTool instances for AssistantAgent.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
client:
|
|
71
|
+
Any Lians client — ``LocalLiansClient``, ``LiansClient``, or
|
|
72
|
+
``AsyncLiansClient``. Async clients are detected automatically.
|
|
73
|
+
agent_id:
|
|
74
|
+
The agent namespace to read/write memories under.
|
|
75
|
+
|
|
76
|
+
Returns
|
|
77
|
+
-------
|
|
78
|
+
List of three AutoGen ``FunctionTool`` instances.
|
|
79
|
+
|
|
80
|
+
Raises
|
|
81
|
+
------
|
|
82
|
+
ImportError
|
|
83
|
+
If ``autogen-core`` is not installed.
|
|
84
|
+
Install with: ``pip install lians[autogen]``
|
|
85
|
+
"""
|
|
86
|
+
try:
|
|
87
|
+
from autogen_core.tools import FunctionTool # type: ignore[import]
|
|
88
|
+
except ImportError:
|
|
89
|
+
raise ImportError(
|
|
90
|
+
"autogen-core is required for AutoGen integration.\n"
|
|
91
|
+
"Install with: pip install lians[autogen]\n"
|
|
92
|
+
"or: pip install autogen-core"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
_is_async = asyncio.iscoroutinefunction(getattr(client, "recall", None))
|
|
96
|
+
|
|
97
|
+
def _fmt(memories: list[dict]) -> str:
|
|
98
|
+
if not memories:
|
|
99
|
+
return "No relevant memories found."
|
|
100
|
+
return "\n".join(
|
|
101
|
+
f"[{(m.get('event_time') or '')[:10]}] {m.get('content') or '[erased]'}"
|
|
102
|
+
for m in memories
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
def _run_maybe_async(coro: Any) -> Any:
|
|
106
|
+
if _is_async:
|
|
107
|
+
return asyncio.get_event_loop().run_until_complete(coro)
|
|
108
|
+
return coro # already a plain value from sync client
|
|
109
|
+
|
|
110
|
+
# ── Tool functions ────────────────────────────────────────────────────────
|
|
111
|
+
|
|
112
|
+
async def agentmem_remember(
|
|
113
|
+
content: str,
|
|
114
|
+
event_time_iso: str,
|
|
115
|
+
metadata_json: str = "{}",
|
|
116
|
+
importance: float = 0.5,
|
|
117
|
+
) -> str:
|
|
118
|
+
"""
|
|
119
|
+
Store a fact in Lians persistent memory.
|
|
120
|
+
|
|
121
|
+
Use event_time_iso for when the event occurred (not now). Add structured
|
|
122
|
+
metadata for precision recall: ticker, metric, entity, source, jurisdiction.
|
|
123
|
+
|
|
124
|
+
Facts are AES-256-GCM encrypted at rest, written to a SHA-256 audit chain,
|
|
125
|
+
and automatically superseded when a newer value for the same entity+attribute
|
|
126
|
+
arrives — so recall always returns the current truth.
|
|
127
|
+
|
|
128
|
+
:param content: The fact or observation to store.
|
|
129
|
+
:param event_time_iso: ISO 8601 timestamp of when the event occurred.
|
|
130
|
+
Example: '2026-05-10T00:00:00Z'
|
|
131
|
+
:param metadata_json: JSON metadata tags.
|
|
132
|
+
Example: '{"ticker": "NVDA", "metric": "guidance"}'
|
|
133
|
+
:param importance: Salience 0.0–1.0. Default 0.5.
|
|
134
|
+
"""
|
|
135
|
+
dt = datetime.fromisoformat(event_time_iso.replace("Z", "+00:00"))
|
|
136
|
+
meta = json.loads(metadata_json) if isinstance(metadata_json, str) else {}
|
|
137
|
+
kwargs: dict[str, Any] = dict(
|
|
138
|
+
agent_id=agent_id,
|
|
139
|
+
content=content,
|
|
140
|
+
event_time=dt,
|
|
141
|
+
metadata=meta,
|
|
142
|
+
importance=importance,
|
|
143
|
+
source="autogen",
|
|
144
|
+
)
|
|
145
|
+
if _is_async:
|
|
146
|
+
await client.add(**kwargs)
|
|
147
|
+
else:
|
|
148
|
+
client.add(**kwargs)
|
|
149
|
+
return f"Stored: {content[:120]}{'…' if len(content) > 120 else ''}"
|
|
150
|
+
|
|
151
|
+
async def agentmem_recall(query: str, k: int = 5) -> str:
|
|
152
|
+
"""
|
|
153
|
+
Retrieve current relevant facts from Lians.
|
|
154
|
+
|
|
155
|
+
Superseded facts are excluded at the DB layer. Only the most recent
|
|
156
|
+
valid value for each fact is returned — your agent never sees stale context.
|
|
157
|
+
|
|
158
|
+
:param query: Natural-language query. Example: 'NVDA guidance FY2026'
|
|
159
|
+
:param k: Number of memories to return (1–20). Default 5.
|
|
160
|
+
"""
|
|
161
|
+
if _is_async:
|
|
162
|
+
result = await client.recall(agent_id=agent_id, query=query, k=k)
|
|
163
|
+
else:
|
|
164
|
+
result = client.recall(agent_id=agent_id, query=query, k=k)
|
|
165
|
+
return _fmt(result.get("memories", []))
|
|
166
|
+
|
|
167
|
+
async def agentmem_recall_at(query: str, as_of_iso: str, k: int = 5) -> str:
|
|
168
|
+
"""
|
|
169
|
+
Retrieve facts valid at a specific point in time (compliance/audit path).
|
|
170
|
+
|
|
171
|
+
Returns the exact knowledge state at the given timestamp — supports
|
|
172
|
+
out-of-order ingestion correctly. Use in multi-agent workflows where one
|
|
173
|
+
agent must reconstruct what another agent knew before a decision.
|
|
174
|
+
|
|
175
|
+
:param query: Natural-language query.
|
|
176
|
+
:param as_of_iso: ISO 8601 timestamp. Only facts valid at this moment
|
|
177
|
+
are returned. Example: '2026-03-01T00:00:00Z'
|
|
178
|
+
:param k: Number of memories to return (1–20). Default 5.
|
|
179
|
+
"""
|
|
180
|
+
as_of = datetime.fromisoformat(as_of_iso.replace("Z", "+00:00"))
|
|
181
|
+
if _is_async:
|
|
182
|
+
result = await client.recall(agent_id=agent_id, query=query, k=k, as_of=as_of)
|
|
183
|
+
else:
|
|
184
|
+
result = client.recall(agent_id=agent_id, query=query, k=k, as_of=as_of)
|
|
185
|
+
return f"Facts valid as of {as_of_iso[:10]}:\n{_fmt(result.get('memories', []))}"
|
|
186
|
+
|
|
187
|
+
return [
|
|
188
|
+
FunctionTool(agentmem_remember, description=agentmem_remember.__doc__ or ""),
|
|
189
|
+
FunctionTool(agentmem_recall, description=agentmem_recall.__doc__ or ""),
|
|
190
|
+
FunctionTool(agentmem_recall_at, description=agentmem_recall_at.__doc__ or ""),
|
|
191
|
+
]
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
def build_autogen_functions(
|
|
195
|
+
client: Any,
|
|
196
|
+
agent_id: str,
|
|
197
|
+
) -> tuple[list[dict], dict[str, Any]]:
|
|
198
|
+
"""
|
|
199
|
+
Return (functions_schema, function_map) for AutoGen v0.2 ConversableAgent.
|
|
200
|
+
|
|
201
|
+
The functions_schema list goes into the ``functions`` parameter; the
|
|
202
|
+
function_map dict goes into ``function_map``.
|
|
203
|
+
|
|
204
|
+
Parameters
|
|
205
|
+
----------
|
|
206
|
+
client:
|
|
207
|
+
Any synchronous Lians client (LocalLiansClient or LiansClient).
|
|
208
|
+
agent_id:
|
|
209
|
+
The agent namespace to read/write memories under.
|
|
210
|
+
|
|
211
|
+
Returns
|
|
212
|
+
-------
|
|
213
|
+
A (list, dict) tuple compatible with ConversableAgent's ``functions`` and
|
|
214
|
+
``function_map`` parameters.
|
|
215
|
+
"""
|
|
216
|
+
def _fmt(memories: list[dict]) -> str:
|
|
217
|
+
if not memories:
|
|
218
|
+
return "No relevant memories found."
|
|
219
|
+
return "\n".join(
|
|
220
|
+
f"[{(m.get('event_time') or '')[:10]}] {m.get('content') or '[erased]'}"
|
|
221
|
+
for m in memories
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def _remember(content: str, event_time_iso: str, metadata_json: str = "{}", importance: float = 0.5) -> str:
|
|
225
|
+
dt = datetime.fromisoformat(event_time_iso.replace("Z", "+00:00"))
|
|
226
|
+
meta = json.loads(metadata_json) if isinstance(metadata_json, str) else {}
|
|
227
|
+
client.add(agent_id=agent_id, content=content, event_time=dt, metadata=meta, importance=importance, source="autogen_v2")
|
|
228
|
+
return f"Stored: {content[:120]}"
|
|
229
|
+
|
|
230
|
+
def _recall(query: str, k: int = 5) -> str:
|
|
231
|
+
result = client.recall(agent_id=agent_id, query=query, k=k)
|
|
232
|
+
return _fmt(result.get("memories", []))
|
|
233
|
+
|
|
234
|
+
def _recall_at(query: str, as_of_iso: str, k: int = 5) -> str:
|
|
235
|
+
as_of = datetime.fromisoformat(as_of_iso.replace("Z", "+00:00"))
|
|
236
|
+
result = client.recall(agent_id=agent_id, query=query, k=k, as_of=as_of)
|
|
237
|
+
return f"Facts valid as of {as_of_iso[:10]}:\n{_fmt(result.get('memories', []))}"
|
|
238
|
+
|
|
239
|
+
functions = [
|
|
240
|
+
{
|
|
241
|
+
"name": "agentmem_remember",
|
|
242
|
+
"description": "Store a fact with its event timestamp in Lians persistent memory.",
|
|
243
|
+
"parameters": {
|
|
244
|
+
"type": "object",
|
|
245
|
+
"properties": {
|
|
246
|
+
"content": {"type": "string", "description": "The fact to remember."},
|
|
247
|
+
"event_time_iso": {"type": "string", "description": "ISO 8601 event timestamp."},
|
|
248
|
+
"metadata_json": {"type": "string", "description": "JSON metadata tags.", "default": "{}"},
|
|
249
|
+
"importance": {"type": "number", "description": "Salience 0–1.", "default": 0.5},
|
|
250
|
+
},
|
|
251
|
+
"required": ["content", "event_time_iso"],
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
"name": "agentmem_recall",
|
|
256
|
+
"description": "Retrieve current relevant facts from Lians (superseded facts excluded).",
|
|
257
|
+
"parameters": {
|
|
258
|
+
"type": "object",
|
|
259
|
+
"properties": {
|
|
260
|
+
"query": {"type": "string"},
|
|
261
|
+
"k": {"type": "integer", "default": 5},
|
|
262
|
+
},
|
|
263
|
+
"required": ["query"],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
{
|
|
267
|
+
"name": "agentmem_recall_at",
|
|
268
|
+
"description": "Retrieve facts valid at a specific timestamp (compliance / audit path).",
|
|
269
|
+
"parameters": {
|
|
270
|
+
"type": "object",
|
|
271
|
+
"properties": {
|
|
272
|
+
"query": {"type": "string"},
|
|
273
|
+
"as_of_iso": {"type": "string", "description": "ISO 8601 timestamp."},
|
|
274
|
+
"k": {"type": "integer", "default": 5},
|
|
275
|
+
},
|
|
276
|
+
"required": ["query", "as_of_iso"],
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
]
|
|
280
|
+
|
|
281
|
+
function_map = {
|
|
282
|
+
"agentmem_remember": _remember,
|
|
283
|
+
"agentmem_recall": _recall,
|
|
284
|
+
"agentmem_recall_at": _recall_at,
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
return functions, function_map
|