meshagent-agents 0.0.22__py3-none-any.whl → 0.0.24__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.

Potentially problematic release.


This version of meshagent-agents might be problematic. Click here for more details.

@@ -37,7 +37,7 @@ class Listener(TaskRunner):
37
37
  "properties" : {
38
38
  "path" : {
39
39
  "type" : "string",
40
- "description" : "the path of the document to proofread"
40
+ "description" : "the path of the document to listen to"
41
41
  }
42
42
  }
43
43
  },
@@ -0,0 +1,337 @@
1
+ from meshagent.agents.worker import Worker
2
+ from meshagent.tools import Tool, Toolkit
3
+ from meshagent.api.room_server_client import TextDataType
4
+ from email import message_from_bytes
5
+ from email.message import EmailMessage
6
+ from email.policy import default
7
+ import email.utils
8
+ from meshagent.api import ParticipantToken
9
+
10
+ from meshagent.api import RoomClient
11
+
12
+ from datetime import datetime, timezone
13
+
14
+ import secrets
15
+
16
+ from typing import Literal, Optional
17
+ import json
18
+
19
+ import uuid
20
+ import logging
21
+
22
+ import os
23
+ import aiosmtplib
24
+
25
+ logger = logging.getLogger("mail")
26
+
27
+ type MessageRole = Literal["user", "agent"]
28
+
29
+
30
+
31
+ def create_reply_email_message(*, message: dict, from_address: str, body: str) -> EmailMessage:
32
+
33
+ subject : str = message.get("subject")
34
+
35
+ if not subject.startswith("RE:"):
36
+ subject = "RE: " + subject
37
+
38
+ _, addr = email.utils.parseaddr(from_address)
39
+ domain = addr.split("@")[-1].lower()
40
+ id = f"<{uuid.uuid4()}@{domain}>"
41
+
42
+ msg = EmailMessage()
43
+ msg["Message-ID"] = id
44
+ msg["Subject"] = subject
45
+ msg["From"] = from_address
46
+ msg["To"] = message.get("reply_to")
47
+ msg["In-Reply-To"] = message.get("id")
48
+ msg.set_content(body)
49
+
50
+ return msg
51
+
52
+ def message_to_json(*, message: EmailMessage, role: MessageRole):
53
+
54
+ body_part = message.get_body(('plain', 'html')) # returns the “best” part :contentReference[oaicite:0]{index=0}
55
+ if body_part:
56
+ body = body_part.get_content()
57
+ else: # simple, non-MIME message
58
+ body = message.get_content()
59
+
60
+ id = message.get("Message-ID")
61
+ if id == None:
62
+ mfrom = message.get("From")
63
+ _, addr = email.utils.parseaddr(mfrom)
64
+ domain = addr.split("@")[-1].lower()
65
+ id = f"{uuid.uuid4()}@{domain}"
66
+
67
+ return {
68
+ "id" : id,
69
+ "in_reply_to" : message.get("In-Reply-To"),
70
+ "reply_to" : message.get("Reply-To", message.get("From")),
71
+ "references" : message.get("References"),
72
+ "from" : message.get("From"),
73
+ "to" : message.get_all("To"),
74
+ "subject" : message.get("Subject"),
75
+ "body" : body,
76
+ "attachments" : [],
77
+ "role" : role
78
+ }
79
+
80
+ async def load_message(*, room: RoomClient, message_id: str) -> dict | None:
81
+
82
+ messages = await room.database.search(
83
+ table="emails",
84
+ where={
85
+ "id" : message_id
86
+ })
87
+
88
+ if len(messages) == 0:
89
+ return None
90
+
91
+ return json.loads(messages[0]["json"])
92
+
93
+ async def save_email_message(*, room: RoomClient, content: bytes, role: MessageRole) -> dict:
94
+
95
+ message = message_from_bytes(content, policy=default)
96
+
97
+ now = datetime.now(timezone.utc)
98
+
99
+ folder_path = now.strftime('%Y/%m/%d') +"/" + now.strftime('%H/%M/%S') + '/' + secrets.token_hex(3)
100
+
101
+ queued_message = message_to_json(message=message, role=role)
102
+ message_id = queued_message["id"]
103
+
104
+
105
+ queued_message["role"] = role
106
+
107
+ queued_message["path"] = f".emails/{message_id}/message.json"
108
+
109
+ for part in message.iter_attachments(): # ↔ only the “real” attachments :contentReference[oaicite:0]{index=0}
110
+ fname = part.get_filename() or "attachment.bin" # RFC 2183 filename, if any :contentReference[oaicite:1]{index=1}
111
+ ctype = part.get_content_type() # e.g. image/png, application/pdf
112
+ # get_content() auto-decodes transfer-encodings; returns
113
+ # *str* for text/*, *bytes* for everything else :contentReference[oaicite:2]{index=2}
114
+ data = part.get_content()
115
+
116
+ # make sure we write binary data
117
+ bin_data = data.encode(part.get_content_charset('utf-8')) if isinstance(data, str) else data
118
+
119
+ path = f".emails/{folder_path}/attachments/{fname}"
120
+ handle = await room.storage.open(path=path)
121
+ try:
122
+ logger.info(f"writing content to {path}")
123
+ await room.storage.write(handle=handle, data=bin_data)
124
+ finally:
125
+ await room.storage.close(handle=handle)
126
+
127
+ queued_message["attachments"].append(path)
128
+
129
+ logger.info(f"received mail, {queued_message}")
130
+
131
+ # write email
132
+ path = f".emails/{folder_path}/message.eml"
133
+ handle = await room.storage.open(path=path)
134
+ try:
135
+ logger.info(f"writing source message.eml to {path}")
136
+ await room.storage.write(handle=handle, data=content)
137
+ finally:
138
+ await room.storage.close(handle=handle)
139
+
140
+ path = f".emails/{folder_path}/message.json"
141
+ handle = await room.storage.open(path=path)
142
+ try:
143
+ logger.info(f"writing source message.json to {path}")
144
+ await room.storage.write(handle=handle, data=json.dumps(queued_message, indent=4).encode("utf-8"))
145
+ finally:
146
+ await room.storage.close(handle=handle)
147
+
148
+ # create email table if it doesn't exist
149
+ tables = await room.database.list_tables()
150
+
151
+ if "emails" not in tables:
152
+
153
+ await room.database.create_table_with_schema(
154
+ name="emails",
155
+ schema={
156
+ "id" : TextDataType(),
157
+ "json" : TextDataType()
158
+ },
159
+ mode="create_if_not_exists"
160
+ )
161
+
162
+ await room.database.create_scalar_index(table="emails", column="id")
163
+
164
+
165
+ await room.database.insert(table="emails", records=[ { "id" : message_id, "json" : json.dumps(queued_message) } ])
166
+
167
+ return queued_message
168
+
169
+
170
+ async def load_thread(*, room: RoomClient, message: dict, thread: list[dict]):
171
+
172
+ in_reply_to = message.get("in_reply_to", None)
173
+ if in_reply_to != None:
174
+
175
+ source = await load_message(room=room, message_id=in_reply_to)
176
+
177
+ if source != None:
178
+
179
+ thread.insert(0, source)
180
+
181
+ await load_thread(room=room, message=source, thread=thread)
182
+
183
+ else:
184
+
185
+ logger.warning(f"message not found {in_reply_to}")
186
+
187
+
188
+ class SmtpConfiguration:
189
+ def __init__(self, username: Optional[str] = None, password: Optional[str] = None, port: Optional[int] = None, hostname: Optional[str] = None):
190
+ if username == None:
191
+ username = os.getenv("SMTP_USERNAME")
192
+
193
+ if password == None:
194
+ password = os.getenv("SMTP_PASSWORD")
195
+
196
+ if port == None:
197
+ port = int(os.getenv("SMTP_PORT", "587"))
198
+
199
+ if hostname == None:
200
+ hostname = os.getenv("SMTP_HOSTNAME")
201
+
202
+ self.username = username
203
+ self.password = password
204
+ self.port = port
205
+ self.hostname = hostname
206
+
207
+ class MailWorker(Worker):
208
+
209
+ def __init__(self, *,
210
+ queue: str = "email",
211
+ name,
212
+ title=None,
213
+ description=None,
214
+ requires=None,
215
+ llm_adapter,
216
+ tool_adapter = None,
217
+ toolkits = None,
218
+ rules = None,
219
+ domain: str = os.getenv("MESHAGENT_MAIL_DOMAIN", "mail.meshagent.com"),
220
+ smtp: Optional[SmtpConfiguration] = None):
221
+
222
+ if smtp == None:
223
+ smtp = SmtpConfiguration()
224
+
225
+ self._domain = domain
226
+ self._smtp = smtp
227
+ super().__init__(queue=queue, name=name, title=title, description=description, requires=requires, llm_adapter=llm_adapter, tool_adapter=tool_adapter, toolkits=toolkits, rules=rules)
228
+
229
+ async def start(self, *, room):
230
+
231
+ await super().start(room=room)
232
+
233
+ token = ParticipantToken.from_jwt(room.protocol.token, validate=False)
234
+ self._email_address = room_address(project_id=token.project_id, room_name=room.room_name, domain=self._domain)
235
+
236
+ async def append_message_context(self, *, room, message, chat_context):
237
+
238
+ thread = [
239
+ message
240
+ ]
241
+
242
+ await load_thread(room=room, message=message, thread=thread)
243
+
244
+ for msg in thread:
245
+
246
+ if msg["role"] == "agent":
247
+
248
+ chat_context.append_assistant_message(json.dumps(msg))
249
+
250
+ else:
251
+
252
+ chat_context.append_user_message(json.dumps(msg))
253
+
254
+
255
+ # TODO: load previous messages
256
+ return await super().append_message_context(room=room, message=message, chat_context=chat_context)
257
+
258
+ async def process_message(self, *, chat_context, room, message, toolkits):
259
+
260
+ logger.info(f"processing message {message}")
261
+ body = await super().process_message(chat_context=chat_context, room=room, message=message, toolkits=toolkits)
262
+
263
+ msg = create_reply_email_message(message=message, from_address=self._email_address, body=body)
264
+
265
+
266
+ reply_msg_dict = await save_email_message(room=room, content=msg.as_bytes(), role="agent")
267
+
268
+ logger.info(f"replying with message {reply_msg_dict}")
269
+
270
+
271
+ username = self._smtp.username
272
+ if username == None:
273
+ username = self.room.local_participant.get_attribute("name")
274
+
275
+ password = self._smtp.password
276
+ if password == None:
277
+ password = self.room.protocol.token
278
+
279
+ await aiosmtplib.send(msg, hostname=self._smtp.hostname, port=self._smtp.port, username=username, password=password)
280
+
281
+
282
+
283
+ def base36encode(number: int):
284
+ if not isinstance(number, int):
285
+ raise TypeError('number must be an integer')
286
+ if number < 0:
287
+ raise ValueError('number must be non-negative')
288
+
289
+ alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'
290
+ if number == 0:
291
+ return '0'
292
+ base36 = ''
293
+ while number:
294
+ number, i = divmod(number, 36)
295
+ base36 = alphabet[i] + base36
296
+ return base36
297
+
298
+ def compress_uuid(guid_string: str):
299
+ guid_int = int(guid_string.replace('-', ''), 16)
300
+ return base36encode(guid_int)
301
+
302
+ def base36decode(number_str: str) -> int:
303
+ """Decode a base36-encoded string into an integer."""
304
+ alphabet = '0123456789abcdefghijklmnopqrstuvwxyz'
305
+ base = 36
306
+ number = 0
307
+ for char in number_str:
308
+ try:
309
+ value = alphabet.index(char)
310
+ except ValueError:
311
+ raise ValueError(f"Invalid character '{char}' for base36 encoding")
312
+ number = number * base + value
313
+ return number
314
+
315
+ def decompress_uuid(compressed_uuid: str) -> str:
316
+ """
317
+ Reverse the compressed UUID to its standard 36-character UUID format.
318
+
319
+ Args:
320
+ compressed_uuid: A base36 string that represents a UUID compressed from its standard form.
321
+
322
+ Returns:
323
+ A string in the UUID format (8-4-4-4-12 hexadecimal characters).
324
+ """
325
+ # Decode the base36 string back to the original integer.
326
+ guid_int = base36decode(compressed_uuid)
327
+
328
+ # Convert the integer into a 32-digit hexadecimal string with leading zeros.
329
+ hex_str = f'{guid_int:032x}'
330
+
331
+ # Reinsert dashes to match the standard UUID format: 8-4-4-4-12.
332
+ standard_uuid = f'{hex_str[0:8]}-{hex_str[8:12]}-{hex_str[12:16]}-{hex_str[16:20]}-{hex_str[20:32]}'
333
+ return standard_uuid
334
+
335
+
336
+ def room_address(*, project_id: str, room_name: str, domain: str = os.getenv("MESHAGENT_MAIL_DOMAIN", "mail.meshagent.com")):
337
+ return f"{compress_uuid(project_id)}+{room_name}@{domain}"
@@ -1 +1 @@
1
- __version__ = "0.0.22"
1
+ __version__ = "0.0.24"
@@ -1,33 +1,28 @@
1
- from .agent import TaskRunner, AgentCallContext
1
+ from .agent import SingleRoomAgent
2
2
  from meshagent.api.chan import Chan
