fenix-mcp 0.7.0__py3-none-any.whl → 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.
- fenix_mcp/__init__.py +1 -1
- fenix_mcp/application/tools/initialize.py +15 -20
- fenix_mcp/application/tools/intelligence.py +71 -75
- fenix_mcp/application/tools/knowledge.py +272 -313
- fenix_mcp/application/tools/productivity.py +51 -51
- fenix_mcp/application/tools/user_config.py +32 -32
- fenix_mcp/domain/knowledge.py +43 -48
- fenix_mcp/domain/user_config.py +10 -2
- fenix_mcp/infrastructure/fenix_api/client.py +28 -44
- {fenix_mcp-0.7.0.dist-info → fenix_mcp-1.0.0.dist-info}/METADATA +1 -1
- {fenix_mcp-0.7.0.dist-info → fenix_mcp-1.0.0.dist-info}/RECORD +14 -14
- {fenix_mcp-0.7.0.dist-info → fenix_mcp-1.0.0.dist-info}/WHEEL +0 -0
- {fenix_mcp-0.7.0.dist-info → fenix_mcp-1.0.0.dist-info}/entry_points.txt +0 -0
- {fenix_mcp-0.7.0.dist-info → fenix_mcp-1.0.0.dist-info}/top_level.txt +0 -0
|
@@ -39,90 +39,93 @@ class KnowledgeAction(str, Enum):
|
|
|
39
39
|
# Work items
|
|
40
40
|
WORK_CREATE = (
|
|
41
41
|
"work_create",
|
|
42
|
-
"
|
|
42
|
+
"Creates a work item with title, status and optional links.",
|
|
43
43
|
)
|
|
44
44
|
WORK_LIST = (
|
|
45
45
|
"work_list",
|
|
46
|
-
"
|
|
46
|
+
"Lists work items with status, priority and context filters.",
|
|
47
47
|
)
|
|
48
|
-
WORK_GET = ("work_get", "
|
|
48
|
+
WORK_GET = ("work_get", "Gets full details of a work item by ID.")
|
|
49
49
|
WORK_UPDATE = (
|
|
50
50
|
"work_update",
|
|
51
|
-
"
|
|
51
|
+
"Updates specific fields of an existing work item.",
|
|
52
52
|
)
|
|
53
|
-
WORK_DELETE = ("work_delete", "
|
|
54
|
-
WORK_BACKLOG = ("work_backlog", "
|
|
55
|
-
WORK_SEARCH = (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
53
|
+
WORK_DELETE = ("work_delete", "Permanently removes a work item.")
|
|
54
|
+
WORK_BACKLOG = ("work_backlog", "Lists backlog items for a team.")
|
|
55
|
+
WORK_SEARCH = (
|
|
56
|
+
"work_search",
|
|
57
|
+
"Searches work items by text with additional filters.",
|
|
58
|
+
)
|
|
59
|
+
WORK_ANALYTICS = ("work_analytics", "Returns consolidated work item metrics.")
|
|
60
|
+
WORK_BY_BOARD = ("work_by_board", "Lists work items associated with a board.")
|
|
61
|
+
WORK_BY_SPRINT = ("work_by_sprint", "Lists work items associated with a sprint.")
|
|
62
|
+
WORK_BY_EPIC = ("work_by_epic", "Lists work items associated with an epic.")
|
|
63
|
+
WORK_CHILDREN = ("work_children", "Lists child work items of a parent item.")
|
|
61
64
|
WORK_STATUS_UPDATE = (
|
|
62
65
|
"work_status_update",
|
|
63
|
-
"
|
|
66
|
+
"Updates only the status of a work item.",
|
|
64
67
|
)
|
|
65
68
|
WORK_ASSIGN_SPRINT = (
|
|
66
69
|
"work_assign_sprint",
|
|
67
|
-
"
|
|
70
|
+
"Assigns work items to a sprint.",
|
|
68
71
|
)
|
|
69
72
|
|
|
70
73
|
# Boards
|
|
71
|
-
BOARD_LIST = ("board_list", "
|
|
72
|
-
BOARD_BY_TEAM = ("board_by_team", "
|
|
73
|
-
BOARD_FAVORITES = ("board_favorites", "
|
|
74
|
-
BOARD_GET = ("board_get", "
|
|
75
|
-
BOARD_COLUMNS = ("board_columns", "
|
|
74
|
+
BOARD_LIST = ("board_list", "Lists available boards with optional filters.")
|
|
75
|
+
BOARD_BY_TEAM = ("board_by_team", "Lists boards for a specific team.")
|
|
76
|
+
BOARD_FAVORITES = ("board_favorites", "Lists boards marked as favorites.")
|
|
77
|
+
BOARD_GET = ("board_get", "Gets board details by ID.")
|
|
78
|
+
BOARD_COLUMNS = ("board_columns", "Lists columns configured for a board.")
|
|
76
79
|
|
|
77
80
|
# Sprints
|
|
78
|
-
SPRINT_LIST = ("sprint_list", "
|
|
79
|
-
SPRINT_BY_TEAM = ("sprint_by_team", "
|
|
80
|
-
SPRINT_ACTIVE = ("sprint_active", "
|
|
81
|
-
SPRINT_GET = ("sprint_get", "
|
|
81
|
+
SPRINT_LIST = ("sprint_list", "Lists available sprints with optional filters.")
|
|
82
|
+
SPRINT_BY_TEAM = ("sprint_by_team", "Lists sprints associated with a team.")
|
|
83
|
+
SPRINT_ACTIVE = ("sprint_active", "Gets the active sprint for a team.")
|
|
84
|
+
SPRINT_GET = ("sprint_get", "Gets sprint details by ID.")
|
|
82
85
|
SPRINT_WORK_ITEMS = (
|
|
83
86
|
"sprint_work_items",
|
|
84
|
-
"
|
|
87
|
+
"Lists work items linked to a sprint.",
|
|
85
88
|
)
|
|
86
89
|
|
|
87
90
|
# Modes
|
|
88
|
-
MODE_CREATE = ("mode_create", "
|
|
89
|
-
MODE_LIST = ("mode_list", "
|
|
90
|
-
MODE_GET = ("mode_get", "
|
|
91
|
-
MODE_UPDATE = ("mode_update", "
|
|
92
|
-
MODE_DELETE = ("mode_delete", "
|
|
93
|
-
MODE_RULE_ADD = ("mode_rule_add", "
|
|
91
|
+
MODE_CREATE = ("mode_create", "Creates a mode with content and optional metadata.")
|
|
92
|
+
MODE_LIST = ("mode_list", "Lists registered modes.")
|
|
93
|
+
MODE_GET = ("mode_get", "Gets full details of a mode.")
|
|
94
|
+
MODE_UPDATE = ("mode_update", "Updates properties of an existing mode.")
|
|
95
|
+
MODE_DELETE = ("mode_delete", "Removes a mode.")
|
|
96
|
+
MODE_RULE_ADD = ("mode_rule_add", "Associates a rule with a mode.")
|
|
94
97
|
MODE_RULE_REMOVE = (
|
|
95
98
|
"mode_rule_remove",
|
|
96
|
-
"
|
|
99
|
+
"Removes the association of a rule with a mode.",
|
|
97
100
|
)
|
|
98
|
-
MODE_RULES = ("mode_rules", "
|
|
101
|
+
MODE_RULES = ("mode_rules", "Lists rules associated with a mode.")
|
|
99
102
|
|
|
100
103
|
# Rules
|
|
101
|
-
RULE_CREATE = ("rule_create", "
|
|
102
|
-
RULE_LIST = ("rule_list", "
|
|
103
|
-
RULE_GET = ("rule_get", "
|
|
104
|
-
RULE_UPDATE = ("rule_update", "
|
|
105
|
-
RULE_DELETE = ("rule_delete", "
|
|
104
|
+
RULE_CREATE = ("rule_create", "Creates a rule with content and metadata.")
|
|
105
|
+
RULE_LIST = ("rule_list", "Lists registered rules.")
|
|
106
|
+
RULE_GET = ("rule_get", "Gets rule details.")
|
|
107
|
+
RULE_UPDATE = ("rule_update", "Updates an existing rule.")
|
|
108
|
+
RULE_DELETE = ("rule_delete", "Removes a rule.")
|
|
106
109
|
|
|
107
110
|
# Documentation
|
|
108
|
-
DOC_CREATE = ("doc_create", "
|
|
109
|
-
DOC_LIST = ("doc_list", "
|
|
110
|
-
DOC_GET = ("doc_get", "
|
|
111
|
-
DOC_UPDATE = ("doc_update", "
|
|
112
|
-
DOC_DELETE = ("doc_delete", "
|
|
113
|
-
DOC_SEARCH = ("doc_search", "
|
|
114
|
-
DOC_ROOTS = ("doc_roots", "
|
|
115
|
-
DOC_RECENT = ("doc_recent", "
|
|
116
|
-
DOC_ANALYTICS = ("doc_analytics", "
|
|
117
|
-
DOC_CHILDREN = ("doc_children", "
|
|
118
|
-
DOC_TREE = ("doc_tree", "
|
|
119
|
-
DOC_FULL_TREE = ("doc_full_tree", "
|
|
120
|
-
DOC_MOVE = ("doc_move", "
|
|
121
|
-
DOC_PUBLISH = ("doc_publish", "
|
|
122
|
-
DOC_VERSION = ("doc_version", "
|
|
123
|
-
DOC_DUPLICATE = ("doc_duplicate", "
|
|
124
|
-
|
|
125
|
-
HELP = ("knowledge_help", "
|
|
111
|
+
DOC_CREATE = ("doc_create", "Creates a documentation item.")
|
|
112
|
+
DOC_LIST = ("doc_list", "Lists documentation items with filters.")
|
|
113
|
+
DOC_GET = ("doc_get", "Gets documentation item details.")
|
|
114
|
+
DOC_UPDATE = ("doc_update", "Updates a documentation item.")
|
|
115
|
+
DOC_DELETE = ("doc_delete", "Removes a documentation item.")
|
|
116
|
+
DOC_SEARCH = ("doc_search", "Searches documentation items by text.")
|
|
117
|
+
DOC_ROOTS = ("doc_roots", "Lists available root documents.")
|
|
118
|
+
DOC_RECENT = ("doc_recent", "Lists recently accessed documents.")
|
|
119
|
+
DOC_ANALYTICS = ("doc_analytics", "Returns document analytics.")
|
|
120
|
+
DOC_CHILDREN = ("doc_children", "Lists child documents of an item.")
|
|
121
|
+
DOC_TREE = ("doc_tree", "Retrieves the direct tree of a document.")
|
|
122
|
+
DOC_FULL_TREE = ("doc_full_tree", "Retrieves the full documentation tree.")
|
|
123
|
+
DOC_MOVE = ("doc_move", "Moves a document to another parent.")
|
|
124
|
+
DOC_PUBLISH = ("doc_publish", "Changes publication status of a document.")
|
|
125
|
+
DOC_VERSION = ("doc_version", "Generates or retrieves a document version.")
|
|
126
|
+
DOC_DUPLICATE = ("doc_duplicate", "Duplicates an existing document.")
|
|
127
|
+
|
|
128
|
+
HELP = ("knowledge_help", "Shows available actions and their uses.")
|
|
126
129
|
|
|
127
130
|
@classmethod
|
|
128
131
|
def choices(cls) -> List[str]:
|
|
@@ -131,7 +134,7 @@ class KnowledgeAction(str, Enum):
|
|
|
131
134
|
@classmethod
|
|
132
135
|
def formatted_help(cls) -> str:
|
|
133
136
|
lines = [
|
|
134
|
-
"| **
|
|
137
|
+
"| **Action** | **Description** |",
|
|
135
138
|
"| --- | --- |",
|
|
136
139
|
]
|
|
137
140
|
for member in cls:
|
|
@@ -139,7 +142,7 @@ class KnowledgeAction(str, Enum):
|
|
|
139
142
|
return "\n".join(lines)
|
|
140
143
|
|
|
141
144
|
|
|
142
|
-
ACTION_FIELD_DESCRIPTION = "
|
|
145
|
+
ACTION_FIELD_DESCRIPTION = "Knowledge action. Choose one of the values: " + ", ".join(
|
|
143
146
|
f"`{member.value}` ({member.description.rstrip('.')})."
|
|
144
147
|
for member in KnowledgeAction
|
|
145
148
|
)
|
|
@@ -156,165 +159,158 @@ _ALLOWED_DOC_TYPES = {
|
|
|
156
159
|
class KnowledgeRequest(ToolRequest):
|
|
157
160
|
action: KnowledgeAction = Field(description=ACTION_FIELD_DESCRIPTION)
|
|
158
161
|
id: Optional[UUIDStr] = Field(
|
|
159
|
-
default=None, description="
|
|
162
|
+
default=None, description="Primary resource ID (UUID)."
|
|
160
163
|
)
|
|
161
|
-
limit: int = Field(default=20, ge=1, le=100, description="
|
|
164
|
+
limit: int = Field(default=20, ge=1, le=100, description="Result limit.")
|
|
162
165
|
offset: int = Field(
|
|
163
|
-
default=0, ge=0, description="
|
|
164
|
-
)
|
|
165
|
-
team_id: Optional[UUIDStr] = Field(
|
|
166
|
-
default=None, description="ID do time para filtros (UUID)."
|
|
166
|
+
default=0, ge=0, description="Pagination offset (when supported)."
|
|
167
167
|
)
|
|
168
168
|
board_id: Optional[UUIDStr] = Field(
|
|
169
|
-
default=None, description="
|
|
169
|
+
default=None, description="Associated board ID (UUID)."
|
|
170
170
|
)
|
|
171
171
|
sprint_id: Optional[UUIDStr] = Field(
|
|
172
|
-
default=None, description="
|
|
172
|
+
default=None, description="Associated sprint ID (UUID)."
|
|
173
173
|
)
|
|
174
174
|
epic_id: Optional[UUIDStr] = Field(
|
|
175
|
-
default=None, description="
|
|
175
|
+
default=None, description="Associated epic ID (UUID)."
|
|
176
176
|
)
|
|
177
|
-
query: Optional[str] = Field(default=None, description="
|
|
177
|
+
query: Optional[str] = Field(default=None, description="Filter/search term.")
|
|
178
178
|
return_content: Optional[bool] = Field(
|
|
179
|
-
default=None, description="
|
|
179
|
+
default=None, description="Return full content."
|
|
180
180
|
)
|
|
181
181
|
return_description: Optional[bool] = Field(
|
|
182
|
-
default=None, description="
|
|
182
|
+
default=None, description="Return full description."
|
|
183
183
|
)
|
|
184
184
|
return_metadata: Optional[bool] = Field(
|
|
185
|
-
default=None, description="
|
|
185
|
+
default=None, description="Return full metadata."
|
|
186
186
|
)
|
|
187
187
|
|
|
188
188
|
# Work item fields
|
|
189
|
-
work_title: Optional[TitleStr] = Field(
|
|
190
|
-
default=None, description="Título do work item."
|
|
191
|
-
)
|
|
189
|
+
work_title: Optional[TitleStr] = Field(default=None, description="Work item title.")
|
|
192
190
|
work_description: Optional[MarkdownStr] = Field(
|
|
193
|
-
default=None, description="
|
|
191
|
+
default=None, description="Work item description (Markdown)."
|
|
194
192
|
)
|
|
195
193
|
work_type: Optional[str] = Field(
|
|
196
194
|
default="task",
|
|
197
|
-
description="
|
|
195
|
+
description="Work item type (epic, feature, story, task, subtask, bug).",
|
|
198
196
|
)
|
|
199
197
|
work_status: Optional[str] = Field(
|
|
200
198
|
default=None,
|
|
201
|
-
description="
|
|
199
|
+
description="Work item status (backlog, todo, in_progress, review, testing, done, cancelled).",
|
|
202
200
|
)
|
|
203
201
|
work_priority: Optional[str] = Field(
|
|
204
202
|
default=None,
|
|
205
|
-
description="
|
|
203
|
+
description="Work item priority (critical, high, medium, low).",
|
|
206
204
|
)
|
|
207
205
|
story_points: Optional[int] = Field(
|
|
208
206
|
default=None, ge=0, le=100, description="Story points (0-100)."
|
|
209
207
|
)
|
|
210
208
|
assignee_id: Optional[UUIDStr] = Field(
|
|
211
|
-
default=None, description="ID
|
|
209
|
+
default=None, description="Assignee ID (UUID)."
|
|
212
210
|
)
|
|
213
211
|
parent_id: Optional[UUIDStr] = Field(
|
|
214
|
-
default=None, description="
|
|
212
|
+
default=None, description="Parent item ID (UUID)."
|
|
215
213
|
)
|
|
216
214
|
work_due_date: Optional[DateTimeStr] = Field(
|
|
217
|
-
default=None, description="
|
|
215
|
+
default=None, description="Work item due date (ISO 8601)."
|
|
218
216
|
)
|
|
219
217
|
work_tags: Optional[List[TagStr]] = Field(
|
|
220
|
-
default=None, description="
|
|
218
|
+
default=None, description="Work item tags."
|
|
221
219
|
)
|
|
222
220
|
work_item_ids: Optional[List[UUIDStr]] = Field(
|
|
223
221
|
default=None,
|
|
224
|
-
description="
|
|
222
|
+
description="List of work item IDs for batch operations (UUIDs).",
|
|
225
223
|
)
|
|
226
224
|
|
|
227
225
|
# Mode fields
|
|
228
226
|
mode_id: Optional[UUIDStr] = Field(
|
|
229
|
-
default=None, description="
|
|
227
|
+
default=None, description="Related mode ID (UUID)."
|
|
230
228
|
)
|
|
231
|
-
mode_name: Optional[TitleStr] = Field(default=None, description="
|
|
229
|
+
mode_name: Optional[TitleStr] = Field(default=None, description="Mode name.")
|
|
232
230
|
mode_description: Optional[DescriptionStr] = Field(
|
|
233
|
-
default=None, description="
|
|
231
|
+
default=None, description="Mode description."
|
|
234
232
|
)
|
|
235
233
|
mode_content: Optional[MarkdownStr] = Field(
|
|
236
|
-
default=None, description="
|
|
234
|
+
default=None, description="Mode content (Markdown)."
|
|
237
235
|
)
|
|
238
236
|
mode_is_default: Optional[bool] = Field(
|
|
239
|
-
default=None, description="
|
|
237
|
+
default=None, description="Indicates if the mode is default."
|
|
240
238
|
)
|
|
241
239
|
mode_metadata: Optional[MarkdownStr] = Field(
|
|
242
|
-
default=None, description="
|
|
240
|
+
default=None, description="Mode metadata for AI processing."
|
|
243
241
|
)
|
|
244
242
|
|
|
245
243
|
# Rule fields
|
|
246
244
|
rule_id: Optional[UUIDStr] = Field(
|
|
247
|
-
default=None, description="
|
|
245
|
+
default=None, description="Related rule ID (UUID)."
|
|
248
246
|
)
|
|
249
|
-
rule_name: Optional[TitleStr] = Field(default=None, description="
|
|
247
|
+
rule_name: Optional[TitleStr] = Field(default=None, description="Rule name.")
|
|
250
248
|
rule_description: Optional[DescriptionStr] = Field(
|
|
251
|
-
default=None, description="
|
|
249
|
+
default=None, description="Rule description."
|
|
252
250
|
)
|
|
253
251
|
rule_content: Optional[MarkdownStr] = Field(
|
|
254
|
-
default=None, description="
|
|
252
|
+
default=None, description="Rule content (Markdown)."
|
|
255
253
|
)
|
|
256
|
-
rule_is_default: Optional[bool] = Field(default=None, description="
|
|
254
|
+
rule_is_default: Optional[bool] = Field(default=None, description="Default rule.")
|
|
257
255
|
rule_metadata: Optional[MarkdownStr] = Field(
|
|
258
|
-
default=None, description="
|
|
256
|
+
default=None, description="Rule metadata for AI processing."
|
|
259
257
|
)
|
|
260
258
|
|
|
261
259
|
# Documentation fields
|
|
262
260
|
doc_title: Optional[TitleStr] = Field(
|
|
263
|
-
default=None, description="
|
|
261
|
+
default=None, description="Documentation title."
|
|
264
262
|
)
|
|
265
263
|
doc_description: Optional[DescriptionStr] = Field(
|
|
266
|
-
default=None, description="
|
|
264
|
+
default=None, description="Documentation description."
|
|
267
265
|
)
|
|
268
266
|
doc_content: Optional[MarkdownStr] = Field(
|
|
269
|
-
default=None, description="
|
|
267
|
+
default=None, description="Documentation content (Markdown)."
|
|
270
268
|
)
|
|
271
269
|
doc_status: Optional[str] = Field(
|
|
272
270
|
default=None,
|
|
273
|
-
description="
|
|
271
|
+
description="Documentation status (draft, review, published, archived).",
|
|
274
272
|
)
|
|
275
273
|
doc_type: Optional[str] = Field(
|
|
276
|
-
default=None,
|
|
274
|
+
default=None,
|
|
275
|
+
description="Documentation type. Values: folder, page, api_doc, guide.",
|
|
277
276
|
)
|
|
278
277
|
doc_language: Optional[LanguageStr] = Field(
|
|
279
|
-
default=None, description="
|
|
278
|
+
default=None, description="Documentation language (e.g.: pt, en, pt-BR)."
|
|
280
279
|
)
|
|
281
280
|
doc_parent_id: Optional[UUIDStr] = Field(
|
|
282
|
-
default=None, description="
|
|
283
|
-
)
|
|
284
|
-
doc_team_id: Optional[UUIDStr] = Field(
|
|
285
|
-
default=None, description="ID do time responsável pela documentação (UUID)."
|
|
281
|
+
default=None, description="Parent document ID (UUID)."
|
|
286
282
|
)
|
|
287
283
|
doc_owner_id: Optional[UUIDStr] = Field(
|
|
288
|
-
default=None, description="ID
|
|
284
|
+
default=None, description="Owner ID (UUID)."
|
|
289
285
|
)
|
|
290
286
|
doc_reviewer_id: Optional[UUIDStr] = Field(
|
|
291
|
-
default=None, description="ID
|
|
287
|
+
default=None, description="Reviewer ID (UUID)."
|
|
292
288
|
)
|
|
293
289
|
doc_version: Optional[VersionStr] = Field(
|
|
294
|
-
default=None, description="
|
|
290
|
+
default=None, description="Document version (e.g.: 1.0, 2.1.3)."
|
|
295
291
|
)
|
|
296
|
-
doc_category: Optional[CategoryStr] = Field(default=None, description="
|
|
292
|
+
doc_category: Optional[CategoryStr] = Field(default=None, description="Category.")
|
|
297
293
|
doc_tags: Optional[List[TagStr]] = Field(default=None, description="Tags.")
|
|
298
294
|
doc_position: Optional[int] = Field(
|
|
299
|
-
default=None, ge=0, description="
|
|
295
|
+
default=None, ge=0, description="Desired position when moving documents."
|
|
300
296
|
)
|
|
301
297
|
doc_emoji: Optional[EmojiStr] = Field(
|
|
302
|
-
default=None, description="Emoji
|
|
298
|
+
default=None, description="Emoji displayed with the document."
|
|
303
299
|
)
|
|
304
300
|
doc_emote: Optional[EmojiStr] = Field(
|
|
305
|
-
default=None, description="Alias
|
|
301
|
+
default=None, description="Alias for emoji, kept for compatibility."
|
|
306
302
|
)
|
|
307
303
|
doc_keywords: Optional[List[TagStr]] = Field(
|
|
308
|
-
default=None, description="
|
|
304
|
+
default=None, description="Keywords for search."
|
|
309
305
|
)
|
|
310
306
|
doc_is_public: Optional[bool] = Field(
|
|
311
|
-
default=None, description="
|
|
307
|
+
default=None, description="Whether the document is public."
|
|
312
308
|
)
|
|
313
309
|
|
|
314
310
|
|
|
315
311
|
class KnowledgeTool(Tool):
|
|
316
312
|
name = "knowledge"
|
|
317
|
-
description = "
|
|
313
|
+
description = "Fenix Cloud knowledge operations (Work Items, Boards, Sprints, Modes, Rules, Docs)."
|
|
318
314
|
request_model = KnowledgeRequest
|
|
319
315
|
|
|
320
316
|
def __init__(self, context: AppContext):
|
|
@@ -338,7 +334,7 @@ class KnowledgeTool(Tool):
|
|
|
338
334
|
if action.value.startswith("doc_"):
|
|
339
335
|
return await self._run_doc(payload)
|
|
340
336
|
return text(
|
|
341
|
-
"❌
|
|
337
|
+
"❌ Invalid action for knowledge.\n\nChoose one of the values:\n"
|
|
342
338
|
+ "\n".join(f"- `{value}`" for value in KnowledgeAction.choices())
|
|
343
339
|
)
|
|
344
340
|
|
|
@@ -349,9 +345,7 @@ class KnowledgeTool(Tool):
|
|
|
349
345
|
action = payload.action
|
|
350
346
|
if action is KnowledgeAction.WORK_CREATE:
|
|
351
347
|
if not payload.work_title:
|
|
352
|
-
return text("❌
|
|
353
|
-
if not payload.team_id:
|
|
354
|
-
return text("❌ Informe team_id para criar o item.")
|
|
348
|
+
return text("❌ Provide work_title to create the item.")
|
|
355
349
|
work = await self._service.work_create(
|
|
356
350
|
{
|
|
357
351
|
"title": payload.work_title,
|
|
@@ -364,12 +358,11 @@ class KnowledgeTool(Tool):
|
|
|
364
358
|
"sprint_id": payload.sprint_id,
|
|
365
359
|
"board_id": payload.board_id,
|
|
366
360
|
"parent_id": payload.parent_id,
|
|
367
|
-
"team_id": payload.team_id,
|
|
368
361
|
"due_date": payload.work_due_date,
|
|
369
362
|
"tags": payload.work_tags,
|
|
370
363
|
}
|
|
371
364
|
)
|
|
372
|
-
return text(_format_work(work, header="✅ Work item
|
|
365
|
+
return text(_format_work(work, header="✅ Work item created"))
|
|
373
366
|
|
|
374
367
|
if action is KnowledgeAction.WORK_LIST:
|
|
375
368
|
items = await self._service.work_list(
|
|
@@ -382,19 +375,19 @@ class KnowledgeTool(Tool):
|
|
|
382
375
|
board=payload.board_id,
|
|
383
376
|
)
|
|
384
377
|
if not items:
|
|
385
|
-
return text("🎯
|
|
378
|
+
return text("🎯 No work items found.")
|
|
386
379
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
387
380
|
return text(f"🎯 **Work items ({len(items)}):**\n\n{body}")
|
|
388
381
|
|
|
389
382
|
if action is KnowledgeAction.WORK_GET:
|
|
390
383
|
if not payload.id:
|
|
391
|
-
return text("❌
|
|
384
|
+
return text("❌ Provide the work item ID.")
|
|
392
385
|
work = await self._service.work_get(payload.id)
|
|
393
|
-
return text(_format_work(work, header="🎯
|
|
386
|
+
return text(_format_work(work, header="🎯 Work item details"))
|
|
394
387
|
|
|
395
388
|
if action is KnowledgeAction.WORK_UPDATE:
|
|
396
389
|
if not payload.id:
|
|
397
|
-
return text("❌
|
|
390
|
+
return text("❌ Provide the work item ID.")
|
|
398
391
|
work = await self._service.work_update(
|
|
399
392
|
payload.id,
|
|
400
393
|
{
|
|
@@ -408,106 +401,97 @@ class KnowledgeTool(Tool):
|
|
|
408
401
|
"sprint_id": payload.sprint_id,
|
|
409
402
|
"board_id": payload.board_id,
|
|
410
403
|
"parent_id": payload.parent_id,
|
|
411
|
-
"team_id": payload.team_id,
|
|
412
404
|
"due_date": payload.work_due_date,
|
|
413
405
|
"tags": payload.work_tags,
|
|
414
406
|
},
|
|
415
407
|
)
|
|
416
|
-
return text(_format_work(work, header="✅ Work item
|
|
408
|
+
return text(_format_work(work, header="✅ Work item updated"))
|
|
417
409
|
|
|
418
410
|
if action is KnowledgeAction.WORK_DELETE:
|
|
419
411
|
if not payload.id:
|
|
420
|
-
return text("❌
|
|
412
|
+
return text("❌ Provide the work item ID.")
|
|
421
413
|
await self._service.work_delete(payload.id)
|
|
422
|
-
return text(f"🗑️ Work item {payload.id}
|
|
414
|
+
return text(f"🗑️ Work item {payload.id} removed.")
|
|
423
415
|
|
|
424
416
|
if action is KnowledgeAction.WORK_BACKLOG:
|
|
425
|
-
|
|
426
|
-
if not team_id:
|
|
427
|
-
return text("❌ Informe team_id para consultar o backlog.")
|
|
428
|
-
items = await self._service.work_backlog(team_id=team_id)
|
|
417
|
+
items = await self._service.work_backlog()
|
|
429
418
|
if not items:
|
|
430
|
-
return text("📋 Backlog
|
|
419
|
+
return text("📋 Backlog empty.")
|
|
431
420
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
432
421
|
return text(f"📋 **Backlog ({len(items)}):**\n\n{body}")
|
|
433
422
|
|
|
434
423
|
if action is KnowledgeAction.WORK_SEARCH:
|
|
435
424
|
query = sanitize_null(payload.query)
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
return text("❌ Informe query e team_id para buscar work items.")
|
|
425
|
+
if not query:
|
|
426
|
+
return text("❌ Provide query to search work items.")
|
|
439
427
|
items = await self._service.work_search(
|
|
440
428
|
query=query,
|
|
441
|
-
team_id=team_id,
|
|
442
429
|
limit=payload.limit,
|
|
443
430
|
)
|
|
444
431
|
if not items:
|
|
445
|
-
return text("🔍
|
|
432
|
+
return text("🔍 No work items found.")
|
|
446
433
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
447
|
-
return text(f"🔍 **
|
|
434
|
+
return text(f"🔍 **Results ({len(items)}):**\n\n{body}")
|
|
448
435
|
|
|
449
436
|
if action is KnowledgeAction.WORK_ANALYTICS:
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
return text("❌ Informe team_id para obter analytics.")
|
|
453
|
-
analytics = await self._service.work_analytics(team_id=team_id)
|
|
454
|
-
lines = ["📊 **Analytics de Work Items**"]
|
|
437
|
+
analytics = await self._service.work_analytics()
|
|
438
|
+
lines = ["📊 **Work Items Analytics**"]
|
|
455
439
|
for key, value in analytics.items():
|
|
456
440
|
lines.append(f"- {key}: {value}")
|
|
457
441
|
return text("\n".join(lines))
|
|
458
442
|
|
|
459
443
|
if action is KnowledgeAction.WORK_BY_BOARD:
|
|
460
444
|
if not payload.board_id:
|
|
461
|
-
return text("❌
|
|
445
|
+
return text("❌ Provide board_id to list items.")
|
|
462
446
|
items = await self._service.work_by_board(board_id=payload.board_id)
|
|
463
447
|
if not items:
|
|
464
|
-
return text("🗂️
|
|
448
|
+
return text("🗂️ No work items for the specified board.")
|
|
465
449
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
466
|
-
return text(f"🗂️ **
|
|
450
|
+
return text(f"🗂️ **Board items ({len(items)}):**\n\n{body}")
|
|
467
451
|
|
|
468
452
|
if action is KnowledgeAction.WORK_BY_SPRINT:
|
|
469
453
|
if not payload.sprint_id:
|
|
470
|
-
return text("❌
|
|
454
|
+
return text("❌ Provide sprint_id to list items.")
|
|
471
455
|
items = await self._service.work_by_sprint(sprint_id=payload.sprint_id)
|
|
472
456
|
if not items:
|
|
473
|
-
return text("🏃
|
|
457
|
+
return text("🏃 No items linked to the specified sprint.")
|
|
474
458
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
475
|
-
return text(f"🏃 **
|
|
459
|
+
return text(f"🏃 **Sprint work items ({len(items)}):**\n\n{body}")
|
|
476
460
|
|
|
477
461
|
if action is KnowledgeAction.WORK_BY_EPIC:
|
|
478
462
|
if not payload.epic_id:
|
|
479
|
-
return text("❌
|
|
463
|
+
return text("❌ Provide epic_id to list items.")
|
|
480
464
|
items = await self._service.work_by_epic(epic_id=payload.epic_id)
|
|
481
465
|
if not items:
|
|
482
|
-
return text("📦
|
|
466
|
+
return text("📦 No items linked to the specified epic.")
|
|
483
467
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
484
|
-
return text(f"📦 **
|
|
468
|
+
return text(f"📦 **Epic work items ({len(items)}):**\n\n{body}")
|
|
485
469
|
|
|
486
470
|
if action is KnowledgeAction.WORK_CHILDREN:
|
|
487
471
|
if not payload.id:
|
|
488
|
-
return text("❌
|
|
472
|
+
return text("❌ Provide the parent work item ID.")
|
|
489
473
|
items = await self._service.work_children(payload.id)
|
|
490
474
|
if not items:
|
|
491
|
-
return text("👶
|
|
475
|
+
return text("👶 No child items found.")
|
|
492
476
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
493
|
-
return text(f"👶 **
|
|
477
|
+
return text(f"👶 **Child work items ({len(items)}):**\n\n{body}")
|
|
494
478
|
|
|
495
479
|
if action is KnowledgeAction.WORK_STATUS_UPDATE:
|
|
496
480
|
if not payload.id:
|
|
497
|
-
return text("❌
|
|
481
|
+
return text("❌ Provide the work item ID.")
|
|
498
482
|
if not payload.work_status:
|
|
499
|
-
return text("❌
|
|
483
|
+
return text("❌ Provide work_status to update.")
|
|
500
484
|
work = await self._service.work_update_status(
|
|
501
485
|
payload.id,
|
|
502
486
|
{"status": payload.work_status},
|
|
503
487
|
)
|
|
504
|
-
return text(_format_work(work, header="✅ Status
|
|
488
|
+
return text(_format_work(work, header="✅ Status updated"))
|
|
505
489
|
|
|
506
490
|
if action is KnowledgeAction.WORK_ASSIGN_SPRINT:
|
|
507
491
|
if not payload.sprint_id:
|
|
508
|
-
return text("❌
|
|
492
|
+
return text("❌ Provide sprint_id to assign items.")
|
|
509
493
|
if not payload.work_item_ids:
|
|
510
|
-
return text("❌
|
|
494
|
+
return text("❌ Provide work_item_ids with the list of IDs.")
|
|
511
495
|
await self._service.work_assign_to_sprint(
|
|
512
496
|
{
|
|
513
497
|
"sprint_id": payload.sprint_id,
|
|
@@ -515,10 +499,10 @@ class KnowledgeTool(Tool):
|
|
|
515
499
|
}
|
|
516
500
|
)
|
|
517
501
|
count = len(payload.work_item_ids)
|
|
518
|
-
return text(f"✅ {count} work item(s)
|
|
502
|
+
return text(f"✅ {count} work item(s) assigned to sprint.")
|
|
519
503
|
|
|
520
504
|
return text(
|
|
521
|
-
"❌
|
|
505
|
+
"❌ Unsupported work item action.\n\nChoose one of the values:\n"
|
|
522
506
|
+ "\n".join(
|
|
523
507
|
f"- `{value}`"
|
|
524
508
|
for value in KnowledgeAction.choices()
|
|
@@ -536,46 +520,44 @@ class KnowledgeTool(Tool):
|
|
|
536
520
|
limit=payload.limit, offset=payload.offset
|
|
537
521
|
)
|
|
538
522
|
if not boards:
|
|
539
|
-
return text("🗂️
|
|
523
|
+
return text("🗂️ No boards found.")
|
|
540
524
|
body = "\n\n".join(_format_board(board) for board in boards)
|
|
541
525
|
return text(f"🗂️ **Boards ({len(boards)}):**\n\n{body}")
|
|
542
526
|
|
|
543
527
|
if action is KnowledgeAction.BOARD_BY_TEAM:
|
|
544
|
-
|
|
545
|
-
return text("❌ Informe team_id para listar boards do time.")
|
|
546
|
-
boards = await self._service.board_list_by_team(payload.team_id)
|
|
528
|
+
boards = await self._service.board_list_by_team()
|
|
547
529
|
if not boards:
|
|
548
|
-
return text("🗂️
|
|
530
|
+
return text("🗂️ No boards registered for the team.")
|
|
549
531
|
body = "\n\n".join(_format_board(board) for board in boards)
|
|
550
|
-
return text(f"🗂️ **
|
|
532
|
+
return text(f"🗂️ **Team boards ({len(boards)}):**\n\n{body}")
|
|
551
533
|
|
|
552
534
|
if action is KnowledgeAction.BOARD_FAVORITES:
|
|
553
535
|
boards = await self._service.board_favorites()
|
|
554
536
|
if not boards:
|
|
555
|
-
return text("⭐
|
|
537
|
+
return text("⭐ No favorite boards registered.")
|
|
556
538
|
body = "\n\n".join(_format_board(board) for board in boards)
|
|
557
|
-
return text(f"⭐ **
|
|
539
|
+
return text(f"⭐ **Favorite boards ({len(boards)}):**\n\n{body}")
|
|
558
540
|
|
|
559
541
|
if action is KnowledgeAction.BOARD_GET:
|
|
560
542
|
if not payload.board_id:
|
|
561
|
-
return text("❌
|
|
543
|
+
return text("❌ Provide board_id to get details.")
|
|
562
544
|
board = await self._service.board_get(payload.board_id)
|
|
563
|
-
return text(_format_board(board, header="🗂️
|
|
545
|
+
return text(_format_board(board, header="🗂️ Board details"))
|
|
564
546
|
|
|
565
547
|
if action is KnowledgeAction.BOARD_COLUMNS:
|
|
566
548
|
if not payload.board_id:
|
|
567
|
-
return text("❌
|
|
549
|
+
return text("❌ Provide board_id to list columns.")
|
|
568
550
|
columns = await self._service.board_columns(payload.board_id)
|
|
569
551
|
if not columns:
|
|
570
|
-
return text("📊 Board
|
|
552
|
+
return text("📊 Board has no columns registered.")
|
|
571
553
|
body = "\n".join(
|
|
572
|
-
f"- {col.get('name', '
|
|
554
|
+
f"- {col.get('name', 'Unnamed')} (ID: {col.get('id')})"
|
|
573
555
|
for col in columns
|
|
574
556
|
)
|
|
575
|
-
return text(f"📊 **
|
|
557
|
+
return text(f"📊 **Board columns:**\n{body}")
|
|
576
558
|
|
|
577
559
|
return text(
|
|
578
|
-
"❌
|
|
560
|
+
"❌ Unsupported board action.\n\nChoose one of the values:\n"
|
|
579
561
|
+ "\n".join(
|
|
580
562
|
f"- `{value}`"
|
|
581
563
|
for value in KnowledgeAction.choices()
|
|
@@ -593,44 +575,40 @@ class KnowledgeTool(Tool):
|
|
|
593
575
|
limit=payload.limit, offset=payload.offset
|
|
594
576
|
)
|
|
595
577
|
if not sprints:
|
|
596
|
-
return text("🏃
|
|
578
|
+
return text("🏃 No sprints found.")
|
|
597
579
|
body = "\n\n".join(_format_sprint(sprint) for sprint in sprints)
|
|
598
580
|
return text(f"🏃 **Sprints ({len(sprints)}):**\n\n{body}")
|
|
599
581
|
|
|
600
582
|
if action is KnowledgeAction.SPRINT_BY_TEAM:
|
|
601
|
-
|
|
602
|
-
return text("❌ Informe team_id para listar sprints do time.")
|
|
603
|
-
sprints = await self._service.sprint_list_by_team(payload.team_id)
|
|
583
|
+
sprints = await self._service.sprint_list_by_team()
|
|
604
584
|
if not sprints:
|
|
605
|
-
return text("🏃
|
|
585
|
+
return text("🏃 No sprints registered for the team.")
|
|
606
586
|
body = "\n\n".join(_format_sprint(sprint) for sprint in sprints)
|
|
607
|
-
return text(f"🏃 **
|
|
587
|
+
return text(f"🏃 **Team sprints ({len(sprints)}):**\n\n{body}")
|
|
608
588
|
|
|
609
589
|
if action is KnowledgeAction.SPRINT_ACTIVE:
|
|
610
|
-
|
|
611
|
-
return text("❌ Informe team_id para consultar o sprint ativo.")
|
|
612
|
-
sprint = await self._service.sprint_active(payload.team_id)
|
|
590
|
+
sprint = await self._service.sprint_active()
|
|
613
591
|
if not sprint:
|
|
614
|
-
return text("⏳
|
|
615
|
-
return text(_format_sprint(sprint, header="⏳
|
|
592
|
+
return text("⏳ No active sprint at the moment.")
|
|
593
|
+
return text(_format_sprint(sprint, header="⏳ Active sprint"))
|
|
616
594
|
|
|
617
595
|
if action is KnowledgeAction.SPRINT_GET:
|
|
618
596
|
if not payload.sprint_id:
|
|
619
|
-
return text("❌
|
|
597
|
+
return text("❌ Provide sprint_id to get details.")
|
|
620
598
|
sprint = await self._service.sprint_get(payload.sprint_id)
|
|
621
|
-
return text(_format_sprint(sprint, header="🏃
|
|
599
|
+
return text(_format_sprint(sprint, header="🏃 Sprint details"))
|
|
622
600
|
|
|
623
601
|
if action is KnowledgeAction.SPRINT_WORK_ITEMS:
|
|
624
602
|
if not payload.sprint_id:
|
|
625
|
-
return text("❌
|
|
603
|
+
return text("❌ Provide sprint_id to list items.")
|
|
626
604
|
items = await self._service.sprint_work_items(payload.sprint_id)
|
|
627
605
|
if not items:
|
|
628
|
-
return text("🏃
|
|
606
|
+
return text("🏃 No items linked to the specified sprint.")
|
|
629
607
|
body = "\n\n".join(_format_work(item) for item in items)
|
|
630
|
-
return text(f"🏃 **
|
|
608
|
+
return text(f"🏃 **Sprint items ({len(items)}):**\n\n{body}")
|
|
631
609
|
|
|
632
610
|
return text(
|
|
633
|
-
"❌
|
|
611
|
+
"❌ Unsupported sprint action.\n\nChoose one of the values:\n"
|
|
634
612
|
+ "\n".join(
|
|
635
613
|
f"- `{value}`"
|
|
636
614
|
for value in KnowledgeAction.choices()
|
|
@@ -645,7 +623,7 @@ class KnowledgeTool(Tool):
|
|
|
645
623
|
action = payload.action
|
|
646
624
|
if action is KnowledgeAction.MODE_CREATE:
|
|
647
625
|
if not payload.mode_name:
|
|
648
|
-
return text("❌
|
|
626
|
+
return text("❌ Provide mode_name to create the mode.")
|
|
649
627
|
mode = await self._service.mode_create(
|
|
650
628
|
{
|
|
651
629
|
"name": payload.mode_name,
|
|
@@ -655,7 +633,7 @@ class KnowledgeTool(Tool):
|
|
|
655
633
|
"metadata": payload.mode_metadata,
|
|
656
634
|
}
|
|
657
635
|
)
|
|
658
|
-
return text(_format_mode(mode, header="✅
|
|
636
|
+
return text(_format_mode(mode, header="✅ Mode created"))
|
|
659
637
|
|
|
660
638
|
if action is KnowledgeAction.MODE_LIST:
|
|
661
639
|
modes = await self._service.mode_list(
|
|
@@ -664,23 +642,23 @@ class KnowledgeTool(Tool):
|
|
|
664
642
|
return_metadata=payload.return_metadata,
|
|
665
643
|
)
|
|
666
644
|
if not modes:
|
|
667
|
-
return text("🎭
|
|
645
|
+
return text("🎭 No modes found.")
|
|
668
646
|
body = "\n\n".join(_format_mode(mode) for mode in modes)
|
|
669
647
|
return text(f"🎭 **Modes ({len(modes)}):**\n\n{body}")
|
|
670
648
|
|
|
671
649
|
if action is KnowledgeAction.MODE_GET:
|
|
672
650
|
if not payload.mode_id:
|
|
673
|
-
return text("❌
|
|
651
|
+
return text("❌ Provide mode_id to get details.")
|
|
674
652
|
mode = await self._service.mode_get(
|
|
675
653
|
payload.mode_id,
|
|
676
654
|
return_description=payload.return_description,
|
|
677
655
|
return_metadata=payload.return_metadata,
|
|
678
656
|
)
|
|
679
|
-
return text(_format_mode(mode, header="🎭
|
|
657
|
+
return text(_format_mode(mode, header="🎭 Mode details"))
|
|
680
658
|
|
|
681
659
|
if action is KnowledgeAction.MODE_UPDATE:
|
|
682
660
|
if not payload.mode_id:
|
|
683
|
-
return text("❌
|
|
661
|
+
return text("❌ Provide mode_id to update.")
|
|
684
662
|
mode = await self._service.mode_update(
|
|
685
663
|
payload.mode_id,
|
|
686
664
|
{
|
|
@@ -691,53 +669,53 @@ class KnowledgeTool(Tool):
|
|
|
691
669
|
"metadata": payload.mode_metadata,
|
|
692
670
|
},
|
|
693
671
|
)
|
|
694
|
-
return text(_format_mode(mode, header="✅
|
|
672
|
+
return text(_format_mode(mode, header="✅ Mode updated"))
|
|
695
673
|
|
|
696
674
|
if action is KnowledgeAction.MODE_DELETE:
|
|
697
675
|
if not payload.mode_id:
|
|
698
|
-
return text("❌
|
|
676
|
+
return text("❌ Provide mode_id to remove.")
|
|
699
677
|
await self._service.mode_delete(payload.mode_id)
|
|
700
|
-
return text(f"🗑️
|
|
678
|
+
return text(f"🗑️ Mode {payload.mode_id} removed.")
|
|
701
679
|
|
|
702
680
|
if action is KnowledgeAction.MODE_RULE_ADD:
|
|
703
681
|
if not payload.mode_id or not payload.rule_id:
|
|
704
|
-
return text("❌
|
|
682
|
+
return text("❌ Provide mode_id and rule_id to associate.")
|
|
705
683
|
link = await self._service.mode_rule_add(payload.mode_id, payload.rule_id)
|
|
706
684
|
return text(
|
|
707
685
|
"\n".join(
|
|
708
686
|
[
|
|
709
|
-
"🔗 **
|
|
710
|
-
f"
|
|
711
|
-
f"
|
|
687
|
+
"🔗 **Rule associated with mode!**",
|
|
688
|
+
f"Mode: {link.get('modeId', payload.mode_id)}",
|
|
689
|
+
f"Rule: {link.get('ruleId', payload.rule_id)}",
|
|
712
690
|
]
|
|
713
691
|
)
|
|
714
692
|
)
|
|
715
693
|
|
|
716
694
|
if action is KnowledgeAction.MODE_RULE_REMOVE:
|
|
717
695
|
if not payload.mode_id or not payload.rule_id:
|
|
718
|
-
return text("❌
|
|
696
|
+
return text("❌ Provide mode_id and rule_id to remove the association.")
|
|
719
697
|
await self._service.mode_rule_remove(payload.mode_id, payload.rule_id)
|
|
720
|
-
return text("🔗
|
|
698
|
+
return text("🔗 Association removed.")
|
|
721
699
|
|
|
722
700
|
if action is KnowledgeAction.MODE_RULES:
|
|
723
701
|
if payload.mode_id:
|
|
724
702
|
rules = await self._service.mode_rules(payload.mode_id)
|
|
725
|
-
context_label = f"
|
|
703
|
+
context_label = f"mode {payload.mode_id}"
|
|
726
704
|
elif payload.rule_id:
|
|
727
705
|
rules = await self._service.mode_rules_for_rule(payload.rule_id)
|
|
728
|
-
context_label = f"
|
|
706
|
+
context_label = f"rule {payload.rule_id}"
|
|
729
707
|
else:
|
|
730
|
-
return text("❌
|
|
708
|
+
return text("❌ Provide mode_id or rule_id to list associations.")
|
|
731
709
|
if not rules:
|
|
732
|
-
return text("🔗
|
|
710
|
+
return text("🔗 No associations found.")
|
|
733
711
|
body = "\n".join(
|
|
734
|
-
f"- {item.get('name', '
|
|
712
|
+
f"- {item.get('name', 'Unnamed')} (ID: {item.get('id')})"
|
|
735
713
|
for item in rules
|
|
736
714
|
)
|
|
737
|
-
return text(f"🔗 **
|
|
715
|
+
return text(f"🔗 **Associations for {context_label}:**\n{body}")
|
|
738
716
|
|
|
739
717
|
return text(
|
|
740
|
-
"❌
|
|
718
|
+
"❌ Unsupported mode action.\n\nChoose one of the values:\n"
|
|
741
719
|
+ "\n".join(
|
|
742
720
|
f"- `{value}`"
|
|
743
721
|
for value in KnowledgeAction.choices()
|
|
@@ -752,7 +730,7 @@ class KnowledgeTool(Tool):
|
|
|
752
730
|
action = payload.action
|
|
753
731
|
if action is KnowledgeAction.RULE_CREATE:
|
|
754
732
|
if not payload.rule_name or not payload.rule_content:
|
|
755
|
-
return text("❌
|
|
733
|
+
return text("❌ Provide rule_name and rule_content.")
|
|
756
734
|
rule = await self._service.rule_create(
|
|
757
735
|
{
|
|
758
736
|
"name": payload.rule_name,
|
|
@@ -762,7 +740,7 @@ class KnowledgeTool(Tool):
|
|
|
762
740
|
"metadata": payload.rule_metadata,
|
|
763
741
|
}
|
|
764
742
|
)
|
|
765
|
-
return text(_format_rule(rule, header="✅
|
|
743
|
+
return text(_format_rule(rule, header="✅ Rule created"))
|
|
766
744
|
|
|
767
745
|
if action is KnowledgeAction.RULE_LIST:
|
|
768
746
|
rules = await self._service.rule_list(
|
|
@@ -771,24 +749,24 @@ class KnowledgeTool(Tool):
|
|
|
771
749
|
return_modes=payload.return_metadata,
|
|
772
750
|
)
|
|
773
751
|
if not rules:
|
|
774
|
-
return text("📋
|
|
752
|
+
return text("📋 No rules found.")
|
|
775
753
|
body = "\n\n".join(_format_rule(rule) for rule in rules)
|
|
776
|
-
return text(f"📋 **
|
|
754
|
+
return text(f"📋 **Rules ({len(rules)}):**\n\n{body}")
|
|
777
755
|
|
|
778
756
|
if action is KnowledgeAction.RULE_GET:
|
|
779
757
|
if not payload.rule_id:
|
|
780
|
-
return text("❌
|
|
758
|
+
return text("❌ Provide rule_id to get details.")
|
|
781
759
|
rule = await self._service.rule_get(
|
|
782
760
|
payload.rule_id,
|
|
783
761
|
return_description=payload.return_description,
|
|
784
762
|
return_metadata=payload.return_metadata,
|
|
785
763
|
return_modes=payload.return_metadata,
|
|
786
764
|
)
|
|
787
|
-
return text(_format_rule(rule, header="📋
|
|
765
|
+
return text(_format_rule(rule, header="📋 Rule details"))
|
|
788
766
|
|
|
789
767
|
if action is KnowledgeAction.RULE_UPDATE:
|
|
790
768
|
if not payload.rule_id:
|
|
791
|
-
return text("❌
|
|
769
|
+
return text("❌ Provide rule_id to update.")
|
|
792
770
|
rule = await self._service.rule_update(
|
|
793
771
|
payload.rule_id,
|
|
794
772
|
{
|
|
@@ -799,16 +777,16 @@ class KnowledgeTool(Tool):
|
|
|
799
777
|
"metadata": payload.rule_metadata,
|
|
800
778
|
},
|
|
801
779
|
)
|
|
802
|
-
return text(_format_rule(rule, header="✅
|
|
780
|
+
return text(_format_rule(rule, header="✅ Rule updated"))
|
|
803
781
|
|
|
804
782
|
if action is KnowledgeAction.RULE_DELETE:
|
|
805
783
|
if not payload.rule_id:
|
|
806
|
-
return text("❌
|
|
784
|
+
return text("❌ Provide rule_id to remove.")
|
|
807
785
|
await self._service.rule_delete(payload.rule_id)
|
|
808
|
-
return text(f"🗑️
|
|
786
|
+
return text(f"🗑️ Rule {payload.rule_id} removed.")
|
|
809
787
|
|
|
810
788
|
return text(
|
|
811
|
-
"❌
|
|
789
|
+
"❌ Unsupported rule action.\n\nChoose one of the values:\n"
|
|
812
790
|
+ "\n".join(
|
|
813
791
|
f"- `{value}`"
|
|
814
792
|
for value in KnowledgeAction.choices()
|
|
@@ -823,11 +801,11 @@ class KnowledgeTool(Tool):
|
|
|
823
801
|
action = payload.action
|
|
824
802
|
if action is KnowledgeAction.DOC_CREATE:
|
|
825
803
|
if not payload.doc_title:
|
|
826
|
-
return text("❌
|
|
804
|
+
return text("❌ Provide doc_title to create the documentation.")
|
|
827
805
|
if payload.doc_type and payload.doc_type not in _ALLOWED_DOC_TYPES:
|
|
828
806
|
allowed = ", ".join(sorted(_ALLOWED_DOC_TYPES))
|
|
829
807
|
return text(
|
|
830
|
-
"❌ doc_type
|
|
808
|
+
"❌ Invalid doc_type. Use one of the supported values: " + allowed
|
|
831
809
|
)
|
|
832
810
|
doc = await self._service.doc_create(
|
|
833
811
|
{
|
|
@@ -838,7 +816,6 @@ class KnowledgeTool(Tool):
|
|
|
838
816
|
"doc_type": sanitize_null(payload.doc_type),
|
|
839
817
|
"language": sanitize_null(payload.doc_language),
|
|
840
818
|
"parent_id": sanitize_null(payload.doc_parent_id),
|
|
841
|
-
"team_id": sanitize_null(payload.doc_team_id or payload.team_id),
|
|
842
819
|
"owner_user_id": sanitize_null(payload.doc_owner_id),
|
|
843
820
|
"reviewer_user_id": sanitize_null(payload.doc_reviewer_id),
|
|
844
821
|
"version": sanitize_null(payload.doc_version),
|
|
@@ -849,7 +826,7 @@ class KnowledgeTool(Tool):
|
|
|
849
826
|
"is_public": payload.doc_is_public,
|
|
850
827
|
}
|
|
851
828
|
)
|
|
852
|
-
return text(_format_doc(doc, header="✅
|
|
829
|
+
return text(_format_doc(doc, header="✅ Documentation created"))
|
|
853
830
|
|
|
854
831
|
if action is KnowledgeAction.DOC_LIST:
|
|
855
832
|
docs = await self._service.doc_list(
|
|
@@ -858,26 +835,26 @@ class KnowledgeTool(Tool):
|
|
|
858
835
|
returnContent=payload.return_content,
|
|
859
836
|
)
|
|
860
837
|
if not docs:
|
|
861
|
-
return text("📄
|
|
838
|
+
return text("📄 No documentation found.")
|
|
862
839
|
body = "\n\n".join(_format_doc(doc) for doc in docs)
|
|
863
|
-
return text(f"📄 **
|
|
840
|
+
return text(f"📄 **Documents ({len(docs)}):**\n\n{body}")
|
|
864
841
|
|
|
865
842
|
if action is KnowledgeAction.DOC_GET:
|
|
866
843
|
if not payload.id:
|
|
867
|
-
return text("❌
|
|
844
|
+
return text("❌ Provide the documentation ID.")
|
|
868
845
|
doc = await self._service.doc_get(
|
|
869
846
|
payload.id,
|
|
870
847
|
returnContent=payload.return_content,
|
|
871
848
|
)
|
|
872
|
-
return text(_format_doc(doc, header="📄
|
|
849
|
+
return text(_format_doc(doc, header="📄 Documentation details"))
|
|
873
850
|
|
|
874
851
|
if action is KnowledgeAction.DOC_UPDATE:
|
|
875
852
|
if not payload.id:
|
|
876
|
-
return text("❌
|
|
853
|
+
return text("❌ Provide the documentation ID.")
|
|
877
854
|
if payload.doc_type and payload.doc_type not in _ALLOWED_DOC_TYPES:
|
|
878
855
|
allowed = ", ".join(sorted(_ALLOWED_DOC_TYPES))
|
|
879
856
|
return text(
|
|
880
|
-
"❌ doc_type
|
|
857
|
+
"❌ Invalid doc_type. Use one of the supported values: " + allowed
|
|
881
858
|
)
|
|
882
859
|
doc = await self._service.doc_update(
|
|
883
860
|
payload.id,
|
|
@@ -889,7 +866,6 @@ class KnowledgeTool(Tool):
|
|
|
889
866
|
"doc_type": sanitize_null(payload.doc_type),
|
|
890
867
|
"language": sanitize_null(payload.doc_language),
|
|
891
868
|
"parent_id": sanitize_null(payload.doc_parent_id),
|
|
892
|
-
"team_id": sanitize_null(payload.doc_team_id or payload.team_id),
|
|
893
869
|
"owner_user_id": sanitize_null(payload.doc_owner_id),
|
|
894
870
|
"reviewer_user_id": sanitize_null(payload.doc_reviewer_id),
|
|
895
871
|
"version": sanitize_null(payload.doc_version),
|
|
@@ -900,115 +876,99 @@ class KnowledgeTool(Tool):
|
|
|
900
876
|
"is_public": payload.doc_is_public,
|
|
901
877
|
},
|
|
902
878
|
)
|
|
903
|
-
return text(_format_doc(doc, header="✅
|
|
879
|
+
return text(_format_doc(doc, header="✅ Documentation updated"))
|
|
904
880
|
|
|
905
881
|
if action is KnowledgeAction.DOC_DELETE:
|
|
906
882
|
if not payload.id:
|
|
907
|
-
return text("❌
|
|
883
|
+
return text("❌ Provide the documentation ID.")
|
|
908
884
|
await self._service.doc_delete(payload.id)
|
|
909
|
-
return text(f"🗑️
|
|
885
|
+
return text(f"🗑️ Documentation {payload.id} removed.")
|
|
910
886
|
|
|
911
887
|
if action is KnowledgeAction.DOC_SEARCH:
|
|
912
888
|
query = sanitize_null(payload.query)
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
return text("❌ Informe query e team_id para buscar documentação.")
|
|
889
|
+
if not query:
|
|
890
|
+
return text("❌ Provide query to search documentation.")
|
|
916
891
|
docs = await self._service.doc_search(
|
|
917
892
|
query=query,
|
|
918
|
-
team_id=team_id,
|
|
919
893
|
limit=payload.limit,
|
|
920
894
|
)
|
|
921
895
|
if not docs:
|
|
922
|
-
return text(
|
|
923
|
-
"🔍 Nenhum documento encontrado para os filtros informados."
|
|
924
|
-
)
|
|
896
|
+
return text("🔍 No documents found for the specified filters.")
|
|
925
897
|
body = "\n\n".join(_format_doc(doc) for doc in docs)
|
|
926
|
-
return text(f"🔍 **
|
|
898
|
+
return text(f"🔍 **Results ({len(docs)}):**\n\n{body}")
|
|
927
899
|
|
|
928
900
|
if action is KnowledgeAction.DOC_ROOTS:
|
|
929
|
-
|
|
930
|
-
if not team_id:
|
|
931
|
-
return text("❌ Informe team_id para listar raízes.")
|
|
932
|
-
docs = await self._service.doc_roots(team_id=team_id)
|
|
901
|
+
docs = await self._service.doc_roots()
|
|
933
902
|
if not docs:
|
|
934
|
-
return text("📚
|
|
903
|
+
return text("📚 No roots found.")
|
|
935
904
|
body = "\n".join(
|
|
936
|
-
f"- {doc.get('title', '
|
|
905
|
+
f"- {doc.get('title', 'Untitled')} (ID: {doc.get('id')})"
|
|
937
906
|
for doc in docs
|
|
938
907
|
)
|
|
939
|
-
return text(f"📚 **
|
|
908
|
+
return text(f"📚 **Documentation roots:**\n{body}")
|
|
940
909
|
|
|
941
910
|
if action is KnowledgeAction.DOC_RECENT:
|
|
942
|
-
team_id = sanitize_null(payload.doc_team_id or payload.team_id)
|
|
943
|
-
if not team_id:
|
|
944
|
-
return text("❌ Informe team_id para listar documentos recentes.")
|
|
945
911
|
docs = await self._service.doc_recent(
|
|
946
|
-
team_id=team_id,
|
|
947
912
|
limit=payload.limit,
|
|
948
913
|
)
|
|
949
914
|
if not docs:
|
|
950
|
-
return text("🕒
|
|
915
|
+
return text("🕒 No recent documentation found.")
|
|
951
916
|
body = "\n\n".join(_format_doc(doc) for doc in docs)
|
|
952
|
-
return text(f"🕒 **
|
|
917
|
+
return text(f"🕒 **Recent documents ({len(docs)}):**\n\n{body}")
|
|
953
918
|
|
|
954
919
|
if action is KnowledgeAction.DOC_ANALYTICS:
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
return text("❌ Informe team_id para obter analytics.")
|
|
958
|
-
analytics = await self._service.doc_analytics(team_id=team_id)
|
|
959
|
-
lines = ["📊 **Analytics de Documentação**"]
|
|
920
|
+
analytics = await self._service.doc_analytics()
|
|
921
|
+
lines = ["📊 **Documentation Analytics**"]
|
|
960
922
|
for key, value in analytics.items():
|
|
961
923
|
lines.append(f"- {key}: {value}")
|
|
962
924
|
return text("\n".join(lines))
|
|
963
925
|
|
|
964
926
|
if action is KnowledgeAction.DOC_CHILDREN:
|
|
965
927
|
if not payload.id:
|
|
966
|
-
return text("❌
|
|
928
|
+
return text("❌ Provide the documentation ID.")
|
|
967
929
|
docs = await self._service.doc_children(payload.id)
|
|
968
930
|
if not docs:
|
|
969
|
-
return text("📄
|
|
931
|
+
return text("📄 No children registered for the specified document.")
|
|
970
932
|
body = "\n".join(
|
|
971
|
-
f"- {doc.get('title', '
|
|
933
|
+
f"- {doc.get('title', 'Untitled')} (ID: {doc.get('id')})"
|
|
972
934
|
for doc in docs
|
|
973
935
|
)
|
|
974
|
-
return text(f"📄 **
|
|
936
|
+
return text(f"📄 **Children:**\n{body}")
|
|
975
937
|
|
|
976
938
|
if action is KnowledgeAction.DOC_TREE:
|
|
977
939
|
if not payload.id:
|
|
978
|
-
return text("❌
|
|
940
|
+
return text("❌ Provide the documentation ID.")
|
|
979
941
|
tree = await self._service.doc_tree(payload.id)
|
|
980
|
-
return text(f"🌳
|
|
942
|
+
return text(f"🌳 **Documentation tree for {payload.id}:**\n{tree}")
|
|
981
943
|
|
|
982
944
|
if action is KnowledgeAction.DOC_FULL_TREE:
|
|
983
945
|
tree = await self._service.doc_full_tree()
|
|
984
|
-
return text(f"🌳
|
|
946
|
+
return text(f"🌳 **Full documentation tree:**\n{tree}")
|
|
985
947
|
|
|
986
948
|
if action is KnowledgeAction.DOC_MOVE:
|
|
987
949
|
if not payload.id:
|
|
988
|
-
return text("❌
|
|
950
|
+
return text("❌ Provide the documentation ID.")
|
|
989
951
|
if payload.doc_parent_id is None and payload.doc_position is None:
|
|
990
|
-
return text(
|
|
991
|
-
"❌ Informe doc_parent_id, doc_position ou ambos para mover."
|
|
992
|
-
)
|
|
952
|
+
return text("❌ Provide doc_parent_id, doc_position or both to move.")
|
|
993
953
|
move_payload = {
|
|
994
954
|
"new_parent_id": payload.doc_parent_id,
|
|
995
955
|
"new_position": payload.doc_position,
|
|
996
956
|
}
|
|
997
957
|
doc = await self._service.doc_move(payload.id, move_payload)
|
|
998
|
-
return text(_format_doc(doc, header="📦
|
|
958
|
+
return text(_format_doc(doc, header="📦 Documentation moved"))
|
|
999
959
|
|
|
1000
960
|
if action is KnowledgeAction.DOC_PUBLISH:
|
|
1001
961
|
if not payload.id:
|
|
1002
|
-
return text("❌
|
|
962
|
+
return text("❌ Provide the documentation ID.")
|
|
1003
963
|
result = await self._service.doc_publish(payload.id)
|
|
1004
|
-
return text(f"🗞️
|
|
964
|
+
return text(f"🗞️ Document published: {result}")
|
|
1005
965
|
|
|
1006
966
|
if action is KnowledgeAction.DOC_VERSION:
|
|
1007
967
|
if not payload.id:
|
|
1008
|
-
return text("❌
|
|
968
|
+
return text("❌ Provide the documentation ID.")
|
|
1009
969
|
if not payload.doc_version:
|
|
1010
970
|
return text(
|
|
1011
|
-
"❌
|
|
971
|
+
"❌ Provide doc_version with the version number/identifier."
|
|
1012
972
|
)
|
|
1013
973
|
version_payload = {
|
|
1014
974
|
"title": payload.doc_title or f"Version {payload.doc_version}",
|
|
@@ -1016,24 +976,23 @@ class KnowledgeTool(Tool):
|
|
|
1016
976
|
"content": payload.doc_content,
|
|
1017
977
|
}
|
|
1018
978
|
doc = await self._service.doc_version(payload.id, version_payload)
|
|
1019
|
-
return text(_format_doc(doc, header="🗞️
|
|
979
|
+
return text(_format_doc(doc, header="🗞️ New version created"))
|
|
1020
980
|
|
|
1021
981
|
if action is KnowledgeAction.DOC_DUPLICATE:
|
|
1022
982
|
if not payload.id:
|
|
1023
|
-
return text("❌
|
|
983
|
+
return text("❌ Provide the documentation ID.")
|
|
1024
984
|
if not payload.doc_title:
|
|
1025
|
-
return text("❌
|
|
985
|
+
return text("❌ Provide doc_title to name the copy.")
|
|
1026
986
|
doc = await self._service.doc_duplicate(
|
|
1027
987
|
payload.id,
|
|
1028
988
|
{
|
|
1029
989
|
"title": payload.doc_title,
|
|
1030
|
-
"team_id": payload.doc_team_id or payload.team_id,
|
|
1031
990
|
},
|
|
1032
991
|
)
|
|
1033
|
-
return text(_format_doc(doc, header="🗂️
|
|
992
|
+
return text(_format_doc(doc, header="🗂️ Document duplicated"))
|
|
1034
993
|
|
|
1035
994
|
return text(
|
|
1036
|
-
"❌
|
|
995
|
+
"❌ Unsupported documentation action.\n\nChoose one of the values:\n"
|
|
1037
996
|
+ "\n".join(
|
|
1038
997
|
f"- `{value}`"
|
|
1039
998
|
for value in KnowledgeAction.choices()
|
|
@@ -1043,7 +1002,7 @@ class KnowledgeTool(Tool):
|
|
|
1043
1002
|
|
|
1044
1003
|
async def _handle_help(self):
|
|
1045
1004
|
return text(
|
|
1046
|
-
"📚 **
|
|
1005
|
+
"📚 **Available actions for knowledge**\n\n"
|
|
1047
1006
|
+ KnowledgeAction.formatted_help()
|
|
1048
1007
|
)
|
|
1049
1008
|
|
|
@@ -1055,13 +1014,13 @@ def _format_work(item: Dict[str, Any], *, header: Optional[str] = None) -> str:
|
|
|
1055
1014
|
lines.append("")
|
|
1056
1015
|
|
|
1057
1016
|
# Extract title
|
|
1058
|
-
title = item.get("title") or item.get("name") or "
|
|
1017
|
+
title = item.get("title") or item.get("name") or "Untitled"
|
|
1059
1018
|
|
|
1060
1019
|
# Extract status
|
|
1061
|
-
status = item.get("status") or item.get("state") or "
|
|
1020
|
+
status = item.get("status") or item.get("state") or "unknown"
|
|
1062
1021
|
|
|
1063
1022
|
# Extract priority
|
|
1064
|
-
priority = item.get("priority") or item.get("priority_level") or "
|
|
1023
|
+
priority = item.get("priority") or item.get("priority_level") or "undefined"
|
|
1065
1024
|
|
|
1066
1025
|
# Extract ID
|
|
1067
1026
|
item_id = item.get("id", "N/A")
|
|
@@ -1080,13 +1039,13 @@ def _format_work(item: Dict[str, Any], *, header: Optional[str] = None) -> str:
|
|
|
1080
1039
|
f"🎯 **{title}**",
|
|
1081
1040
|
f"ID: {item_id}",
|
|
1082
1041
|
f"Status: {status}",
|
|
1083
|
-
f"
|
|
1084
|
-
f"
|
|
1042
|
+
f"Priority: {priority}",
|
|
1043
|
+
f"Assignee: {assignee}",
|
|
1085
1044
|
]
|
|
1086
1045
|
)
|
|
1087
1046
|
if item.get("due_date") or item.get("dueDate"):
|
|
1088
1047
|
lines.append(
|
|
1089
|
-
f"
|
|
1048
|
+
f"Due date: {_format_date(item.get('due_date') or item.get('dueDate'))}"
|
|
1090
1049
|
)
|
|
1091
1050
|
if item.get("tags"):
|
|
1092
1051
|
tags = item.get("tags", [])
|
|
@@ -1102,10 +1061,10 @@ def _format_board(board: Dict[str, Any], header: Optional[str] = None) -> str:
|
|
|
1102
1061
|
lines.append("")
|
|
1103
1062
|
lines.extend(
|
|
1104
1063
|
[
|
|
1105
|
-
f"🗂️ **{board.get('name', '
|
|
1064
|
+
f"🗂️ **{board.get('name', 'Unnamed')}**",
|
|
1106
1065
|
f"ID: {board.get('id', 'N/A')}",
|
|
1107
|
-
f"
|
|
1108
|
-
f"
|
|
1066
|
+
f"Team: {board.get('team_id', 'N/A')}",
|
|
1067
|
+
f"Columns: {len(board.get('columns', []))}",
|
|
1109
1068
|
]
|
|
1110
1069
|
)
|
|
1111
1070
|
return "\n".join(lines)
|
|
@@ -1118,19 +1077,19 @@ def _format_sprint(sprint: Dict[str, Any], header: Optional[str] = None) -> str:
|
|
|
1118
1077
|
lines.append("")
|
|
1119
1078
|
lines.extend(
|
|
1120
1079
|
[
|
|
1121
|
-
f"🏃 **{sprint.get('name', '
|
|
1080
|
+
f"🏃 **{sprint.get('name', 'Unnamed')}**",
|
|
1122
1081
|
f"ID: {sprint.get('id', 'N/A')}",
|
|
1123
1082
|
f"Status: {sprint.get('status', 'N/A')}",
|
|
1124
|
-
f"
|
|
1083
|
+
f"Team: {sprint.get('team_id', 'N/A')}",
|
|
1125
1084
|
]
|
|
1126
1085
|
)
|
|
1127
1086
|
if sprint.get("start_date") or sprint.get("startDate"):
|
|
1128
1087
|
lines.append(
|
|
1129
|
-
f"
|
|
1088
|
+
f"Start: {_format_date(sprint.get('start_date') or sprint.get('startDate'))}"
|
|
1130
1089
|
)
|
|
1131
1090
|
if sprint.get("end_date") or sprint.get("endDate"):
|
|
1132
1091
|
lines.append(
|
|
1133
|
-
f"
|
|
1092
|
+
f"End: {_format_date(sprint.get('end_date') or sprint.get('endDate'))}"
|
|
1134
1093
|
)
|
|
1135
1094
|
return "\n".join(lines)
|
|
1136
1095
|
|
|
@@ -1142,13 +1101,13 @@ def _format_mode(mode: Dict[str, Any], header: Optional[str] = None) -> str:
|
|
|
1142
1101
|
lines.append("")
|
|
1143
1102
|
lines.extend(
|
|
1144
1103
|
[
|
|
1145
|
-
f"🎭 **{mode.get('name', '
|
|
1104
|
+
f"🎭 **{mode.get('name', 'Unnamed')}**",
|
|
1146
1105
|
f"ID: {mode.get('id', 'N/A')}",
|
|
1147
|
-
f"
|
|
1106
|
+
f"Default: {mode.get('is_default', False)}",
|
|
1148
1107
|
]
|
|
1149
1108
|
)
|
|
1150
1109
|
if mode.get("description"):
|
|
1151
|
-
lines.append(f"
|
|
1110
|
+
lines.append(f"Description: {mode['description']}")
|
|
1152
1111
|
return "\n".join(lines)
|
|
1153
1112
|
|
|
1154
1113
|
|
|
@@ -1159,13 +1118,13 @@ def _format_rule(rule: Dict[str, Any], header: Optional[str] = None) -> str:
|
|
|
1159
1118
|
lines.append("")
|
|
1160
1119
|
lines.extend(
|
|
1161
1120
|
[
|
|
1162
|
-
f"📋 **{rule.get('name', '
|
|
1121
|
+
f"📋 **{rule.get('name', 'Unnamed')}**",
|
|
1163
1122
|
f"ID: {rule.get('id', 'N/A')}",
|
|
1164
|
-
f"
|
|
1123
|
+
f"Default: {rule.get('is_default', False)}",
|
|
1165
1124
|
]
|
|
1166
1125
|
)
|
|
1167
1126
|
if rule.get("description"):
|
|
1168
|
-
lines.append(f"
|
|
1127
|
+
lines.append(f"Description: {rule['description']}")
|
|
1169
1128
|
return "\n".join(lines)
|
|
1170
1129
|
|
|
1171
1130
|
|
|
@@ -1176,15 +1135,15 @@ def _format_doc(doc: Dict[str, Any], header: Optional[str] = None) -> str:
|
|
|
1176
1135
|
lines.append("")
|
|
1177
1136
|
lines.extend(
|
|
1178
1137
|
[
|
|
1179
|
-
f"📄 **{doc.get('title') or doc.get('name', '
|
|
1138
|
+
f"📄 **{doc.get('title') or doc.get('name', 'Untitled')}**",
|
|
1180
1139
|
f"ID: {doc.get('id', 'N/A')}",
|
|
1181
1140
|
f"Status: {doc.get('status', 'N/A')}",
|
|
1182
|
-
f"
|
|
1141
|
+
f"Team: {doc.get('team_id', 'N/A')}",
|
|
1183
1142
|
]
|
|
1184
1143
|
)
|
|
1185
1144
|
if doc.get("updated_at") or doc.get("updatedAt"):
|
|
1186
1145
|
lines.append(
|
|
1187
|
-
f"
|
|
1146
|
+
f"Updated at: {_format_date(doc.get('updated_at') or doc.get('updatedAt'))}"
|
|
1188
1147
|
)
|
|
1189
1148
|
return "\n".join(lines)
|
|
1190
1149
|
|