datarobot-genai 0.2.16__py3-none-any.whl → 0.2.17__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.
- datarobot_genai/drmcp/tools/clients/confluence.py +88 -0
- datarobot_genai/drmcp/tools/confluence/tools.py +48 -0
- {datarobot_genai-0.2.16.dist-info → datarobot_genai-0.2.17.dist-info}/METADATA +1 -1
- {datarobot_genai-0.2.16.dist-info → datarobot_genai-0.2.17.dist-info}/RECORD +8 -8
- {datarobot_genai-0.2.16.dist-info → datarobot_genai-0.2.17.dist-info}/WHEEL +0 -0
- {datarobot_genai-0.2.16.dist-info → datarobot_genai-0.2.17.dist-info}/entry_points.txt +0 -0
- {datarobot_genai-0.2.16.dist-info → datarobot_genai-0.2.17.dist-info}/licenses/AUTHORS +0 -0
- {datarobot_genai-0.2.16.dist-info → datarobot_genai-0.2.17.dist-info}/licenses/LICENSE +0 -0
|
@@ -59,6 +59,22 @@ class ConfluencePage(BaseModel):
|
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
|
|
62
|
+
class ConfluenceComment(BaseModel):
|
|
63
|
+
"""Pydantic model for Confluence comment."""
|
|
64
|
+
|
|
65
|
+
comment_id: str = Field(..., description="The unique comment ID")
|
|
66
|
+
page_id: str = Field(..., description="The page ID where the comment was added")
|
|
67
|
+
body: str = Field(..., description="Comment content in storage format")
|
|
68
|
+
|
|
69
|
+
def as_flat_dict(self) -> dict[str, Any]:
|
|
70
|
+
"""Return a flat dictionary representation of the comment."""
|
|
71
|
+
return {
|
|
72
|
+
"comment_id": self.comment_id,
|
|
73
|
+
"page_id": self.page_id,
|
|
74
|
+
"body": self.body,
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
|
|
62
78
|
class ConfluenceClient:
|
|
63
79
|
"""
|
|
64
80
|
Client for interacting with Confluence API using OAuth access token.
|
|
@@ -294,6 +310,78 @@ class ConfluenceClient:
|
|
|
294
310
|
|
|
295
311
|
return self._parse_response(response.json())
|
|
296
312
|
|
|
313
|
+
def _parse_comment_response(self, data: dict, page_id: str) -> ConfluenceComment:
|
|
314
|
+
"""Parse API response into ConfluenceComment."""
|
|
315
|
+
body_content = ""
|
|
316
|
+
body = data.get("body", {})
|
|
317
|
+
if isinstance(body, dict):
|
|
318
|
+
storage = body.get("storage", {})
|
|
319
|
+
if isinstance(storage, dict):
|
|
320
|
+
body_content = storage.get("value", "")
|
|
321
|
+
|
|
322
|
+
return ConfluenceComment(
|
|
323
|
+
comment_id=str(data.get("id", "")),
|
|
324
|
+
page_id=page_id,
|
|
325
|
+
body=body_content,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
async def add_comment(self, page_id: str, comment_body: str) -> ConfluenceComment:
|
|
329
|
+
"""
|
|
330
|
+
Add a comment to a Confluence page.
|
|
331
|
+
|
|
332
|
+
Args:
|
|
333
|
+
page_id: The numeric page ID where the comment will be added
|
|
334
|
+
comment_body: The text content of the comment
|
|
335
|
+
|
|
336
|
+
Returns
|
|
337
|
+
-------
|
|
338
|
+
ConfluenceComment with the created comment data
|
|
339
|
+
|
|
340
|
+
Raises
|
|
341
|
+
------
|
|
342
|
+
ConfluenceError: If page not found, permission denied, or invalid content
|
|
343
|
+
httpx.HTTPStatusError: If the API request fails with unexpected status
|
|
344
|
+
"""
|
|
345
|
+
cloud_id = await self._get_cloud_id()
|
|
346
|
+
url = f"{ATLASSIAN_API_BASE}/ex/confluence/{cloud_id}/wiki/rest/api/content"
|
|
347
|
+
|
|
348
|
+
payload: dict[str, Any] = {
|
|
349
|
+
"type": "comment",
|
|
350
|
+
"container": {"id": page_id, "type": "page"},
|
|
351
|
+
"body": {
|
|
352
|
+
"storage": {
|
|
353
|
+
"value": comment_body,
|
|
354
|
+
"representation": "storage",
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
response = await self._client.post(url, json=payload)
|
|
360
|
+
|
|
361
|
+
if response.status_code == HTTPStatus.NOT_FOUND:
|
|
362
|
+
error_msg = self._extract_error_message(response)
|
|
363
|
+
raise ConfluenceError(
|
|
364
|
+
f"Page with ID '{page_id}' not found: {error_msg}",
|
|
365
|
+
status_code=404,
|
|
366
|
+
)
|
|
367
|
+
|
|
368
|
+
if response.status_code == HTTPStatus.FORBIDDEN:
|
|
369
|
+
raise ConfluenceError(
|
|
370
|
+
f"Permission denied: you don't have access to add comments to page '{page_id}'",
|
|
371
|
+
status_code=403,
|
|
372
|
+
)
|
|
373
|
+
|
|
374
|
+
if response.status_code == HTTPStatus.BAD_REQUEST:
|
|
375
|
+
error_msg = self._extract_error_message(response)
|
|
376
|
+
raise ConfluenceError(f"Invalid request: {error_msg}", status_code=400)
|
|
377
|
+
|
|
378
|
+
if response.status_code == HTTPStatus.TOO_MANY_REQUESTS:
|
|
379
|
+
raise ConfluenceError("Rate limit exceeded. Please try again later.", status_code=429)
|
|
380
|
+
|
|
381
|
+
response.raise_for_status()
|
|
382
|
+
|
|
383
|
+
return self._parse_comment_response(response.json(), page_id)
|
|
384
|
+
|
|
297
385
|
async def __aenter__(self) -> "ConfluenceClient":
|
|
298
386
|
"""Async context manager entry."""
|
|
299
387
|
return self
|
|
@@ -138,3 +138,51 @@ async def confluence_create_page(
|
|
|
138
138
|
content=f"New page '{title}' created successfully in space '{space_key}'.",
|
|
139
139
|
structured_content={"new_page_id": page_response.page_id, "title": page_response.title},
|
|
140
140
|
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
@dr_mcp_tool(tags={"confluence", "write", "add", "comment"})
|
|
144
|
+
async def confluence_add_comment(
|
|
145
|
+
*,
|
|
146
|
+
page_id: Annotated[str, "The numeric ID of the page where the comment will be added."],
|
|
147
|
+
comment_body: Annotated[str, "The text content of the comment."],
|
|
148
|
+
) -> ToolResult:
|
|
149
|
+
"""Add a new comment to a specified Confluence page for collaboration.
|
|
150
|
+
|
|
151
|
+
Use this tool to add comments to Confluence pages to facilitate collaboration
|
|
152
|
+
and discussion. Comments are added at the page level.
|
|
153
|
+
|
|
154
|
+
Usage:
|
|
155
|
+
- Add comment: page_id="856391684", comment_body="Great work on this documentation!"
|
|
156
|
+
"""
|
|
157
|
+
if not page_id:
|
|
158
|
+
raise ToolError("Argument validation error: 'page_id' cannot be empty.")
|
|
159
|
+
|
|
160
|
+
if not comment_body:
|
|
161
|
+
raise ToolError("Argument validation error: 'comment_body' cannot be empty.")
|
|
162
|
+
|
|
163
|
+
access_token = await get_atlassian_access_token()
|
|
164
|
+
if isinstance(access_token, ToolError):
|
|
165
|
+
raise access_token
|
|
166
|
+
|
|
167
|
+
try:
|
|
168
|
+
async with ConfluenceClient(access_token) as client:
|
|
169
|
+
comment_response = await client.add_comment(
|
|
170
|
+
page_id=page_id,
|
|
171
|
+
comment_body=comment_body,
|
|
172
|
+
)
|
|
173
|
+
except ConfluenceError as e:
|
|
174
|
+
logger.error(f"Confluence error adding comment: {e}")
|
|
175
|
+
raise ToolError(str(e))
|
|
176
|
+
except Exception as e:
|
|
177
|
+
logger.error(f"Unexpected error adding comment to Confluence page: {e}")
|
|
178
|
+
raise ToolError(
|
|
179
|
+
f"An unexpected error occurred while adding comment to page '{page_id}': {str(e)}"
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
return ToolResult(
|
|
183
|
+
content=f"Comment added successfully to page ID {page_id}.",
|
|
184
|
+
structured_content={
|
|
185
|
+
"comment_id": comment_response.comment_id,
|
|
186
|
+
"page_id": page_id,
|
|
187
|
+
},
|
|
188
|
+
)
|
|
@@ -76,11 +76,11 @@ datarobot_genai/drmcp/test_utils/utils.py,sha256=esGKFv8aO31-Qg3owayeWp32BYe1CdY
|
|
|
76
76
|
datarobot_genai/drmcp/tools/__init__.py,sha256=0kq9vMkF7EBsS6lkEdiLibmUrghTQqosHbZ5k-V9a5g,578
|
|
77
77
|
datarobot_genai/drmcp/tools/clients/__init__.py,sha256=0kq9vMkF7EBsS6lkEdiLibmUrghTQqosHbZ5k-V9a5g,578
|
|
78
78
|
datarobot_genai/drmcp/tools/clients/atlassian.py,sha256=__M_uz7FrcbKCYRzeMn24DCEYD6OmFx_LuywHCxgXsA,6472
|
|
79
|
-
datarobot_genai/drmcp/tools/clients/confluence.py,sha256=
|
|
79
|
+
datarobot_genai/drmcp/tools/clients/confluence.py,sha256=gDzy8t5t3b1mwEr-CuZ5BwXXQ52AXke8J_Ra7i_8T1g,13692
|
|
80
80
|
datarobot_genai/drmcp/tools/clients/jira.py,sha256=Rm91JAyrNIqxu66-9rU1YqoRXVnWbEy-Ahvy6f6HlVg,9823
|
|
81
81
|
datarobot_genai/drmcp/tools/clients/s3.py,sha256=GmwzvurFdNfvxOooA8g5S4osRysHYU0S9ypg_177Glg,953
|
|
82
82
|
datarobot_genai/drmcp/tools/confluence/__init__.py,sha256=0kq9vMkF7EBsS6lkEdiLibmUrghTQqosHbZ5k-V9a5g,578
|
|
83
|
-
datarobot_genai/drmcp/tools/confluence/tools.py,sha256=
|
|
83
|
+
datarobot_genai/drmcp/tools/confluence/tools.py,sha256=jSF7yXGFqqlMcavkRIY4HbMxb7tCeunA2ST41wa2vGI,7219
|
|
84
84
|
datarobot_genai/drmcp/tools/jira/__init__.py,sha256=0kq9vMkF7EBsS6lkEdiLibmUrghTQqosHbZ5k-V9a5g,578
|
|
85
85
|
datarobot_genai/drmcp/tools/jira/tools.py,sha256=dfkqTU2HH-7n44hX80ODFacKq0p0LOchFcZtIIKFNMM,9687
|
|
86
86
|
datarobot_genai/drmcp/tools/predictive/__init__.py,sha256=WuOHlNNEpEmcF7gVnhckruJRKU2qtmJLE3E7zoCGLDo,1030
|
|
@@ -106,9 +106,9 @@ datarobot_genai/nat/datarobot_llm_clients.py,sha256=Yu208Ed_p_4P3HdpuM7fYnKcXtim
|
|
|
106
106
|
datarobot_genai/nat/datarobot_llm_providers.py,sha256=aDoQcTeGI-odqydPXEX9OGGNFbzAtpqzTvHHEkmJuEQ,4963
|
|
107
107
|
datarobot_genai/nat/datarobot_mcp_client.py,sha256=35FzilxNp4VqwBYI0NsOc91-xZm1C-AzWqrOdDy962A,9612
|
|
108
108
|
datarobot_genai/nat/helpers.py,sha256=Q7E3ADZdtFfS8E6OQPyw2wgA6laQ58N3bhLj5CBWwJs,3265
|
|
109
|
-
datarobot_genai-0.2.
|
|
110
|
-
datarobot_genai-0.2.
|
|
111
|
-
datarobot_genai-0.2.
|
|
112
|
-
datarobot_genai-0.2.
|
|
113
|
-
datarobot_genai-0.2.
|
|
114
|
-
datarobot_genai-0.2.
|
|
109
|
+
datarobot_genai-0.2.17.dist-info/METADATA,sha256=FAAExscPOUIc1_sTNKY3DPTygcVtfrql4fubM9b6nDg,6301
|
|
110
|
+
datarobot_genai-0.2.17.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
111
|
+
datarobot_genai-0.2.17.dist-info/entry_points.txt,sha256=jEW3WxDZ8XIK9-ISmTyt5DbmBb047rFlzQuhY09rGrM,284
|
|
112
|
+
datarobot_genai-0.2.17.dist-info/licenses/AUTHORS,sha256=isJGUXdjq1U7XZ_B_9AH8Qf0u4eX0XyQifJZ_Sxm4sA,80
|
|
113
|
+
datarobot_genai-0.2.17.dist-info/licenses/LICENSE,sha256=U2_VkLIktQoa60Nf6Tbt7E4RMlfhFSjWjcJJfVC-YCE,11341
|
|
114
|
+
datarobot_genai-0.2.17.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|