3
3
  from meshagent.api import RoomMessage, RoomException, RoomClient, RemoteParticipant
4
+ from meshagent.agents import AgentChatContext
4
5
  from meshagent.tools import Toolkit
5
6
  from .adapter import LLMAdapter, ToolResponseAdapter
6
7
  import asyncio
7
8
  from typing import Optional
8
9
  import json
9
-
10
+ from meshagent.tools import ToolContext
10
11
  import logging
11
12
 
12
13
  logger = logging.getLogger("chat")
13
14
 
14
15
 
15
-
16
- # todo: thread should stop when participant stops?
17
-
18
- class Worker(TaskRunner):
19
- def __init__(self, *, queue: str, prompt: str, name, title = None, description = None, requires = None, llm_adapter: LLMAdapter, tool_adapter: Optional[ToolResponseAdapter] = None, toolkits: Optional[list[Toolkit]] = None, rules : Optional[list[str]] = None, supports_tools: bool = True):
16
+ class Worker(SingleRoomAgent):
17
+ def __init__(self, *, queue: str, name, title = None, description = None, requires = None, llm_adapter: LLMAdapter, tool_adapter: Optional[ToolResponseAdapter] = None, toolkits: Optional[list[Toolkit]] = None, rules : Optional[list[str]] = None):
20
18
  super().__init__(
21
19
  name=name,
22
20
  title=title,
23
21
  description=description,
24
22
  requires=requires,
25
- output_schema=None,
26
- supports_tools=supports_tools
27
23
  )
