meshagent-tools 0.20.3__py3-none-any.whl → 0.20.4__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.
@@ -91,7 +91,7 @@ class DeleteRowsTool(Tool):
91
91
  super().__init__(
92
92
  name=f"delete_{table}_rows",
93
93
  title=f"delete {table} rows",
94
- description=f"search {table} table for rows with the specified values (specify null for a column to exclude it from the search) and then delete them",
94
+ description=f"delete from {table} where rows match the specified values (specify null for a column to exclude it from the search)",
95
95
  input_schema=input_schema,
96
96
  )
97
97
 
@@ -179,7 +179,7 @@ class SearchTool(Tool):
179
179
  self.table = table
180
180
  self.namespace = namespace
181
181
 
182
- input_schema = {
182
+ query = {
183
183
  "type": "object",
184
184
  "required": [],
185
185
  "additionalProperties": False,
@@ -187,9 +187,28 @@ class SearchTool(Tool):
187
187
  }
188
188
 
189
189
  for k, v in schema.items():
190
- input_schema["required"].append(k)
191
- input_schema["properties"][k] = v.to_json_schema()
190
+ query["required"].append(k)
191
+ query["properties"][k] = v.to_json_schema()
192
192
 
193
+ input_schema = {
194
+ "type": "object",
195
+ "required": ["query", "limit", "offset", "select"],
196
+ "additionalProperties": False,
197
+ "properties": {
198
+ "query": query,
199
+ "select": {
200
+ "type": "array",
201
+ "description": f"the columns to return, available columns: {','.join(schema.keys())}",
202
+ "items": {
203
+ "type": "string",
204
+ },
205
+ },
206
+ "limit": {"type": "integer"},
207
+ "offset": {"type": "integer"},
208
+ },
209
+ }
210
+
211
+ print(input_schema)
193
212
  super().__init__(
194
213
  name=f"search_{table}",
195
214
  title=f"search {table}",
@@ -197,15 +216,79 @@ class SearchTool(Tool):
197
216
  input_schema=input_schema,
198
217
  )
199
218
 
200
- async def execute(self, context: ToolContext, **values):
219
+ async def execute(
220
+ self,
221
+ context: ToolContext,
222
+ query: object,
223
+ limit: int,
224
+ offset: int,
225
+ select: list[str],
226
+ ):
201
227
  search = {}
202
228
 
203
- for k, v in values.items():
229
+ for k, v in query.items():
204
230
  if v is not None:
205
231
  search[k] = v
206
232
 
207
233
  return {
208
234
  "rows": await context.room.database.search(
235
+ select=select,
236
+ table=self.table,
237
+ where=search if len(search) > 0 else None,
238
+ namespace=self.namespace,
239
+ offset=offset,
240
+ limit=limit,
241
+ )
242
+ }
243
+
244
+
245
+ class CountTool(Tool):
246
+ def __init__(
247
+ self,
248
+ *,
249
+ table: str,
250
+ schema: dict[str, DataType],
251
+ namespace: Optional[list[str]] = None,
252
+ ):
253
+ self.table = table
254
+ self.namespace = namespace
255
+
256
+ query = {
257
+ "type": "object",
258
+ "required": [],
259
+ "additionalProperties": False,
260
+ "properties": {},
261
+ }
262
+
263
+ input_schema = {
264
+ "type": "object",
265
+ "required": ["query"],
266
+ "additionalProperties": False,
267
+ "properties": {
268
+ "query": query,
269
+ },
270
+ }
271
+
272
+ for k, v in schema.items():
273
+ query["required"].append(k)
274
+ query["properties"][k] = v.to_json_schema()
275
+
276
+ super().__init__(
277
+ name=f"count_{table}",
278
+ title=f"count_{table}",
279
+ description=f"count matching rows in the {table} table",
280
+ input_schema=input_schema,
281
+ )
282
+
283
+ async def execute(self, context: ToolContext, query: object):
284
+ search = {}
285
+
286
+ for k, v in query.items():
287
+ if v is not None:
288
+ search[k] = v
289
+
290
+ return {
291
+ "rows": await context.room.database.count(
209
292
  table=self.table,
210
293
  where=search if len(search) > 0 else None,
211
294
  namespace=self.namespace,
@@ -326,6 +409,7 @@ class DatabaseToolkit(RemoteToolkit):
326
409
  )
327
410
  )
328
411
 
412
+ tools.append(CountTool(table=table, schema=schema, namespace=namespace))
329
413
  tools.append(SearchTool(table=table, schema=schema, namespace=namespace))
330
414
  tools.append(
331
415
  AdvancedSearchTool(table=table, schema=schema, namespace=namespace)
@@ -0,0 +1,535 @@
1
+ from datetime import datetime, timedelta, timezone
2
+ from typing import Any, Literal, Optional
3
+ from zoneinfo import ZoneInfo
4
+ from .config import ToolkitConfig
5
+ from .tool import Tool
6
+ from .toolkit import ToolContext, ToolkitBuilder
7
+ from .hosting import RemoteToolkit, Toolkit
8
+ from meshagent.api.room_server_client import RoomClient
9
+
10
+
11
+ # ----------------------------
12
+ # Helpers
13
+ # ----------------------------
14
+
15
+
16
+ def _now_utc() -> datetime:
17
+ return datetime.now(timezone.utc)
18
+
19
+
20
+ def _get_tz(tz: Optional[str]) -> timezone:
21
+ """
22
+ Returns a tzinfo. If tz is None -> UTC.
23
+ If tz is provided, uses zoneinfo when available; falls back to UTC if unknown.
24
+ """
25
+ if not tz:
26
+ return timezone.utc
27
+ if ZoneInfo is None:
28
+ # zoneinfo not available; safest fallback
29
+ return timezone.utc
30
+ try:
31
+ return ZoneInfo(tz) # type: ignore[arg-type]
32
+ except Exception:
33
+ return timezone.utc
34
+
35
+
36
+ def _ensure_aware(dt: datetime, tz: Optional[str] = None) -> datetime:
37
+ """
38
+ If dt is naive, interpret it in tz (or UTC if tz not provided) and make aware.
39
+ If aware, leave as-is.
40
+ """
41
+ if dt.tzinfo is None:
42
+ return dt.replace(tzinfo=_get_tz(tz))
43
+ return dt
44
+
45
+
46
+ def _to_tz(dt: datetime, tz: Optional[str]) -> datetime:
47
+ dt = _ensure_aware(dt, tz=None)
48
+ return dt.astimezone(_get_tz(tz))
49
+
50
+
51
+ def _iso(dt: datetime) -> str:
52
+ """
53
+ Canonical DB-friendly ISO with offset.
54
+ """
55
+ dt = _ensure_aware(dt)
56
+ # Keep offset; many DBs accept it; if you prefer 'Z', format_utc tool handles that.
57
+ return dt.isoformat()
58
+
59
+
60
+ def _parse_iso(s: str, assume_tz: Optional[str] = None) -> datetime:
61
+ """
62
+ Parse ISO-8601-ish strings. If it ends with 'Z', treat as UTC.
63
+ If parsed datetime is naive, attach assume_tz (or UTC).
64
+ """
65
+ s2 = s.strip()
66
+ if s2.endswith("Z"):
67
+ s2 = s2[:-1] + "+00:00"
68
+ dt = datetime.fromisoformat(s2)
69
+ return _ensure_aware(dt, assume_tz)
70
+
71
+
72
+ def _start_of_day(dt: datetime) -> datetime:
73
+ dt = _ensure_aware(dt)
74
+ return dt.replace(hour=0, minute=0, second=0, microsecond=0)
75
+
76
+
77
+ def _end_of_day(dt: datetime) -> datetime:
78
+ # inclusive end: 23:59:59.999999
79
+ dt = _ensure_aware(dt)
80
+ return dt.replace(hour=23, minute=59, second=59, microsecond=999999)
81
+
82
+
83
+ def _start_of_month(dt: datetime) -> datetime:
84
+ dt = _ensure_aware(dt)
85
+ return dt.replace(day=1, hour=0, minute=0, second=0, microsecond=0)
86
+
87
+
88
+ def _end_of_month(dt: datetime) -> datetime:
89
+ dt = _ensure_aware(dt)
90
+ # go to first of next month then subtract a microsecond
91
+ if dt.month == 12:
92
+ nxt = dt.replace(
93
+ year=dt.year + 1, month=1, day=1, hour=0, minute=0, second=0, microsecond=0
94
+ )
95
+ else:
96
+ nxt = dt.replace(
97
+ month=dt.month + 1, day=1, hour=0, minute=0, second=0, microsecond=0
98
+ )
99
+ return nxt - timedelta(microseconds=1)
100
+
101
+
102
+ def _start_of_week(dt: datetime, week_start: int) -> datetime:
103
+ """
104
+ week_start: 0=Mon ... 6=Sun
105
+ """
106
+ dt = _ensure_aware(dt)
107
+ # Python weekday(): Mon=0..Sun=6
108
+ delta_days = (dt.weekday() - week_start) % 7
109
+ return _start_of_day(dt - timedelta(days=delta_days))
110
+
111
+
112
+ def _end_of_week(dt: datetime, week_start: int) -> datetime:
113
+ return (
114
+ _start_of_week(dt, week_start) + timedelta(days=7) - timedelta(microseconds=1)
115
+ )
116
+
117
+
118
+ # ----------------------------
119
+ # Tools
120
+ # ----------------------------
121
+
122
+
123
+ class NowTool(Tool):
124
+ def __init__(self):
125
+ super().__init__(
126
+ name="now",
127
+ title="now",
128
+ description="Get current time. Returns both UTC and (optional) timezone-local ISO strings.",
129
+ input_schema={
130
+ "type": "object",
131
+ "required": ["tz"],
132
+ "additionalProperties": False,
133
+ "properties": {
134
+ "tz": {
135
+ "type": ["string", "null"],
136
+ "description": "IANA timezone name (e.g. 'America/Los_Angeles'). If omitted, only UTC is returned.",
137
+ }
138
+ },
139
+ },
140
+ )
141
+
142
+ async def execute(self, context: ToolContext, tz: Optional[str] = None):
143
+ utc = _now_utc()
144
+ out: dict[str, Any] = {"utc": _iso(utc)}
145
+ if tz:
146
+ out["local"] = _iso(_to_tz(utc, tz))
147
+ out["tz"] = tz
148
+ return out
149
+
150
+
151
+ class TodayTool(Tool):
152
+ def __init__(self):
153
+ super().__init__(
154
+ name="today_range",
155
+ title="today range",
156
+ description="Get the start/end of 'today' in a given timezone (defaults to UTC). Useful for date filters.",
157
+ input_schema={
158
+ "type": "object",
159
+ "required": ["tz"],
160
+ "additionalProperties": False,
161
+ "properties": {
162
+ "tz": {
163
+ "type": ["string", "null"],
164
+ "description": "IANA timezone name (default UTC).",
165
+ },
166
+ },
167
+ },
168
+ )
169
+
170
+ async def execute(self, context: ToolContext, tz: Optional[str] = None):
171
+ base = _to_tz(_now_utc(), tz)
172
+ start = _start_of_day(base)
173
+ end = _end_of_day(base)
174
+ return {"start": _iso(start), "end": _iso(end), "tz": tz or "UTC"}
175
+
176
+
177
+ class WeekRangeTool(Tool):
178
+ def __init__(self):
179
+ super().__init__(
180
+ name="week_range",
181
+ title="week range",
182
+ description="Get start/end of the week containing a given datetime (or now), in a timezone. Week start configurable.",
183
+ input_schema={
184
+ "type": "object",
185
+ "required": ["dt", "tz", "week_start"],
186
+ "additionalProperties": False,
187
+ "properties": {
188
+ "dt": {
189
+ "type": ["string", "null"],
190
+ "description": "ISO datetime. If omitted, uses now.",
191
+ },
192
+ "tz": {
193
+ "type": ["string", "null"],
194
+ "description": "IANA timezone name (default UTC).",
195
+ },
196
+ "week_start": {
197
+ "type": "integer",
198
+ "description": "0=Mon .. 6=Sun (default 0).",
199
+ "minimum": 0,
200
+ "maximum": 6,
201
+ },
202
+ },
203
+ },
204
+ )
205
+
206
+ async def execute(
207
+ self,
208
+ context: ToolContext,
209
+ dt: Optional[str] = None,
210
+ tz: Optional[str] = None,
211
+ week_start: int = 0,
212
+ ):
213
+ base = _to_tz(_parse_iso(dt, assume_tz=tz) if dt else _now_utc(), tz)
214
+ start = _start_of_week(base, week_start)
215
+ end = _end_of_week(base, week_start)
216
+ iso_year, iso_week, iso_wday = base.isocalendar()
217
+ return {
218
+ "start": _iso(start),
219
+ "end": _iso(end),
220
+ "tz": tz or "UTC",
221
+ "week_start": week_start,
222
+ "iso": {"year": iso_year, "week": iso_week, "weekday": iso_wday},
223
+ }
224
+
225
+
226
+ class MonthRangeTool(Tool):
227
+ def __init__(self):
228
+ super().__init__(
229
+ name="month_range",
230
+ title="month range",
231
+ description="Get start/end of the month containing a given datetime (or now), in a timezone.",
232
+ input_schema={
233
+ "type": "object",
234
+ "required": ["dt", "tz"],
235
+ "additionalProperties": False,
236
+ "properties": {
237
+ "dt": {
238
+ "type": ["string", "null"],
239
+ "description": "ISO datetime. If omitted, uses now.",
240
+ },
241
+ "tz": {
242
+ "type": ["string", "null"],
243
+ "description": "IANA timezone name (default UTC).",
244
+ },
245
+ },
246
+ },
247
+ )
248
+
249
+ async def execute(
250
+ self, context: ToolContext, dt: Optional[str] = None, tz: Optional[str] = None
251
+ ):
252
+ base = _to_tz(_parse_iso(dt, assume_tz=tz) if dt else _now_utc(), tz)
253
+ start = _start_of_month(base)
254
+ end = _end_of_month(base)
255
+ return {
256
+ "start": _iso(start),
257
+ "end": _iso(end),
258
+ "tz": tz or "UTC",
259
+ "year": base.year,
260
+ "month": base.month,
261
+ }
262
+
263
+
264
+ class AddDurationTool(Tool):
265
+ def __init__(self):
266
+ super().__init__(
267
+ name="add_duration",
268
+ title="add duration",
269
+ description="Add a duration to an ISO datetime. Supports days/hours/minutes/seconds.",
270
+ input_schema={
271
+ "type": "object",
272
+ "required": ["dt", "tz", "days", "hours", "minutes", "seconds"],
273
+ "additionalProperties": False,
274
+ "properties": {
275
+ "dt": {"type": "string", "description": "Base ISO datetime."},
276
+ "tz": {
277
+ "type": ["string", "null"],
278
+ "description": "IANA timezone name. If dt is naive, interpret it in this timezone (default UTC). Also controls output tz.",
279
+ },
280
+ "days": {"type": "integer"},
281
+ "hours": {"type": "integer"},
282
+ "minutes": {"type": "integer"},
283
+ "seconds": {"type": "integer"},
284
+ },
285
+ },
286
+ )
287
+
288
+ async def execute(
289
+ self,
290
+ context: ToolContext,
291
+ *,
292
+ dt: str,
293
+ tz: Optional[str] = None,
294
+ days: int = 0,
295
+ hours: int = 0,
296
+ minutes: int = 0,
297
+ seconds: int = 0,
298
+ ):
299
+ base = _parse_iso(dt, assume_tz=tz)
300
+ base = _to_tz(base, tz)
301
+ out = base + timedelta(days=days, hours=hours, minutes=minutes, seconds=seconds)
302
+ return {"dt": _iso(out), "tz": tz or "UTC"}
303
+
304
+
305
+ class DiffTool(Tool):
306
+ def __init__(self):
307
+ super().__init__(
308
+ name="diff",
309
+ title="diff",
310
+ description="Compute dt2 - dt1. Returns seconds, and a simple breakdown.",
311
+ input_schema={
312
+ "type": "object",
313
+ "required": ["dt1", "dt2", "assume_tz"],
314
+ "additionalProperties": False,
315
+ "properties": {
316
+ "dt1": {"type": "string", "description": "ISO datetime 1."},
317
+ "dt2": {"type": "string", "description": "ISO datetime 2."},
318
+ "assume_tz": {
319
+ "type": ["string", "null"],
320
+ "description": "IANA timezone name. If either input is naive, interpret it in this timezone (default UTC).",
321
+ },
322
+ },
323
+ },
324
+ )
325
+
326
+ async def execute(
327
+ self,
328
+ context: ToolContext,
329
+ *,
330
+ dt1: str,
331
+ dt2: str,
332
+ assume_tz: Optional[str] = None,
333
+ ):
334
+ a = _parse_iso(dt1, assume_tz=assume_tz)
335
+ b = _parse_iso(dt2, assume_tz=assume_tz)
336
+ delta = b - a
337
+ total_seconds = int(delta.total_seconds())
338
+ sign = -1 if total_seconds < 0 else 1
339
+ secs = abs(total_seconds)
340
+
341
+ days, rem = divmod(secs, 86400)
342
+ hours, rem = divmod(rem, 3600)
343
+ minutes, seconds = divmod(rem, 60)
344
+
345
+ return {
346
+ "seconds": total_seconds,
347
+ "breakdown": {
348
+ "sign": sign,
349
+ "days": days,
350
+ "hours": hours,
351
+ "minutes": minutes,
352
+ "seconds": seconds,
353
+ },
354
+ }
355
+
356
+
357
+ class ParseTool(Tool):
358
+ def __init__(self):
359
+ super().__init__(
360
+ name="parse_iso",
361
+ title="parse iso datetime",
362
+ description="Parse an ISO datetime string and return normalized ISO plus components.",
363
+ input_schema={
364
+ "type": "object",
365
+ "required": ["dt", "assume_tz", "tz"],
366
+ "additionalProperties": False,
367
+ "properties": {
368
+ "dt": {
369
+ "type": "string",
370
+ "description": "ISO datetime (accepts trailing 'Z').",
371
+ },
372
+ "assume_tz": {
373
+ "type": ["string", "null"],
374
+ "description": "IANA timezone name. If dt is naive, interpret it in this timezone (default UTC).",
375
+ },
376
+ "tz": {
377
+ "type": ["string", "null"],
378
+ "description": "IANA timezone name. Convert output to this timezone (default keep parsed tz).",
379
+ },
380
+ },
381
+ },
382
+ )
383
+
384
+ async def execute(
385
+ self,
386
+ context: ToolContext,
387
+ *,
388
+ dt: str,
389
+ assume_tz: Optional[str] = None,
390
+ tz: Optional[str] = None,
391
+ ):
392
+ parsed = _parse_iso(dt, assume_tz=assume_tz)
393
+ if tz:
394
+ parsed = _to_tz(parsed, tz)
395
+ iso_year, iso_week, iso_wday = parsed.isocalendar()
396
+ return {
397
+ "iso": _iso(parsed),
398
+ "components": {
399
+ "year": parsed.year,
400
+ "month": parsed.month,
401
+ "day": parsed.day,
402
+ "hour": parsed.hour,
403
+ "minute": parsed.minute,
404
+ "second": parsed.second,
405
+ "microsecond": parsed.microsecond,
406
+ },
407
+ "weekday": parsed.weekday(), # Mon=0..Sun=6
408
+ "iso_week": {"year": iso_year, "week": iso_week, "weekday": iso_wday},
409
+ "tz": str(parsed.tzinfo),
410
+ }
411
+
412
+
413
+ class FormatTool(Tool):
414
+ def __init__(self):
415
+ super().__init__(
416
+ name="format_dt",
417
+ title="format datetime",
418
+ description="Format an ISO datetime using strftime. (Use for human-readable strings.)",
419
+ input_schema={
420
+ "type": "object",
421
+ "required": ["dt", "fmt", "assume_tz", "tz"],
422
+ "additionalProperties": False,
423
+ "properties": {
424
+ "dt": {"type": "string", "description": "ISO datetime."},
425
+ "fmt": {
426
+ "type": "string",
427
+ "description": "strftime format string, e.g. '%Y-%m-%d %H:%M:%S'.",
428
+ },
429
+ "assume_tz": {
430
+ "type": ["string", "null"],
431
+ "description": "IANA timezone name. If dt is naive, interpret it in this timezone (default UTC).",
432
+ },
433
+ "tz": {
434
+ "type": ["string", "null"],
435
+ "description": "IANA timezone name. Convert before formatting (default: keep).",
436
+ },
437
+ },
438
+ },
439
+ )
440
+
441
+ async def execute(
442
+ self,
443
+ context: ToolContext,
444
+ *,
445
+ dt: str,
446
+ fmt: str,
447
+ assume_tz: Optional[str] = None,
448
+ tz: Optional[str] = None,
449
+ ):
450
+ parsed = _parse_iso(dt, assume_tz=assume_tz)
451
+ if tz:
452
+ parsed = _to_tz(parsed, tz)
453
+ return {"text": parsed.strftime(fmt)}
454
+
455
+
456
+ class UtcZTool(Tool):
457
+ def __init__(self):
458
+ super().__init__(
459
+ name="to_utc_z",
460
+ title="to utc Z",
461
+ description="Convert an ISO datetime to UTC and return an RFC3339-ish Z string (e.g. 2026-01-11T12:34:56Z).",
462
+ input_schema={
463
+ "type": "object",
464
+ "required": ["dt", "assume_tz", "drop_microseconds"],
465
+ "additionalProperties": False,
466
+ "properties": {
467
+ "dt": {"type": "string", "description": "ISO datetime."},
468
+ "assume_tz": {
469
+ "type": ["string", "null"],
470
+ "description": "IANA timezone name. If dt is naive, interpret it in this timezone (default UTC).",
471
+ },
472
+ "drop_microseconds": {
473
+ "type": "boolean",
474
+ "description": "Default true.",
475
+ },
476
+ },
477
+ },
478
+ )
479
+
480
+ async def execute(
481
+ self,
482
+ context: ToolContext,
483
+ *,
484
+ dt: str,
485
+ assume_tz: Optional[str] = None,
486
+ drop_microseconds: bool = True,
487
+ ):
488
+ parsed = _parse_iso(dt, assume_tz=assume_tz)
489
+ u = parsed.astimezone(timezone.utc)
490
+ if drop_microseconds:
491
+ u = u.replace(microsecond=0)
492
+ # emit Z
493
+ s = u.isoformat().replace("+00:00", "Z")
494
+ return {"dt": s}
495
+
496
+
497
+ # ----------------------------
498
+ # Toolkit
499
+ # ----------------------------
500
+
501
+
502
+ class DatetimeToolkit(RemoteToolkit):
503
+ def __init__(self):
504
+ tools = [
505
+ NowTool(),
506
+ TodayTool(),
507
+ WeekRangeTool(),
508
+ MonthRangeTool(),
509
+ AddDurationTool(),
510
+ DiffTool(),
511
+ ParseTool(),
512
+ FormatTool(),
513
+ UtcZTool(),
514
+ ]
515
+ super().__init__(
516
+ name="datetime",
517
+ title="datetime",
518
+ description="Useful datetime utilities: now/ranges/parse/format/add/diff",
519
+ tools=tools,
520
+ )
521
+
522
+
523
+ class DatetimeToolkitConfig(ToolkitConfig):
524
+ name: Literal["datetime"] = "datetime"
525
+
526
+
527
+ class DatetimeToolkitBuilder(ToolkitBuilder):
528
+ def __init__(self):
529
+ super().__init__(name="datetime", type=DatetimeToolkitConfig)
530
+
531
+ async def make(
532
+ self, *, room: RoomClient, model: str, config: DatetimeToolkitConfig
533
+ ) -> Toolkit:
534
+ # no room dependency required; purely local computations
535
+ return DatetimeToolkit()
@@ -0,0 +1,43 @@
1
+ import uuid
2
+ from .tool import Tool
3
+ from .toolkit import ToolContext
4
+ from .hosting import RemoteToolkit
5
+
6
+
7
+ class UuidV4Tool(Tool):
8
+ def __init__(self):
9
+ super().__init__(
10
+ name="uuid_v4",
11
+ title="uuid v4",
12
+ description="Generate UUIDv4 strings (standard 8-4-4-4-12 format).",
13
+ input_schema={
14
+ "type": "object",
15
+ "required": ["count"],
16
+ "additionalProperties": False,
17
+ "properties": {
18
+ "count": {
19
+ "type": "integer",
20
+ "description": "How many UUIDs to generate (default 1).",
21
+ },
22
+ },
23
+ },
24
+ )
25
+
26
+ async def execute(self, context: ToolContext, *, count: int = 1):
27
+ # uuid.uuid4() returns a UUID object; str(...) yields canonical form:
28
+ # xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
29
+ uuids = [str(uuid.uuid4()) for _ in range(int(count or 1))]
30
+ if count == 1:
31
+ return {"uuid": uuids[0]}
32
+ return {"uuids": uuids, "count": len(uuids)}
33
+
34
+
35
+ class UUIDToolkit(RemoteToolkit):
36
+ def __init__(self):
37
+ tools = [UuidV4Tool()]
38
+ super().__init__(
39
+ name="uuid",
40
+ title="uuid",
41
+ description="Generate uuids",
42
+ tools=tools,
43
+ )
@@ -1 +1 @@
1
- __version__ = "0.20.3"
1
+ __version__ = "0.20.4"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: meshagent-tools
3
- Version: 0.20.3
3
+ Version: 0.20.4
4
4
  Summary: Tools for Meshagent
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: Documentation, https://docs.meshagent.com
@@ -12,7 +12,7 @@ License-File: LICENSE
12
12
  Requires-Dist: pyjwt~=2.10
13
13
  Requires-Dist: pytest~=8.4
14
14
  Requires-Dist: pytest-asyncio~=0.26
15
- Requires-Dist: meshagent-api~=0.20.3
15
+ Requires-Dist: meshagent-api~=0.20.4
16
16
  Requires-Dist: aiohttp~=3.10
17
17
  Requires-Dist: opentelemetry-distro~=0.54b1
18
18
  Dynamic: license-file
@@ -1,7 +1,8 @@
1
1
  meshagent/tools/__init__.py,sha256=1zgD5OvAJP10eERoE72VbDu9hFVfAqCWUXw3SiCYFTE,1285
2
2
  meshagent/tools/blob.py,sha256=aDW_z8R4HrmrYzAWoWm13Ypqcxcl4rL1Dc0ESnQETLM,1473
3
3
  meshagent/tools/config.py,sha256=zH2xGxg28K7Tg-aYor6LXdzf0LRxS9iE0679H1FuWhE,79
4
- meshagent/tools/database.py,sha256=UMH0_qNZsWqHvI7NFXwWJUADbiOM5AnMYyi0gJtwM7U,10631
4
+ meshagent/tools/database.py,sha256=TXy7L7_0IxjKM9TqZlx8om4SP_bTjTWqPfNosljb0kE,12910
5
+ meshagent/tools/datetime.py,sha256=2pOUOWopYIsc5y4EoFo_1PdBaBcTSkeOOs_EqdqYTk0,17503
5
6
  meshagent/tools/discovery.py,sha256=GZcC4XCgk0ftcYCBxuWlaIsLV5vU4-gXiu0HhlDUlwY,1861
6
7
  meshagent/tools/document_tools.py,sha256=LMULXOSBjsvhKjqzxUxe8586t0Vol0v1Btu5v6ofm7A,11755
7
8
  meshagent/tools/hosting.py,sha256=l1BCgnSrCJQsWU9Kycq3hEI4ZlYxffDfde6QeJUfko0,10678
@@ -11,10 +12,11 @@ meshagent/tools/storage.py,sha256=Y79G__Mp4swJ3tnm-zXtD-SqDeKU9kqHEVoUQH_QedA,72
11
12
  meshagent/tools/strict_schema.py,sha256=IytdAANa6lsfrsg5FsJuqYrxH9D_fayl-Lc9EwgLJSM,6277
12
13
  meshagent/tools/tool.py,sha256=9OAlbfaHqfgJnCDBSW-8PS0Z1K1KjWGD3JBUyiHOxAk,3131
13
14
  meshagent/tools/toolkit.py,sha256=rCCkpQBoSkmmhjnRGA4jx0QP-ds6WTJ0PkQVnf1Ls7s,3843
14
- meshagent/tools/version.py,sha256=gbf7freb96tMI3GZmlo8Yd1Od2bGCv9ECLz-l6H8pns,23
15
+ meshagent/tools/uuid.py,sha256=mzRwDmXy39U5lHhd9wqV4r-ZdS8jPfDTTs4UfW4KHJQ,1342
16
+ meshagent/tools/version.py,sha256=8BDEBRu96nHUJh0tYmos3SRV4xNzQNFZYR61tRE85tQ,23
15
17
  meshagent/tools/web_toolkit.py,sha256=IoOYjOBmcbQsqWT14xYg02jjWpWmGOkDSxt2U-LQoaA,1258
16
- meshagent_tools-0.20.3.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
17
- meshagent_tools-0.20.3.dist-info/METADATA,sha256=vBp_nbBLh7rfUYcERxMfyDipU7QAHyK5gmJFWsupUkI,2878
18
- meshagent_tools-0.20.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
19
- meshagent_tools-0.20.3.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
20
- meshagent_tools-0.20.3.dist-info/RECORD,,
18
+ meshagent_tools-0.20.4.dist-info/licenses/LICENSE,sha256=eTt0SPW-sVNdkZe9PS_S8WfCIyLjRXRl7sUBWdlteFg,10254
19
+ meshagent_tools-0.20.4.dist-info/METADATA,sha256=oxxgXJEDdBwB6MY6j5u8ZmlCorTdDux_hF18U_KAsdU,2878
20
+ meshagent_tools-0.20.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
21
+ meshagent_tools-0.20.4.dist-info/top_level.txt,sha256=GlcXnHtRP6m7zlG3Df04M35OsHtNXy_DY09oFwWrH74,10
22
+ meshagent_tools-0.20.4.dist-info/RECORD,,