fenix-mcp 0.5.6__py3-none-any.whl → 0.5.8__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.
- fenix_mcp/__init__.py +1 -1
- fenix_mcp/application/tools/intelligence.py +23 -0
- fenix_mcp/domain/intelligence.py +60 -38
- {fenix_mcp-0.5.6.dist-info → fenix_mcp-0.5.8.dist-info}/METADATA +1 -1
- {fenix_mcp-0.5.6.dist-info → fenix_mcp-0.5.8.dist-info}/RECORD +8 -8
- {fenix_mcp-0.5.6.dist-info → fenix_mcp-0.5.8.dist-info}/WHEEL +0 -0
- {fenix_mcp-0.5.6.dist-info → fenix_mcp-0.5.8.dist-info}/entry_points.txt +0 -0
- {fenix_mcp-0.5.6.dist-info → fenix_mcp-0.5.8.dist-info}/top_level.txt +0 -0
fenix_mcp/__init__.py
CHANGED
|
@@ -155,10 +155,21 @@ class IntelligenceTool(Tool):
|
|
|
155
155
|
async def _handle_smart_create(self, payload: IntelligenceRequest):
|
|
156
156
|
if not payload.title or not payload.content:
|
|
157
157
|
return text("❌ Informe título e conteúdo para criar uma memória.")
|
|
158
|
+
|
|
159
|
+
if not payload.metadata or not payload.metadata.strip():
|
|
160
|
+
return text("❌ Informe metadata para criar uma memória.")
|
|
161
|
+
|
|
162
|
+
if not payload.source or not payload.source.strip():
|
|
163
|
+
return text("❌ Informe source para criar uma memória.")
|
|
164
|
+
|
|
158
165
|
try:
|
|
159
166
|
normalized_tags = _ensure_tag_sequence(payload.tags)
|
|
160
167
|
except ValueError as exc:
|
|
161
168
|
return text(f"❌ {exc}")
|
|
169
|
+
|
|
170
|
+
if not normalized_tags or len(normalized_tags) == 0:
|
|
171
|
+
return text("❌ Informe tags para criar uma memória.")
|
|
172
|
+
|
|
162
173
|
memory = await self._service.smart_create_memory(
|
|
163
174
|
title=payload.title,
|
|
164
175
|
content=payload.content,
|
|
@@ -271,6 +282,7 @@ class IntelligenceTool(Tool):
|
|
|
271
282
|
payload.metadata,
|
|
272
283
|
importance=payload.importance,
|
|
273
284
|
tags=normalized_tags,
|
|
285
|
+
source=payload.source,
|
|
274
286
|
existing=existing.get("metadata") if isinstance(existing, dict) else None,
|
|
275
287
|
)
|
|
276
288
|
update_fields: Dict[str, Any] = {
|
|
@@ -330,6 +342,17 @@ def _ensure_tag_sequence(raw: Optional[Any]) -> Optional[List[str]]:
|
|
|
330
342
|
result = [str(item).strip() for item in raw if str(item).strip()]
|
|
331
343
|
return result or None
|
|
332
344
|
if isinstance(raw, str):
|
|
345
|
+
# Try to parse as JSON array first
|
|
346
|
+
try:
|
|
347
|
+
import json
|
|
348
|
+
|
|
349
|
+
parsed = json.loads(raw)
|
|
350
|
+
if isinstance(parsed, list):
|
|
351
|
+
result = [str(item).strip() for item in parsed if str(item).strip()]
|
|
352
|
+
return result or None
|
|
353
|
+
except (json.JSONDecodeError, TypeError):
|
|
354
|
+
pass
|
|
355
|
+
|
|
333
356
|
raise ValueError(
|
|
334
357
|
"O campo `tags` deve ser enviado como array JSON, por exemplo: "
|
|
335
358
|
'["tag1", "tag2"].'
|
fenix_mcp/domain/intelligence.py
CHANGED
|
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
|
|
6
6
|
import asyncio
|
|
7
7
|
from dataclasses import dataclass
|
|
8
|
-
from typing import Any, Dict, Iterable, List, Optional
|
|
8
|
+
from typing import Any, Dict, Iterable, List, Optional
|
|
9
9
|
|
|
10
10
|
from fenix_mcp.infrastructure.fenix_api.client import FenixApiClient
|
|
11
11
|
|
|
@@ -20,18 +20,34 @@ class IntelligenceService:
|
|
|
20
20
|
*,
|
|
21
21
|
title: str,
|
|
22
22
|
content: str,
|
|
23
|
-
metadata:
|
|
23
|
+
metadata: str,
|
|
24
24
|
context: Optional[str],
|
|
25
|
-
source:
|
|
25
|
+
source: str,
|
|
26
26
|
importance: str,
|
|
27
|
-
tags:
|
|
27
|
+
tags: List[str],
|
|
28
28
|
) -> Dict[str, Any]:
|
|
29
|
+
# Validate required parameters
|
|
30
|
+
if not metadata or not metadata.strip():
|
|
31
|
+
raise ValueError("metadata is required and cannot be empty")
|
|
32
|
+
|
|
33
|
+
if not source or not source.strip():
|
|
34
|
+
raise ValueError("source is required and cannot be empty")
|
|
35
|
+
|
|
36
|
+
if not tags or not isinstance(tags, list) or len(tags) == 0:
|
|
37
|
+
raise ValueError("tags is required and must be a non-empty List[str]")
|
|
38
|
+
|
|
39
|
+
# Validate all tags are strings
|
|
40
|
+
for i, tag in enumerate(tags):
|
|
41
|
+
if not isinstance(tag, str) or not tag.strip():
|
|
42
|
+
raise ValueError(
|
|
43
|
+
f"All tags must be non-empty strings, got {type(tag)} at index {i}"
|
|
44
|
+
)
|
|
45
|
+
|
|
29
46
|
importance_value = importance or "medium"
|
|
30
|
-
normalized_tags = normalize_tags(tags)
|
|
31
47
|
metadata_str = build_metadata(
|
|
32
48
|
metadata,
|
|
33
49
|
importance=importance_value,
|
|
34
|
-
tags=
|
|
50
|
+
tags=tags,
|
|
35
51
|
context=context,
|
|
36
52
|
source=source,
|
|
37
53
|
)
|
|
@@ -40,7 +56,7 @@ class IntelligenceService:
|
|
|
40
56
|
"content": content,
|
|
41
57
|
"metadata": metadata_str,
|
|
42
58
|
"priority_score": _importance_to_priority(importance_value),
|
|
43
|
-
"tags":
|
|
59
|
+
"tags": tags,
|
|
44
60
|
}
|
|
45
61
|
return await self._call(self.api.smart_create_memory, _strip_none(payload))
|
|
46
62
|
|
|
@@ -197,12 +213,12 @@ def _strip_none(data: Dict[str, Any]) -> Dict[str, Any]:
|
|
|
197
213
|
|
|
198
214
|
|
|
199
215
|
def build_metadata(
|
|
200
|
-
explicit:
|
|
216
|
+
explicit: str,
|
|
201
217
|
*,
|
|
202
218
|
importance: Optional[str],
|
|
203
|
-
tags:
|
|
219
|
+
tags: List[str],
|
|
204
220
|
context: Optional[str] = None,
|
|
205
|
-
source:
|
|
221
|
+
source: str,
|
|
206
222
|
existing: Optional[str] = None,
|
|
207
223
|
) -> str:
|
|
208
224
|
if explicit and explicit.strip():
|
|
@@ -259,31 +275,37 @@ def _slugify(value: Optional[str]) -> str:
|
|
|
259
275
|
return "-".join(part for part in sanitized.split() if part).lower()
|
|
260
276
|
|
|
261
277
|
|
|
262
|
-
def _format_tags(tags:
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
278
|
+
def _format_tags(tags: List[str]) -> str:
|
|
279
|
+
"""
|
|
280
|
+
Format tags list into a comma-separated string for metadata.
|
|
281
|
+
|
|
282
|
+
Args:
|
|
283
|
+
tags: List of string tags (required)
|
|
284
|
+
|
|
285
|
+
Returns:
|
|
286
|
+
Comma-separated string of tags
|
|
287
|
+
|
|
288
|
+
Raises:
|
|
289
|
+
TypeError: If tags is not a List[str]
|
|
290
|
+
ValueError: If tags is empty
|
|
291
|
+
"""
|
|
292
|
+
if not isinstance(tags, list):
|
|
293
|
+
raise TypeError(f"tags must be List[str], got {type(tags)}")
|
|
294
|
+
|
|
295
|
+
if not tags:
|
|
296
|
+
raise ValueError("tags cannot be empty")
|
|
297
|
+
|
|
298
|
+
# Clean and validate tags
|
|
299
|
+
cleaned_tags = []
|
|
300
|
+
for tag in tags:
|
|
301
|
+
if isinstance(tag, str) and tag.strip():
|
|
302
|
+
cleaned_tags.append(tag.strip())
|
|
303
|
+
else:
|
|
304
|
+
raise ValueError(
|
|
305
|
+
f"All tags must be non-empty strings, got {type(tag)}: {tag}"
|
|
306
|
+
)
|
|
307
|
+
|
|
308
|
+
if not cleaned_tags:
|
|
309
|
+
raise ValueError("No valid tags found after cleaning")
|
|
310
|
+
|
|
311
|
+
return ",".join(sorted(set(cleaned_tags)))
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
fenix_mcp/__init__.py,sha256=
|
|
1
|
+
fenix_mcp/__init__.py,sha256=M1F9ZYuoc3sexAMDAfEhKTIlIzuf38ZtbSzPeq48pPw,180
|
|
2
2
|
fenix_mcp/main.py,sha256=iJV-9btNMDJMObvcn7wBQdbLLKjkYCQ1ANGEwHGHlMU,2857
|
|
3
3
|
fenix_mcp/application/presenters.py,sha256=fGME54PdCDhTBhXO-JUB9yLdBHiE1aeXLTC2fCuxnxM,689
|
|
4
4
|
fenix_mcp/application/tool_base.py,sha256=qUcb46qx9gHQfrSHgj4RD4NCHW-OIvKQdR5G9uxZ5l4,1316
|
|
@@ -6,12 +6,12 @@ fenix_mcp/application/tool_registry.py,sha256=bPT5g8GfxG_qu28R1WaDOZHvtmG6TPDvZi
|
|
|
6
6
|
fenix_mcp/application/tools/__init__.py,sha256=Gi1YvYh-KdL9HD8gLVrknHrxiKKEOhHBEZ02KBXJaKQ,796
|
|
7
7
|
fenix_mcp/application/tools/health.py,sha256=m5DxhoRbdwl6INzd6PISxv1NAv-ljCrezsr773VB0wE,834
|
|
8
8
|
fenix_mcp/application/tools/initialize.py,sha256=f33DNDn9u8IYwpqiBj6bjJ-wHgaUP1zEuAvUM1rMYPc,4674
|
|
9
|
-
fenix_mcp/application/tools/intelligence.py,sha256=
|
|
9
|
+
fenix_mcp/application/tools/intelligence.py,sha256=WwJqWDkkdsh1oCub_WxAoCkPU0A2QyMaymVoWSKHbrY,14955
|
|
10
10
|
fenix_mcp/application/tools/knowledge.py,sha256=4ClGoFRqyFIPuzzg2DAg-w2eMvTP37mH0THXDGftinw,44634
|
|
11
11
|
fenix_mcp/application/tools/productivity.py,sha256=2IMkNdZ-Kd1CFAO7geruAVjtf_BWoDdbnwkl76vhtC8,9973
|
|
12
12
|
fenix_mcp/application/tools/user_config.py,sha256=8mPOZuwszO0TapxgrA7Foe15VQE874_mvfQYlGzyv4Y,6230
|
|
13
13
|
fenix_mcp/domain/initialization.py,sha256=AZhdSNITQ7O3clELBuqGvjJc-c8pFKc7zQz-XR2xXPc,6933
|
|
14
|
-
fenix_mcp/domain/intelligence.py,sha256=
|
|
14
|
+
fenix_mcp/domain/intelligence.py,sha256=2V70uZygyMcukHS4hVinkB-20VokGOw1gQR7jziX9-M,9515
|
|
15
15
|
fenix_mcp/domain/knowledge.py,sha256=fKQOTt20u5aa5Yo7gPeQ1Qxa_K5pBxn1yn8FEfOFltM,20241
|
|
16
16
|
fenix_mcp/domain/productivity.py,sha256=nmHRuVJGRRu1s4eMoAv8vXHKsSauCPl-FvFx3I_yCTE,6661
|
|
17
17
|
fenix_mcp/domain/user_config.py,sha256=LzBDCk31gLMtKHTbBmYb9VoFPHDW6OydpmDXeHHd0Mw,1642
|
|
@@ -22,8 +22,8 @@ fenix_mcp/infrastructure/logging.py,sha256=bHrWlSi_0HshRe3--BK_5nzUszW-gh37q6jsd
|
|
|
22
22
|
fenix_mcp/infrastructure/fenix_api/client.py,sha256=Navi7cGAOradghcbYkFIQQINpjFrdINlNhdfZ4iSSYQ,28338
|
|
23
23
|
fenix_mcp/interface/mcp_server.py,sha256=5UM2NJuNbwHkmCEprIFataJ5nFZiO8efTtP_oW3_iX0,2331
|
|
24
24
|
fenix_mcp/interface/transports.py,sha256=PxdhfjH8UMl03f7nuCLc-M6tMx6-Y-btVz_mSqXKrSI,8138
|
|
25
|
-
fenix_mcp-0.5.
|
|
26
|
-
fenix_mcp-0.5.
|
|
27
|
-
fenix_mcp-0.5.
|
|
28
|
-
fenix_mcp-0.5.
|
|
29
|
-
fenix_mcp-0.5.
|
|
25
|
+
fenix_mcp-0.5.8.dist-info/METADATA,sha256=0j10_pcGqJTS4YeWVgso-tcOrQ0wU_lwldkHtuJT2wA,7260
|
|
26
|
+
fenix_mcp-0.5.8.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
27
|
+
fenix_mcp-0.5.8.dist-info/entry_points.txt,sha256=o52x_YHBupEd-1Z1GSfUjv3gJrx5_I-EkHhCgt1WBaE,49
|
|
28
|
+
fenix_mcp-0.5.8.dist-info/top_level.txt,sha256=2G1UtKpwjaIGQyE7sRoHecxaGLeuexfjrOUjv9DDKh4,10
|
|
29
|
+
fenix_mcp-0.5.8.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|