28
24
 
29
25
  self._queue = queue
30
- self._prompt = prompt
31
26
 
32
27
  if toolkits == None:
33
28
  toolkits = []
@@ -44,71 +39,67 @@ class Worker(TaskRunner):
44
39
  rules = []
45
40
 
46
41
  self._rules = rules
42
+ self._done = False
43
+
47
44
 
45
+ async def start(self, *, room: RoomClient):
46
+ self._done = False
47
+
48
+ await super().start(room=room)
48
49
 
49
- async def ask(self, *, context: AgentCallContext, arguments: dict):
50
50
 
51
- queue = self._queue
52
- prompt = self._prompt
53
-
54
- step_schema = {
55
- "type" : "object",
56
- "required" : ["text","finished"],
57
- "additionalProperties" : False,
58
- "description" : "execute a step",
59
- "properties" : {
60
- "text" : {
61
- "description" : "a reply to the user or status to display during an intermediate step",
62
- "type" : "string"
63
- },
64
- "finished" : {
65
- "description" : "whether the agent has finished answering the user's last message, also should be set to true if we get stuck in a loop, or if the user did not make a request",
66
- "type" : "boolean"
67
- }
68
- }
69
- }
51
+ self._main_task = asyncio.create_task(self.run(room=room))
52
+
53
+ async def stop(self):
54
+
55
+ self._done = True
56
+
57
+ await asyncio.gather(self._main_task)
58
+
59
+ await super().stop()
60
+
61
+
62
+ async def append_message_context(self, *, room: RoomClient, message: dict, chat_context: AgentChatContext):
63
+ chat_context.append_user_message(message=json.dumps(message))
70
64
 
