crewlayer 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.
crewlayer/_memory.py ADDED
@@ -0,0 +1,192 @@
1
+ """Memory resource clients — sync and async."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+ from crewlayer._http import AsyncTransport, SyncTransport
7
+ from crewlayer._types import (
8
+ ExtractResult,
9
+ MemoryPage,
10
+ RecallResult,
11
+ ShortMemory,
12
+ )
13
+
14
+
15
+ class MemoryClient:
16
+ """Synchronous memory operations."""
17
+
18
+ def __init__(self, http: SyncTransport) -> None:
19
+ self._http = http
20
+
21
+ def append(
22
+ self,
23
+ agent_id: str,
24
+ role: str,
25
+ content: str,
26
+ *,
27
+ session_id: str = "default",
28
+ metadata: dict[str, Any] | None = None,
29
+ ) -> ShortMemory:
30
+ """Append a message to the agent's short-term session memory."""
31
+ data = self._http.request(
32
+ "POST",
33
+ f"/v1/agents/{agent_id}/memory/messages",
34
+ params={"session_id": session_id},
35
+ json={"role": role, "content": content, "metadata": metadata or {}},
36
+ )
37
+ return ShortMemory._from(data)
38
+
39
+ def messages(
40
+ self,
41
+ agent_id: str,
42
+ *,
43
+ session_id: str = "default",
44
+ limit: int = 50,
45
+ ) -> ShortMemory:
46
+ """Retrieve recent messages from the agent's session memory."""
47
+ data = self._http.request(
48
+ "GET",
49
+ f"/v1/agents/{agent_id}/memory/messages",
50
+ params={"session_id": session_id, "limit": limit},
51
+ )
52
+ return ShortMemory._from(data)
53
+
54
+ def recall(
55
+ self,
56
+ agent_id: str,
57
+ query: str,
58
+ *,
59
+ limit: int = 10,
60
+ min_similarity: float = 0.0,
61
+ ) -> RecallResult:
62
+ """Semantic search over long-term memories using the query text."""
63
+ data = self._http.request(
64
+ "POST",
65
+ f"/v1/agents/{agent_id}/memory/recall",
66
+ json={"query": query, "limit": limit, "min_similarity": min_similarity},
67
+ )
68
+ return RecallResult._from(data)
69
+
70
+ def extract(
71
+ self,
72
+ agent_id: str,
73
+ conversation: str,
74
+ *,
75
+ session_id: str | None = None,
76
+ ) -> ExtractResult:
77
+ """Extract facts from a conversation with Claude and persist as long-term memories."""
78
+ data = self._http.request(
79
+ "POST",
80
+ f"/v1/agents/{agent_id}/memory/extract",
81
+ json={"conversation": conversation, "session_id": session_id},
82
+ )
83
+ return ExtractResult._from(data)
84
+
85
+ def list(
86
+ self,
87
+ agent_id: str,
88
+ *,
89
+ page: int = 1,
90
+ page_size: int = 20,
91
+ ) -> MemoryPage:
92
+ """List all long-term memories for an agent, paginated."""
93
+ data = self._http.request(
94
+ "GET",
95
+ f"/v1/agents/{agent_id}/memory",
96
+ params={"page": page, "page_size": page_size},
97
+ )
98
+ return MemoryPage._from(data)
99
+
100
+ def delete(self, agent_id: str, memory_id: str) -> None:
101
+ """Soft-delete a long-term memory record."""
102
+ self._http.request("DELETE", f"/v1/agents/{agent_id}/memory/{memory_id}")
103
+
104
+
105
+ class AsyncMemoryClient:
106
+ """Asynchronous memory operations."""
107
+
108
+ def __init__(self, http: AsyncTransport) -> None:
109
+ self._http = http
110
+
111
+ async def append(
112
+ self,
113
+ agent_id: str,
114
+ role: str,
115
+ content: str,
116
+ *,
117
+ session_id: str = "default",
118
+ metadata: dict[str, Any] | None = None,
119
+ ) -> ShortMemory:
120
+ """Append a message to the agent's short-term session memory."""
121
+ data = await self._http.request(
122
+ "POST",
123
+ f"/v1/agents/{agent_id}/memory/messages",
124
+ params={"session_id": session_id},
125
+ json={"role": role, "content": content, "metadata": metadata or {}},
126
+ )
127
+ return ShortMemory._from(data)
128
+
129
+ async def messages(
130
+ self,
131
+ agent_id: str,
132
+ *,
133
+ session_id: str = "default",
134
+ limit: int = 50,
135
+ ) -> ShortMemory:
136
+ """Retrieve recent messages from the agent's session memory."""
137
+ data = await self._http.request(
138
+ "GET",
139
+ f"/v1/agents/{agent_id}/memory/messages",
140
+ params={"session_id": session_id, "limit": limit},
141
+ )
142
+ return ShortMemory._from(data)
143
+
144
+ async def recall(
145
+ self,
146
+ agent_id: str,
147
+ query: str,
148
+ *,
149
+ limit: int = 10,
150
+ min_similarity: float = 0.0,
151
+ ) -> RecallResult:
152
+ """Semantic search over long-term memories using the query text."""
153
+ data = await self._http.request(
154
+ "POST",
155
+ f"/v1/agents/{agent_id}/memory/recall",
156
+ json={"query": query, "limit": limit, "min_similarity": min_similarity},
157
+ )
158
+ return RecallResult._from(data)
159
+
160
+ async def extract(
161
+ self,
162
+ agent_id: str,
163
+ conversation: str,
164
+ *,
165
+ session_id: str | None = None,
166
+ ) -> ExtractResult:
167
+ """Extract facts from a conversation with Claude and persist as long-term memories."""
168
+ data = await self._http.request(
169
+ "POST",
170
+ f"/v1/agents/{agent_id}/memory/extract",
171
+ json={"conversation": conversation, "session_id": session_id},
172
+ )
173
+ return ExtractResult._from(data)
174
+
175
+ async def list(
176
+ self,
177
+ agent_id: str,
178
+ *,
179
+ page: int = 1,
180
+ page_size: int = 20,
181
+ ) -> MemoryPage:
182
+ """List all long-term memories for an agent, paginated."""
183
+ data = await self._http.request(
184
+ "GET",
185
+ f"/v1/agents/{agent_id}/memory",
186
+ params={"page": page, "page_size": page_size},
187
+ )
188
+ return MemoryPage._from(data)
189
+
190
+ async def delete(self, agent_id: str, memory_id: str) -> None:
191
+ """Soft-delete a long-term memory record."""
192
+ await self._http.request("DELETE", f"/v1/agents/{agent_id}/memory/{memory_id}")
crewlayer/_types.py ADDED
@@ -0,0 +1,242 @@
1
+ """Response dataclasses returned by the CrewLayer SDK."""
2
+ from __future__ import annotations
3
+
4
+ from dataclasses import dataclass, field
5
+ from typing import Any
6
+
7
+ # ---------------------------------------------------------------------------
8
+ # Memory
9
+ # ---------------------------------------------------------------------------
10
+
11
+ @dataclass
12
+ class Message:
13
+ """A single message in short-term (session) memory."""
14
+ role: str
15
+ content: str
16
+ metadata: dict[str, Any] = field(default_factory=dict)
17
+
18
+ @classmethod
19
+ def _from(cls, d: dict[str, Any]) -> Message:
20
+ return cls(role=d["role"], content=d["content"], metadata=d.get("metadata", {}))
21
+
22
+
23
+ @dataclass
24
+ class ShortMemory:
25
+ """Short-term memory for a session — a list of recent messages."""
26
+ session_id: str
27
+ messages: list[Message]
28
+ count: int
29
+
30
+ @classmethod
31
+ def _from(cls, d: dict[str, Any]) -> ShortMemory:
32
+ return cls(
33
+ session_id=d["session_id"],
34
+ messages=[Message._from(m) for m in d["messages"]],
35
+ count=d["count"],
36
+ )
37
+
38
+
39
+ @dataclass
40
+ class MemoryItem:
41
+ """A single long-term memory record."""
42
+ id: str
43
+ agent_id: str
44
+ content: str
45
+ importance: float
46
+ tags: list[str]
47
+ created_at: str
48
+ summary: str | None = None
49
+ similarity: float | None = None
50
+
51
+ @classmethod
52
+ def _from(cls, d: dict[str, Any]) -> MemoryItem:
53
+ return cls(
54
+ id=d["id"],
55
+ agent_id=d["agent_id"],
56
+ content=d["content"],
57
+ importance=d["importance"],
58
+ tags=d["tags"],
59
+ created_at=d["created_at"],
60
+ summary=d.get("summary"),
61
+ similarity=d.get("similarity"),
62
+ )
63
+
64
+
65
+ @dataclass
66
+ class RecallResult:
67
+ """Semantic recall results ranked by similarity to the query."""
68
+ query: str
69
+ results: list[MemoryItem]
70
+
71
+ @classmethod
72
+ def _from(cls, d: dict[str, Any]) -> RecallResult:
73
+ return cls(query=d["query"], results=[MemoryItem._from(r) for r in d["results"]])
74
+
75
+
76
+ @dataclass
77
+ class ExtractResult:
78
+ """Result of extracting facts from a conversation."""
79
+ extracted_count: int
80
+ memory_ids: list[str]
81
+
82
+ @classmethod
83
+ def _from(cls, d: dict[str, Any]) -> ExtractResult:
84
+ return cls(extracted_count=d["extracted_count"], memory_ids=d["memory_ids"])
85
+
86
+
87
+ @dataclass
88
+ class MemoryPage:
89
+ """Paginated list of long-term memory records."""
90
+ items: list[MemoryItem]
91
+ total: int
92
+ page: int
93
+ page_size: int
94
+
95
+ @classmethod
96
+ def _from(cls, d: dict[str, Any]) -> MemoryPage:
97
+ return cls(
98
+ items=[MemoryItem._from(i) for i in d["items"]],
99
+ total=d["total"],
100
+ page=d["page"],
101
+ page_size=d["page_size"],
102
+ )
103
+
104
+
105
+ # ---------------------------------------------------------------------------
106
+ # Actions
107
+ # ---------------------------------------------------------------------------
108
+
109
+ @dataclass
110
+ class ActionRecord:
111
+ """An immutable action log entry."""
112
+ id: str
113
+ tenant_id: str
114
+ agent_id: str
115
+ tool_name: str
116
+ input_params: dict[str, Any]
117
+ output_result: dict[str, Any]
118
+ status: str
119
+ timestamp: str
120
+ session_id: str | None = None
121
+ duration_ms: int | None = None
122
+ error_msg: str | None = None
123
+ metadata: dict[str, Any] = field(default_factory=dict)
124
+
125
+ @classmethod
126
+ def _from(cls, d: dict[str, Any]) -> ActionRecord:
127
+ return cls(
128
+ id=d["id"],
129
+ tenant_id=d["tenant_id"],
130
+ agent_id=d["agent_id"],
131
+ tool_name=d["tool_name"],
132
+ input_params=d["input_params"],
133
+ output_result=d["output_result"],
134
+ status=d["status"],
135
+ timestamp=d["timestamp"],
136
+ session_id=d.get("session_id"),
137
+ duration_ms=d.get("duration_ms"),
138
+ error_msg=d.get("error_msg"),
139
+ metadata=d.get("metadata", {}),
140
+ )
141
+
142
+
143
+ @dataclass
144
+ class ActionPage:
145
+ """Cursor-paginated list of action records."""
146
+ items: list[ActionRecord]
147
+ count: int
148
+ next_cursor: str | None
149
+
150
+ @classmethod
151
+ def _from(cls, d: dict[str, Any]) -> ActionPage:
152
+ return cls(
153
+ items=[ActionRecord._from(i) for i in d["items"]],
154
+ count=d["count"],
155
+ next_cursor=d.get("next_cursor"),
156
+ )
157
+
158
+
159
+ @dataclass
160
+ class ToolStat:
161
+ """Aggregate statistics for a single tool."""
162
+ tool_name: str
163
+ count: int
164
+ error_rate: float
165
+ avg_duration_ms: float | None = None
166
+
167
+ @classmethod
168
+ def _from(cls, d: dict[str, Any]) -> ToolStat:
169
+ return cls(
170
+ tool_name=d["tool_name"],
171
+ count=d["count"],
172
+ error_rate=d["error_rate"],
173
+ avg_duration_ms=d.get("avg_duration_ms"),
174
+ )
175
+
176
+
177
+ @dataclass
178
+ class ActionStats:
179
+ """Aggregate action statistics for an agent."""
180
+ total_actions: int
181
+ error_rate: float
182
+ by_tool: list[ToolStat]
183
+ avg_duration_ms: float | None = None
184
+
185
+ @classmethod
186
+ def _from(cls, d: dict[str, Any]) -> ActionStats:
187
+ return cls(
188
+ total_actions=d["total_actions"],
189
+ error_rate=d["error_rate"],
190
+ avg_duration_ms=d.get("avg_duration_ms"),
191
+ by_tool=[ToolStat._from(t) for t in d["by_tool"]],
192
+ )
193
+
194
+
195
+ # ---------------------------------------------------------------------------
196
+ # Context
197
+ # ---------------------------------------------------------------------------
198
+
199
+ @dataclass
200
+ class ContextEntry:
201
+ """A single blackboard context entry."""
202
+ id: str
203
+ tenant_id: str
204
+ namespace: str
205
+ key: str
206
+ value: dict[str, Any]
207
+ version: int
208
+ created_at: str
209
+ updated_at: str
210
+ written_by: str | None = None
211
+ expires_at: str | None = None
212
+
213
+ @classmethod
214
+ def _from(cls, d: dict[str, Any]) -> ContextEntry:
215
+ return cls(
216
+ id=d["id"],
217
+ tenant_id=d["tenant_id"],
218
+ namespace=d["namespace"],
219
+ key=d["key"],
220
+ value=d["value"],
221
+ version=d["version"],
222
+ created_at=d["created_at"],
223
+ updated_at=d["updated_at"],
224
+ written_by=d.get("written_by"),
225
+ expires_at=d.get("expires_at"),
226
+ )
227
+
228
+
229
+ @dataclass
230
+ class ContextNamespace:
231
+ """All non-expired entries in a namespace."""
232
+ namespace: str
233
+ entries: list[ContextEntry]
234
+ count: int
235
+
236
+ @classmethod
237
+ def _from(cls, d: dict[str, Any]) -> ContextNamespace:
238
+ return cls(
239
+ namespace=d["namespace"],
240
+ entries=[ContextEntry._from(e) for e in d["entries"]],
241
+ count=d["count"],
242
+ )
@@ -0,0 +1,6 @@
1
+ """Optional framework integrations for the CrewLayer SDK.
2
+
3
+ Install extras:
4
+ pip install crewlayer[langchain] # LangChain integration
5
+ pip install crewlayer[crewai] # CrewAI integration
6
+ """