vouchstone-sdk 1.0.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.
@@ -0,0 +1,20 @@
1
+ """Vouchstone Python SDK - Build AI Agents with Long-Term Memory"""
2
+
3
+ from .client import VouchstoneClient
4
+ from .agent import Agent, AgentConfig
5
+ from .memory import SemanticMemory, EpisodicMemory, ProceduralMemory, DecisionGraph
6
+ from .types import Message, Decision, MemoryEntry
7
+
8
+ __version__ = "1.0.0"
9
+ __all__ = [
10
+ "VouchstoneClient",
11
+ "Agent",
12
+ "AgentConfig",
13
+ "SemanticMemory",
14
+ "EpisodicMemory",
15
+ "ProceduralMemory",
16
+ "DecisionGraph",
17
+ "Message",
18
+ "Decision",
19
+ "MemoryEntry",
20
+ ]
@@ -0,0 +1,156 @@
1
+ """Agent Base Class with Memory Integration"""
2
+
3
+ from typing import Optional, Dict, Any, List, Callable
4
+ from dataclasses import dataclass, field
5
+ from abc import ABC, abstractmethod
6
+ import asyncio
7
+
8
+ from .memory import SemanticMemory, EpisodicMemory, ProceduralMemory, DecisionGraph
9
+ from .types import Message, AgentResponse
10
+
11
+ @dataclass
12
+ class AgentConfig:
13
+ """Configuration for an Vouchstone Agent"""
14
+ name: str
15
+ model: str = "gpt-4-turbo-preview"
16
+ temperature: float = 0.7
17
+ max_tokens: int = 4096
18
+ system_prompt: Optional[str] = None
19
+
20
+ # Memory configuration
21
+ semantic_memory: bool = True
22
+ episodic_memory: bool = True
23
+ procedural_memory: bool = True
24
+ decision_graph: bool = True
25
+
26
+ # Memory settings
27
+ embedding_model: str = "text-embedding-3-small"
28
+ memory_retention_days: int = 90
29
+
30
+ # Additional config
31
+ tools: List[Dict[str, Any]] = field(default_factory=list)
32
+ metadata: Dict[str, Any] = field(default_factory=dict)
33
+
34
+
35
+ class Agent(ABC):
36
+ """Base class for Vouchstone Agents with Long-Term Memory"""
37
+
38
+ def __init__(self, config: AgentConfig):
39
+ self.config = config
40
+ self.semantic_memory: Optional[SemanticMemory] = None
41
+ self.episodic_memory: Optional[EpisodicMemory] = None
42
+ self.procedural_memory: Optional[ProceduralMemory] = None
43
+ self.decision_graph: Optional[DecisionGraph] = None
44
+
45
+ self._tools: Dict[str, Callable] = {}
46
+ self._initialized = False
47
+
48
+ async def initialize(
49
+ self,
50
+ vector_db_url: Optional[str] = None,
51
+ graph_db_url: Optional[str] = None
52
+ ):
53
+ """Initialize memory systems"""
54
+ if self.config.semantic_memory:
55
+ self.semantic_memory = SemanticMemory(
56
+ embedding_model=self.config.embedding_model,
57
+ vector_db_url=vector_db_url
58
+ )
59
+ await self.semantic_memory.initialize()
60
+
61
+ if self.config.episodic_memory:
62
+ self.episodic_memory = EpisodicMemory(
63
+ retention_days=self.config.memory_retention_days
64
+ )
65
+ await self.episodic_memory.initialize()
66
+
67
+ if self.config.procedural_memory:
68
+ self.procedural_memory = ProceduralMemory()
69
+ await self.procedural_memory.initialize()
70
+
71
+ if self.config.decision_graph:
72
+ self.decision_graph = DecisionGraph(graph_db_url=graph_db_url)
73
+ await self.decision_graph.initialize()
74
+
75
+ self._initialized = True
76
+
77
+ def register_tool(self, name: str, func: Callable, description: str):
78
+ """Register a tool for the agent to use"""
79
+ self._tools[name] = func
80
+ self.config.tools.append({
81
+ "type": "function",
82
+ "function": {
83
+ "name": name,
84
+ "description": description,
85
+ "parameters": {"type": "object", "properties": {}}
86
+ }
87
+ })
88
+
89
+ async def process(self, message: Message) -> AgentResponse:
90
+ """Process a message and return response"""
91
+ if not self._initialized:
92
+ raise RuntimeError("Agent not initialized. Call initialize() first.")
93
+
94
+ # Retrieve relevant memories
95
+ context = await self._build_context(message)
96
+
97
+ # Run the agent logic
98
+ response = await self.run(message, context)
99
+
100
+ # Store in episodic memory
101
+ if self.episodic_memory:
102
+ await self.episodic_memory.store(message, response)
103
+
104
+ # Update decision graph if enabled
105
+ if self.decision_graph and response.decisions:
106
+ for decision in response.decisions:
107
+ await self.decision_graph.record_decision(decision)
108
+
109
+ return response
110
+
111
+ async def _build_context(self, message: Message) -> Dict[str, Any]:
112
+ """Build context from memory systems"""
113
+ context = {}
114
+
115
+ if self.semantic_memory:
116
+ relevant_docs = await self.semantic_memory.search(
117
+ message.content,
118
+ top_k=5
119
+ )
120
+ context["semantic"] = relevant_docs
121
+
122
+ if self.episodic_memory:
123
+ recent_episodes = await self.episodic_memory.get_recent(
124
+ limit=10
125
+ )
126
+ context["episodic"] = recent_episodes
127
+
128
+ if self.procedural_memory:
129
+ relevant_procedures = await self.procedural_memory.get_relevant(
130
+ message.content
131
+ )
132
+ context["procedural"] = relevant_procedures
133
+
134
+ if self.decision_graph:
135
+ decision_context = await self.decision_graph.get_context(
136
+ message.content
137
+ )
138
+ context["decision_graph"] = decision_context
139
+
140
+ return context
141
+
142
+ @abstractmethod
143
+ async def run(self, message: Message, context: Dict[str, Any]) -> AgentResponse:
144
+ """Implement agent logic - must be overridden"""
145
+ pass
146
+
147
+ async def close(self):
148
+ """Cleanup resources"""
149
+ if self.semantic_memory:
150
+ await self.semantic_memory.close()
151
+ if self.episodic_memory:
152
+ await self.episodic_memory.close()
153
+ if self.procedural_memory:
154
+ await self.procedural_memory.close()
155
+ if self.decision_graph:
156
+ await self.decision_graph.close()
@@ -0,0 +1,126 @@
1
+ """Vouchstone SDK Client - Connection to Control Plane"""
2
+
3
+ import httpx
4
+ from typing import Optional, Dict, Any, List
5
+ from .types import AgentDefinition
6
+
7
+ class VouchstoneClient:
8
+ """Client for communicating with Vouchstone Control Plane"""
9
+
10
+ def __init__(
11
+ self,
12
+ api_key: str,
13
+ control_plane_url: str = "https://api.vouchstone.ai",
14
+ tenant_id: Optional[str] = None
15
+ ):
16
+ self.api_key = api_key
17
+ self.base_url = control_plane_url.rstrip("/")
18
+ self.tenant_id = tenant_id
19
+ self._client = httpx.AsyncClient(
20
+ base_url=self.base_url,
21
+ headers={
22
+ "Authorization": f"Bearer {api_key}",
23
+ "X-Tenant-ID": tenant_id or "",
24
+ },
25
+ timeout=30.0
26
+ )
27
+
28
+ async def get_agent(self, agent_id: str) -> AgentDefinition:
29
+ """Fetch agent definition from control plane"""
30
+ response = await self._client.get(f"/api/v1/agents/{agent_id}")
31
+ response.raise_for_status()
32
+ return AgentDefinition(**response.json())
33
+
34
+ async def list_agents(self) -> List[AgentDefinition]:
35
+ """List all agents for tenant"""
36
+ response = await self._client.get("/api/v1/agents")
37
+ response.raise_for_status()
38
+ return [AgentDefinition(**a) for a in response.json()["agents"]]
39
+
40
+ async def report_metrics(self, metrics: Dict[str, Any]) -> None:
41
+ """Report metrics back to control plane"""
42
+ await self._client.post("/api/v1/webhooks/data-plane/metrics", json=metrics)
43
+
44
+ async def report_status(self, agent_id: str, status: Dict[str, Any]) -> None:
45
+ """Report agent status to control plane"""
46
+ await self._client.post(
47
+ "/api/v1/webhooks/data-plane/status",
48
+ json={"agent_id": agent_id, **status}
49
+ )
50
+
51
+ # ============================================================
52
+ # Slice 1 — data plane sync helpers
53
+ # ============================================================
54
+
55
+ async def heartbeat(
56
+ self,
57
+ runtime_version: str,
58
+ pod_count: int,
59
+ queue_depth: int,
60
+ last_seq: int,
61
+ runtime_token: Optional[str] = None,
62
+ ) -> Dict[str, Any]:
63
+ """POST /api/v1/data-plane/heartbeat — returns heartbeat response.
64
+
65
+ ``runtime_token`` is required (provide either here or via
66
+ ``X-Runtime-Token`` on the client).
67
+ """
68
+ headers = {"X-Runtime-Token": runtime_token or ""}
69
+ body = {
70
+ "tenant_id": self.tenant_id,
71
+ "runtime_version": runtime_version,
72
+ "pod_count": pod_count,
73
+ "queue_depth": queue_depth,
74
+ "last_ledger_seq_forwarded": last_seq,
75
+ }
76
+ resp = await self._client.post(
77
+ "/api/v1/data-plane/heartbeat", json=body, headers=headers,
78
+ )
79
+ resp.raise_for_status()
80
+ return resp.json()
81
+
82
+ async def replay_ledger(
83
+ self,
84
+ entries: List[Dict[str, Any]],
85
+ runtime_token: Optional[str] = None,
86
+ ) -> Dict[str, Any]:
87
+ """POST /api/v1/data-plane/ledger/replay — bulk replay."""
88
+ headers = {"X-Runtime-Token": runtime_token or ""}
89
+ body = {"tenant_id": self.tenant_id, "entries": entries}
90
+ resp = await self._client.post(
91
+ "/api/v1/data-plane/ledger/replay", json=body, headers=headers,
92
+ )
93
+ resp.raise_for_status()
94
+ return resp.json()
95
+
96
+ async def fetch_agent_spec(
97
+ self,
98
+ agent_id: Optional[str] = None,
99
+ since: float = 0.0,
100
+ runtime_token: Optional[str] = None,
101
+ ) -> Dict[str, Any]:
102
+ """GET /api/v1/data-plane/agents/spec?since=&tenant_id=.
103
+
104
+ ``agent_id`` is optional — when supplied the response is filtered
105
+ to that agent locally.
106
+ """
107
+ headers = {"X-Runtime-Token": runtime_token or ""}
108
+ params = {"tenant_id": self.tenant_id or "", "since": since}
109
+ resp = await self._client.get(
110
+ "/api/v1/data-plane/agents/spec", params=params, headers=headers,
111
+ )
112
+ resp.raise_for_status()
113
+ data = resp.json()
114
+ if agent_id:
115
+ data["agents"] = [a for a in data.get("agents", []) if str(a.get("id")) == str(agent_id)]
116
+ return data
117
+
118
+ async def close(self):
119
+ """Close the HTTP client"""
120
+ await self._client.aclose()
121
+
122
+ async def __aenter__(self):
123
+ return self
124
+
125
+ async def __aexit__(self, *args):
126
+ await self.close()
@@ -0,0 +1,243 @@
1
+ """Memory Systems for Vouchstone Agents"""
2
+
3
+ from typing import Optional, List, Dict, Any
4
+ from dataclasses import dataclass
5
+ from datetime import datetime, timedelta
6
+ import json
7
+ import hashlib
8
+
9
+ from .types import MemoryEntry, Decision, Episode
10
+
11
+
12
+ class SemanticMemory:
13
+ """Vector-based semantic memory for knowledge retrieval"""
14
+
15
+ def __init__(
16
+ self,
17
+ embedding_model: str = "text-embedding-3-small",
18
+ vector_db_url: Optional[str] = None,
19
+ collection_name: str = "semantic_memory"
20
+ ):
21
+ self.embedding_model = embedding_model
22
+ self.vector_db_url = vector_db_url
23
+ self.collection_name = collection_name
24
+ self._client = None
25
+ self._embedder = None
26
+
27
+ async def initialize(self):
28
+ """Initialize vector DB connection"""
29
+ if self.vector_db_url:
30
+ # Use Qdrant or ChromaDB based on URL
31
+ if "qdrant" in self.vector_db_url:
32
+ from qdrant_client import QdrantClient
33
+ self._client = QdrantClient(url=self.vector_db_url)
34
+ else:
35
+ import chromadb
36
+ self._client = chromadb.HttpClient(host=self.vector_db_url)
37
+ else:
38
+ # Use in-memory ChromaDB for development
39
+ import chromadb
40
+ self._client = chromadb.Client()
41
+
42
+ async def store(self, text: str, metadata: Dict[str, Any] = None) -> str:
43
+ """Store text with embeddings"""
44
+ embedding = await self._get_embedding(text)
45
+ doc_id = hashlib.md5(text.encode()).hexdigest()
46
+
47
+ # Store in vector DB
48
+ collection = self._client.get_or_create_collection(self.collection_name)
49
+ collection.add(
50
+ ids=[doc_id],
51
+ embeddings=[embedding],
52
+ documents=[text],
53
+ metadatas=[metadata or {}]
54
+ )
55
+ return doc_id
56
+
57
+ async def search(self, query: str, top_k: int = 5) -> List[MemoryEntry]:
58
+ """Search for relevant memories"""
59
+ embedding = await self._get_embedding(query)
60
+
61
+ collection = self._client.get_or_create_collection(self.collection_name)
62
+ results = collection.query(
63
+ query_embeddings=[embedding],
64
+ n_results=top_k
65
+ )
66
+
67
+ entries = []
68
+ for i, doc in enumerate(results["documents"][0]):
69
+ entries.append(MemoryEntry(
70
+ id=results["ids"][0][i],
71
+ content=doc,
72
+ metadata=results["metadatas"][0][i] if results["metadatas"] else {},
73
+ score=results["distances"][0][i] if results.get("distances") else 0.0
74
+ ))
75
+ return entries
76
+
77
+ async def _get_embedding(self, text: str) -> List[float]:
78
+ """Get embedding for text"""
79
+ import openai
80
+ client = openai.AsyncOpenAI()
81
+ response = await client.embeddings.create(
82
+ model=self.embedding_model,
83
+ input=text
84
+ )
85
+ return response.data[0].embedding
86
+
87
+ async def close(self):
88
+ pass
89
+
90
+
91
+ class EpisodicMemory:
92
+ """Time-based episodic memory for conversation history"""
93
+
94
+ def __init__(self, retention_days: int = 90):
95
+ self.retention_days = retention_days
96
+ self._episodes: List[Episode] = []
97
+
98
+ async def initialize(self):
99
+ """Initialize episodic memory storage"""
100
+ pass
101
+
102
+ async def store(self, message: Any, response: Any) -> str:
103
+ """Store an episode (message-response pair)"""
104
+ episode = Episode(
105
+ id=f"ep_{datetime.utcnow().timestamp()}",
106
+ timestamp=datetime.utcnow(),
107
+ message=str(message),
108
+ response=str(response),
109
+ metadata={}
110
+ )
111
+ self._episodes.append(episode)
112
+ return episode.id
113
+
114
+ async def get_recent(self, limit: int = 10) -> List[Episode]:
115
+ """Get recent episodes"""
116
+ cutoff = datetime.utcnow() - timedelta(days=self.retention_days)
117
+ recent = [e for e in self._episodes if e.timestamp > cutoff]
118
+ return sorted(recent, key=lambda x: x.timestamp, reverse=True)[:limit]
119
+
120
+ async def search(self, query: str, limit: int = 5) -> List[Episode]:
121
+ """Search episodes by content"""
122
+ matches = []
123
+ query_lower = query.lower()
124
+ for episode in self._episodes:
125
+ if query_lower in episode.message.lower() or query_lower in episode.response.lower():
126
+ matches.append(episode)
127
+ return matches[:limit]
128
+
129
+ async def close(self):
130
+ pass
131
+
132
+
133
+ class ProceduralMemory:
134
+ """Memory for learned procedures and skills"""
135
+
136
+ def __init__(self):
137
+ self._procedures: Dict[str, Dict[str, Any]] = {}
138
+
139
+ async def initialize(self):
140
+ pass
141
+
142
+ async def store_procedure(
143
+ self,
144
+ name: str,
145
+ steps: List[str],
146
+ conditions: Dict[str, Any] = None
147
+ ) -> str:
148
+ """Store a procedure"""
149
+ self._procedures[name] = {
150
+ "name": name,
151
+ "steps": steps,
152
+ "conditions": conditions or {},
153
+ "created_at": datetime.utcnow().isoformat()
154
+ }
155
+ return name
156
+
157
+ async def get_relevant(self, context: str) -> List[Dict[str, Any]]:
158
+ """Get procedures relevant to context"""
159
+ # Simple keyword matching - could use embeddings
160
+ relevant = []
161
+ context_lower = context.lower()
162
+ for name, proc in self._procedures.items():
163
+ if name.lower() in context_lower:
164
+ relevant.append(proc)
165
+ return relevant
166
+
167
+ async def execute_procedure(self, name: str, inputs: Dict[str, Any]) -> Any:
168
+ """Execute a stored procedure"""
169
+ if name not in self._procedures:
170
+ raise ValueError(f"Procedure {name} not found")
171
+
172
+ proc = self._procedures[name]
173
+ # Return steps for now - actual execution would depend on step types
174
+ return {"procedure": name, "steps": proc["steps"], "inputs": inputs}
175
+
176
+ async def close(self):
177
+ pass
178
+
179
+
180
+ class DecisionGraph:
181
+ """Graph-based decision memory with reasoning chains"""
182
+
183
+ def __init__(self, graph_db_url: Optional[str] = None):
184
+ self.graph_db_url = graph_db_url
185
+ self._driver = None
186
+ self._decisions: List[Decision] = []
187
+
188
+ async def initialize(self):
189
+ """Initialize graph database connection"""
190
+ if self.graph_db_url:
191
+ from neo4j import AsyncGraphDatabase
192
+ self._driver = AsyncGraphDatabase.driver(self.graph_db_url)
193
+
194
+ async def record_decision(self, decision: Decision) -> str:
195
+ """Record a decision in the graph"""
196
+ self._decisions.append(decision)
197
+
198
+ if self._driver:
199
+ async with self._driver.session() as session:
200
+ await session.run(
201
+ """
202
+ CREATE (d:Decision {
203
+ id: $id,
204
+ question: $question,
205
+ answer: $answer,
206
+ confidence: $confidence,
207
+ reasoning: $reasoning,
208
+ timestamp: datetime()
209
+ })
210
+ """,
211
+ id=decision.id,
212
+ question=decision.question,
213
+ answer=decision.answer,
214
+ confidence=decision.confidence,
215
+ reasoning=json.dumps(decision.reasoning)
216
+ )
217
+
218
+ return decision.id
219
+
220
+ async def get_context(self, query: str) -> Dict[str, Any]:
221
+ """Get decision context for a query"""
222
+ # Find related decisions
223
+ related = []
224
+ query_lower = query.lower()
225
+ for decision in self._decisions:
226
+ if query_lower in decision.question.lower():
227
+ related.append(decision)
228
+
229
+ return {
230
+ "related_decisions": related[-5:],
231
+ "total_decisions": len(self._decisions)
232
+ }
233
+
234
+ async def get_reasoning_chain(self, decision_id: str) -> List[Dict[str, Any]]:
235
+ """Get the reasoning chain for a decision"""
236
+ for decision in self._decisions:
237
+ if decision.id == decision_id:
238
+ return decision.reasoning
239
+ return []
240
+
241
+ async def close(self):
242
+ if self._driver:
243
+ await self._driver.close()
@@ -0,0 +1,78 @@
1
+ """Type definitions for Vouchstone SDK"""
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Optional, List, Dict, Any
5
+ from datetime import datetime
6
+ from enum import Enum
7
+
8
+
9
+ @dataclass
10
+ class Message:
11
+ """Input message to an agent"""
12
+ content: str
13
+ role: str = "user"
14
+ metadata: Dict[str, Any] = field(default_factory=dict)
15
+ timestamp: datetime = field(default_factory=datetime.utcnow)
16
+
17
+
18
+ @dataclass
19
+ class Decision:
20
+ """A decision made by an agent"""
21
+ id: str
22
+ question: str
23
+ answer: str
24
+ confidence: float
25
+ reasoning: List[Dict[str, Any]] = field(default_factory=list)
26
+ metadata: Dict[str, Any] = field(default_factory=dict)
27
+ timestamp: datetime = field(default_factory=datetime.utcnow)
28
+
29
+
30
+ @dataclass
31
+ class AgentResponse:
32
+ """Response from an agent"""
33
+ content: str
34
+ decisions: List[Decision] = field(default_factory=list)
35
+ tool_calls: List[Dict[str, Any]] = field(default_factory=list)
36
+ metadata: Dict[str, Any] = field(default_factory=dict)
37
+ usage: Dict[str, int] = field(default_factory=dict)
38
+
39
+
40
+ @dataclass
41
+ class MemoryEntry:
42
+ """An entry from memory search"""
43
+ id: str
44
+ content: str
45
+ metadata: Dict[str, Any] = field(default_factory=dict)
46
+ score: float = 0.0
47
+
48
+
49
+ @dataclass
50
+ class Episode:
51
+ """An episodic memory entry"""
52
+ id: str
53
+ timestamp: datetime
54
+ message: str
55
+ response: str
56
+ metadata: Dict[str, Any] = field(default_factory=dict)
57
+
58
+
59
+ @dataclass
60
+ class AgentDefinition:
61
+ """Agent definition from control plane"""
62
+ id: str
63
+ name: str
64
+ slug: str
65
+ agent_type: str
66
+ status: str
67
+ memory_config: Dict[str, Any]
68
+ config_schema: Dict[str, Any]
69
+ code_s3_key: Optional[str] = None
70
+ description: Optional[str] = None
71
+ tags: List[str] = field(default_factory=list)
72
+
73
+
74
+ class AgentStatus(str, Enum):
75
+ DRAFT = "draft"
76
+ ACTIVE = "active"
77
+ PAUSED = "paused"
78
+ ARCHIVED = "archived"
@@ -0,0 +1,125 @@
1
+ Metadata-Version: 2.4
2
+ Name: vouchstone-sdk
3
+ Version: 1.0.0
4
+ Summary: Python SDK for Vouchstone — AI engineers you can vouch for
5
+ Author: Vouchstone
6
+ Author-email: "Vouchstone Inc." <gaurav@datapitcher.com>
7
+ License: Proprietary
8
+ Project-URL: Homepage, https://vouchstone.ai
9
+ Project-URL: Repository, https://github.com/GGChamp85/Vouchstone
10
+ Project-URL: Documentation, https://vouchstone.ai/docs
11
+ Keywords: ai,agents,memory,enterprise,vouchstone
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Intended Audience :: Developers
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 :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ Requires-Dist: httpx>=0.25.0
22
+ Requires-Dist: pydantic>=2.0.0
23
+ Requires-Dist: openai>=1.0.0
24
+ Requires-Dist: anthropic>=0.18.0
25
+ Requires-Dist: numpy>=1.24.0
26
+ Requires-Dist: aiofiles>=23.0.0
27
+ Provides-Extra: vector
28
+ Requires-Dist: chromadb>=0.4.0; extra == "vector"
29
+ Requires-Dist: qdrant-client>=1.7.0; extra == "vector"
30
+ Provides-Extra: graph
31
+ Requires-Dist: neo4j>=5.0.0; extra == "graph"
32
+ Provides-Extra: all
33
+ Requires-Dist: chromadb>=0.4.0; extra == "all"
34
+ Requires-Dist: qdrant-client>=1.7.0; extra == "all"
35
+ Requires-Dist: neo4j>=5.0.0; extra == "all"
36
+ Provides-Extra: dev
37
+ Requires-Dist: pytest>=7.0; extra == "dev"
38
+ Requires-Dist: pytest-asyncio>=0.21; extra == "dev"
39
+ Requires-Dist: black; extra == "dev"
40
+ Requires-Dist: mypy; extra == "dev"
41
+ Dynamic: author
42
+ Dynamic: requires-python
43
+
44
+ # Vouchstone SDK
45
+
46
+ Python SDK for building AI agents on the Vouchstone platform — the first accountable AI engineering firm.
47
+
48
+ ## Install
49
+
50
+ ```bash
51
+ pip install vouchstone-sdk
52
+
53
+ # With vector memory (ChromaDB)
54
+ pip install vouchstone-sdk[vector]
55
+
56
+ # With graph memory (Neo4j)
57
+ pip install vouchstone-sdk[graph]
58
+
59
+ # Everything
60
+ pip install vouchstone-sdk[all]
61
+ ```
62
+
63
+ ## Quick Start
64
+
65
+ ```python
66
+ from vouchstone_sdk import Agent, AgentConfig, Message
67
+
68
+ class MyAgent(Agent):
69
+ async def run(self, message: Message, context: dict):
70
+ relevant_docs = context.get("semantic", [])
71
+ history = context.get("episodic", [])
72
+
73
+ response = await self.llm.complete(
74
+ system=f"You are {self.config.name}. Use the context to help the user.",
75
+ messages=[{"role": "user", "content": message.content}],
76
+ context=relevant_docs,
77
+ )
78
+ return AgentResponse(content=response)
79
+
80
+ config = AgentConfig(
81
+ name="Data Migration Agent",
82
+ model="claude-sonnet-4-20250514",
83
+ semantic_memory=True,
84
+ episodic_memory=True,
85
+ procedural_memory=True,
86
+ )
87
+
88
+ agent = MyAgent(config)
89
+ await agent.initialize(vector_db_url="http://chromadb:8000")
90
+ response = await agent.process(Message(content="Migrate our PostgreSQL to Snowflake"))
91
+ ```
92
+
93
+ ## 5-Layer Memory Stack
94
+
95
+ Each agent has access to a biologically-inspired memory architecture:
96
+
97
+ | Layer | Name | Storage | Purpose |
98
+ |-------|------|---------|---------|
99
+ | 1 | Working | Redis | Current turn context (resets per session) |
100
+ | 2 | Episodic | PostgreSQL | Cross-session traces (append-only) |
101
+ | 3 | Semantic | ChromaDB | Entity store (vector search) |
102
+ | 4 | Procedural | Neo4j | Learned skills (versioned DAG) |
103
+ | 5 | Meta | Control Plane | Decay, dedup, compress, forget |
104
+
105
+ ## Control Plane Client
106
+
107
+ ```python
108
+ from vouchstone_sdk import VouchstoneClient
109
+
110
+ client = VouchstoneClient(
111
+ api_url="https://api.vouchstone.ai",
112
+ api_key="your-api-key",
113
+ tenant_id="your-tenant-id",
114
+ )
115
+
116
+ # List agents
117
+ agents = await client.list_agents()
118
+
119
+ # Execute an agent
120
+ result = await client.execute(agent_id="...", input={"content": "Hello"})
121
+ ```
122
+
123
+ ## License
124
+
125
+ Proprietary — Copyright (c) 2026 Vouchstone Inc. All Rights Reserved.
@@ -0,0 +1,9 @@
1
+ vouchstone_sdk/__init__.py,sha256=zsYejIqKxod_gkESjH50cDZnBiBF48v6mUIlvSQfZbQ,510
2
+ vouchstone_sdk/agent.py,sha256=uOzYuWM1-QX1pDW81gF96vWZ1yiT6cxdZFvRmBncmY4,5384
3
+ vouchstone_sdk/client.py,sha256=lsVdP0rSy-Iml58vBoIlbjF3lgGvL7ni7RyzBG2Js4E,4492
4
+ vouchstone_sdk/memory.py,sha256=bIBKXubJUWqgJvRXFw_bsLsva3gXAonwJdH3V1gULy4,8326
5
+ vouchstone_sdk/types.py,sha256=sLKYYgdnXlZ1aqhILs_qmgQASL11gDQyHJ35_073-4E,1908
6
+ vouchstone_sdk-1.0.0.dist-info/METADATA,sha256=3SVYINig7kwjNUFMFyyS1zkf0qwI3w5KpYtaWqmAluw,3826
7
+ vouchstone_sdk-1.0.0.dist-info/WHEEL,sha256=aeYiig01lYGDzBgS8HxWXOg3uV61G9ijOsup-k9o1sk,91
8
+ vouchstone_sdk-1.0.0.dist-info/top_level.txt,sha256=jq-KNYdmZHhfBiit-AgzwaaZ8XKCVBxZhOBlOlY5GZA,15
9
+ vouchstone_sdk-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (82.0.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ vouchstone_sdk