71
- # todo: add graceful exit
65
+ async def process_message(self, *, chat_context: AgentChatContext, room: RoomClient, message: dict, toolkits: list[Toolkit]):
72
66
 
73
- while True:
67
+ return await self._llm_adapter.next(
68
+ context=chat_context,
69
+ room=room,
70
+ toolkits=toolkits,
71
+ tool_adapter=self._tool_adapter,
72
+ )
74
73
 
75
- message = await self.room.queues.receive(name=queue, create=True, wait=True)
76
- if message != None:
77
-
78
- # for each message, create a new chat context
79
74
 
80
- chat_context = await self.init_chat_context()
75
+ async def run(self, *, room: RoomClient):
81
76
 
82
-
83
- chat_context.append_rules(
84
- rules=[
85
- *self._rules,
86
- ]
87
- )
88
-
89
- chat_context.append_user_message(message=prompt)
90
- chat_context.append_user_message(message=json.dumps(message))
77
+ toolkits = [
78
+ *await self.get_required_toolkits(ToolContext(room=room, caller=room.local_participant)),
79
+ *self._toolkits
80
+ ]
81
+
82
+ while not self._done:
83
+
84
+ message = await room.queues.receive(name=self._queue, create=True, wait=True)
85
+ if message != None:
91
86
 
87
+ logger.info(f"received message on worker queue {message}")
92
88
  try:
93
- while True:
94
-
95
- tool_target = context.caller
96
- if context.on_behalf_of != None:
97
- tool_target = context.on_behalf_of
98
-
99
- response = await self._llm_adapter.next(
100
- context=chat_context,
101
- room=self._room,
102
- toolkits=context.toolkits,
103
- tool_adapter=self._tool_adapter,
104
- output_schema=step_schema,
105
- )
106
-
107
- if response["finished"] or len(context.toolkits) == 0:
108
- break
109
- else:
110
- chat_context.append_user_message(message="proceed to the next step if you are ready")
89
+
90
+ chat_context = await self.init_chat_context()
91
+
92
+ chat_context.append_rules(
93
+ rules=[
94
+ *self._rules,
95
+ ]
96
+ )
111
97
 
98
+ await self.append_message_context(room=room, message=message, chat_context=chat_context)
99
+
100
+
101
+ await self.process_message(chat_context=chat_context, room=room, message=message, toolkits=toolkits)
102
+
112
103
  except Exception as e:
113
104
 
114
105
  logger.error(f"Failed to process a message {message}", exc_info=e)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-agents
3
- Version: 0.0.22
3
+ Version: 0.0.24
4
4
  Summary: Agent Building Blocks for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -12,18 +12,21 @@ License-File: LICENSE
12
12
  Requires-Dist: pyjwt~=2.10.1
13
13
  Requires-Dist: pytest~=8.3.5
14
14
  Requires-Dist: pytest-asyncio~=0.26.0
15
- Requires-Dist: meshagent-api~=0.0.22
16
- Requires-Dist: meshagent-tools~=0.0.22
17
- Requires-Dist: meshagent-openai~=0.0.22
15
+ Requires-Dist: meshagent-api~=0.0.24
16
+ Requires-Dist: meshagent-tools~=0.0.24
17
+ Requires-Dist: meshagent-openai~=0.0.24
18
18
  Requires-Dist: pydantic~=2.11.1
19
19
  Requires-Dist: pydantic-ai~=0.0.48
20
20
  Provides-Extra: all
21
- Requires-Dist: meshagent-api[all]~=0.0.22; extra == "all"
21
+ Requires-Dist: meshagent-api[all]~=0.0.24; extra == "all"
22
22
  Requires-Dist: chonkie~=0.5.1; extra == "all"
23
23
  Requires-Dist: chonkie[semantic]~=0.5.1; extra == "all"
24
24
  Requires-Dist: chonkie[openai]~=0.5.1; extra == "all"
25
+ Requires-Dist: aiosmtplib~=4.0.1; extra == "all"
25
26
  Provides-Extra: sync
26
- Requires-Dist: meshagent-api[sync]~=0.0.22; extra == "sync"
27
+ Requires-Dist: meshagent-api[sync]~=0.0.24; extra == "sync"
28
+ Provides-Extra: mail
29
+ Requires-Dist: aiosmtplib~=4.0.1; extra == "mail"
27
30
  Provides-Extra: rag
28
31
  Requires-Dist: chonkie~=0.5.1; extra == "rag"
29
32
  Requires-Dist: chonkie[semantic]~=0.5.1; extra == "rag"
@@ -6,15 +6,16 @@ meshagent/agents/context.py,sha256=6eFK7wizjzZmZyhbqwazlT_E_e_Cpb17Qa3tBk2BJzw,3
6
6
  meshagent/agents/development.py,sha256=04VYL1Q_BWUTQeVuiVOpyjcs8bzUIX1eQ4VyTtjc5s0,926
7
7
  meshagent/agents/hosting.py,sha256=QFSppE-nbL31yuGvzSpES7FyNHpuHCTDDYSnroottn8,4936
8
8
  meshagent/agents/indexer.py,sha256=Lz7hJvC7hbvnmiFQLEzmakw_1OPh93pp96iSwIv1fQc,19410
9
- meshagent/agents/listener.py,sha256=T205pkkkJyOEDjKpSTrsA1XToGLWfwje_84SQu5V-vM,5359
9
+ meshagent/agents/listener.py,sha256=39u20ZwTNUVR0CRUOi4CTgBreg2ZPbrHQOohwjsfijg,5359
10
+ meshagent/agents/mail.py,sha256=8OyzV0PU8Zd-_1Ohwbm_4riIHYUAh29HJ5cK9eK7hgc,10950
10
11
  meshagent/agents/planning.py,sha256=NtXzYiwykeYdQghWjwsChy4f9OgIsQZWiIstpZvtGtU,21811
11
12
  meshagent/agents/prompt.py,sha256=sidiyLLC6Lr9KO3cUTKttd2oROlcizle_4iKoaNrfhA,1864
12
13
  meshagent/agents/pydantic.py,sha256=My9sv1A56unA0qVoPSH-mYtxcgl0AKyxFgyOM70pjLM,6062
13
14
  meshagent/agents/single_shot_writer.py,sha256=QsGvTIw1qtp8nGLfzuJwdZj6ucY4cW9rdecqNwv83FA,3355
14
15
  meshagent/agents/thread_schema.py,sha256=-KGAMNxQsVuXpvc0avV-OYHe2LMXpjTu5PyQ-1nBnyE,2667
15
16
  meshagent/agents/utils.py,sha256=upMbvG4KODZijeTO3IdW4GgzFPz4jXTzNhZBDmtroic,1431
16
- meshagent/agents/version.py,sha256=NoiGDztYD4fsDDnfSPiSzRkknkNHhFUtKZj0mhQiTYM,22
17
- meshagent/agents/worker.py,sha256=3y7D59ea7c09bwMFAjw1SUspAxe1Gzsta7lzsoyJgKA,3901
17
+ meshagent/agents/version.py,sha256=sE45w-zCTIpVQyXYRbP5E390wIU6bNzRFuAh6ySoc1w,22
18
+ meshagent/agents/worker.py,sha256=G2Q3UpUCQQ8GtPK5_LW4q8uDOyuJXJM_zdRPsx4puck,3260
18
19
  meshagent/agents/writer.py,sha256=2Nk52JcjdRz3EnGBO4EHnv49QzByWiije1LKMNuCAIo,2687
19
20
  meshagent/agents/schemas/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
20
21
  meshagent/agents/schemas/document.py,sha256=GrHkyJ6ZsImqL33FnGKqjBmBpX4u2lAsUMLW4AzDHEM,1318
@@ -22,8 +23,8 @@ meshagent/agents/schemas/gallery.py,sha256=fzAdlDrn_dJz4FDPkSTH9ir7QmRpV8wFjj6RT
22
23
  meshagent/agents/schemas/presentation.py,sha256=DreBXAU7Lx92NBPTlEOZq1gdaRs0OkZrJgPT5N7fYH4,1265
23
24
  meshagent/agents/schemas/schema.py,sha256=O52T5nUGRNQ8AsamZ_W_IQ8WRDqSBo3vWFDSQcC7Lcg,4473
24
25
  meshagent/agents/schemas/super_editor_document.py,sha256=lFpbZn_s_6hchimddzpnGneJ7LaB6dTN_AnLZsx2r9c,1469
25
- meshagent_agents-0.0.22.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
26
- meshagent_agents-0.0.22.dist-info/METADATA,sha256=5XTwW4njBDDj7ZotG9hCM335klUWYsZ46CJXXI8h91M,1187
27
- meshagent_agents-0.0.22.dist-info/WHEEL,sha256=DnLRTWE75wApRYVsjgc6wsVswC54sMSJhAEd4xhDpBk,91
28
- meshagent_agents-0.0.22.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
29
- meshagent_agents-0.0.22.dist-info/RECORD,,
26
+ meshagent_agents-0.0.24.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
27
+ meshagent_agents-0.0.24.dist-info/METADATA,sha256=hlnWqDYCabQsCnWFJdUsKomagFPAoTLtAvxRCqOfAKE,1307
28
+ meshagent_agents-0.0.24.dist-info/WHEEL,sha256=zaaOINJESkSfm_4HQVc5ssNzHCPXhJm0kEUakpsEHaU,91
29
+ meshagent_agents-0.0.24.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
30
+ meshagent_agents-0.0.24.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.4.0)
2
+ Generator: setuptools (80.8.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5