devrev-Python-SDK 3.0.4__py3-none-any.whl → 3.1.1__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.
devrev/client.py CHANGED
@@ -42,10 +42,6 @@ from devrev.services.rev_orgs import AsyncRevOrgsService, RevOrgsService
42
42
  from devrev.services.rev_users import AsyncRevUsersService, RevUsersService
43
43
  from devrev.services.search import AsyncSearchService, SearchService
44
44
  from devrev.services.slas import AsyncSlasService, SlasService
45
- from devrev.services.survey_responses import (
46
- AsyncSurveyResponsesService,
47
- SurveyResponsesService,
48
- )
49
45
  from devrev.services.tags import AsyncTagsService, TagsService
50
46
  from devrev.services.timeline_entries import (
51
47
  AsyncTimelineEntriesService,
@@ -168,7 +164,6 @@ class DevRevClient:
168
164
  self._rev_orgs = RevOrgsService(self._http)
169
165
  self._rev_users = RevUsersService(self._http)
170
166
  self._slas = SlasService(self._http)
171
- self._survey_responses = SurveyResponsesService(self._http)
172
167
  self._tags = TagsService(self._http)
173
168
  self._timeline_entries = TimelineEntriesService(self._http)
174
169
  self._webhooks = WebhooksService(self._http)
@@ -264,11 +259,6 @@ class DevRevClient:
264
259
  """Access the SLAs service."""
265
260
  return self._slas
266
261
 
267
- @property
268
- def survey_responses(self) -> SurveyResponsesService:
269
- """Access the Survey Responses service."""
270
- return self._survey_responses
271
-
272
262
  @property
273
263
  def tags(self) -> TagsService:
274
264
  """Access the Tags service."""
@@ -502,7 +492,6 @@ class AsyncDevRevClient:
502
492
  self._rev_orgs = AsyncRevOrgsService(self._http)
503
493
  self._rev_users = AsyncRevUsersService(self._http)
504
494
  self._slas = AsyncSlasService(self._http)
505
- self._survey_responses = AsyncSurveyResponsesService(self._http)
506
495
  self._tags = AsyncTagsService(self._http)
507
496
  self._timeline_entries = AsyncTimelineEntriesService(self._http)
508
497
  self._webhooks = AsyncWebhooksService(self._http)
@@ -598,11 +587,6 @@ class AsyncDevRevClient:
598
587
  """Access the SLAs service."""
599
588
  return self._slas
600
589
 
601
- @property
602
- def survey_responses(self) -> AsyncSurveyResponsesService:
603
- """Access the Survey Responses service."""
604
- return self._survey_responses
605
-
606
590
  @property
607
591
  def tags(self) -> AsyncTagsService:
608
592
  """Access the Tags service."""
devrev/models/__init__.py CHANGED
@@ -328,12 +328,6 @@ from devrev.models.slas import (
328
328
  SlasUpdateResponse,
329
329
  SlaTrackerStatus,
330
330
  )
331
- from devrev.models.survey_responses import (
332
- SurveyResponse,
333
- SurveyResponsesListMode,
334
- SurveyResponsesListRequest,
335
- SurveyResponsesListResponse,
336
- )
337
331
  from devrev.models.sync import (
338
332
  ExternalRef,
339
333
  StagedInfo,
@@ -705,11 +699,6 @@ __all__ = [
705
699
  "QuestionAnswersUpdateRequest",
706
700
  "QuestionAnswersUpdateResponse",
707
701
  "QuestionAnswersDeleteRequest",
708
- # Survey Responses
709
- "SurveyResponse",
710
- "SurveyResponsesListMode",
711
- "SurveyResponsesListRequest",
712
- "SurveyResponsesListResponse",
713
702
  # Recommendations
714
703
  "MessageRole",
715
704
  "ChatMessage",
devrev/models/works.py CHANGED
@@ -96,48 +96,6 @@ class Work(DevRevResponseModel):
96
96
  actual_close_date: datetime | None = Field(default=None, description="Actual close date")
97
97
  custom_fields: dict[str, Any] | None = Field(default=None, description="Custom fields")
98
98
  external_ref: str | None = Field(default=None, description="External reference")
99
- account: dict[str, Any] | str | None = Field(
100
- default=None,
101
- description="Account associated with the ticket/work, when returned by the API",
102
- )
103
- rev_org: dict[str, Any] | str | None = Field(
104
- default=None,
105
- description="Rev organization associated with the ticket/work",
106
- )
107
- sentiment: dict[str, Any] | str | None = Field(
108
- default=None,
109
- description="Current ticket sentiment, when returned by the API",
110
- )
111
- sentiment_summary: dict[str, Any] | str | None = Field(
112
- default=None,
113
- description="Structured or textual sentiment summary",
114
- )
115
- sentiment_modified_date: datetime | None = Field(
116
- default=None,
117
- description="When ticket sentiment was last modified",
118
- )
119
- sla_summary: dict[str, Any] | None = Field(default=None, description="Ticket SLA summary")
120
- needs_response: bool | None = Field(
121
- default=None,
122
- description="Whether the ticket needs a customer response",
123
- )
124
- channels: list[dict[str, Any] | str] | None = Field(
125
- default=None,
126
- description="Channels associated with the ticket",
127
- )
128
- source_channel: dict[str, Any] | str | None = Field(
129
- default=None,
130
- description="Source channel that created the ticket",
131
- )
132
- group: dict[str, Any] | str | None = Field(
133
- default=None,
134
- description="Group associated with the work item",
135
- )
136
- is_frozen: bool | None = Field(default=None, description="Whether the work item is frozen")
137
- visibility: dict[str, Any] | str | None = Field(
138
- default=None,
139
- description="Work item visibility, when returned by the API",
140
- )
141
99
 
142
100
 
143
101
  class WorkSummary(DevRevResponseModel):
@@ -38,7 +38,6 @@ from devrev.services.rev_orgs import AsyncRevOrgsService, RevOrgsService
38
38
  from devrev.services.rev_users import AsyncRevUsersService, RevUsersService
39
39
  from devrev.services.search import AsyncSearchService, SearchService
40
40
  from devrev.services.slas import AsyncSlasService, SlasService
41
- from devrev.services.survey_responses import AsyncSurveyResponsesService, SurveyResponsesService
42
41
  from devrev.services.tags import AsyncTagsService, TagsService
43
42
  from devrev.services.timeline_entries import (
44
43
  AsyncTimelineEntriesService,
@@ -113,9 +112,6 @@ __all__ = [
113
112
  # SLAs
114
113
  "SlasService",
115
114
  "AsyncSlasService",
116
- # Survey Responses
117
- "SurveyResponsesService",
118
- "AsyncSurveyResponsesService",
119
115
  # Tags
120
116
  "TagsService",
121
117
  "AsyncTagsService",
devrev/services/works.py CHANGED
@@ -147,21 +147,6 @@ class WorksService(BaseService):
147
147
  response = self._post("/works.get", request, WorksGetResponse)
148
148
  return response.work
149
149
 
150
- def get_raw(self, id: str) -> dict[str, Any]:
151
- """Get the raw API payload for a work item.
152
-
153
- Use this supported escape hatch when the DevRev API returns fields that
154
- are not yet represented on the typed :class:`Work` model.
155
-
156
- Args:
157
- id: Work item ID
158
-
159
- Returns:
160
- Raw ``/works.get`` response payload.
161
- """
162
- request = WorksGetRequest(id=id)
163
- return self._post("/works.get", request)
164
-
165
150
  def list(
166
151
  self,
167
152
  *,
@@ -454,11 +439,6 @@ class AsyncWorksService(AsyncBaseService):
454
439
  response = await self._post("/works.get", request, WorksGetResponse)
455
440
  return response.work
456
441
 
457
- async def get_raw(self, id: str) -> dict[str, Any]:
458
- """Get the raw API payload for a work item."""
459
- request = WorksGetRequest(id=id)
460
- return await self._post("/works.get", request)
461
-
462
442
  async def list(
463
443
  self,
464
444
  *,
devrev_mcp/server.py CHANGED
@@ -249,6 +249,7 @@ from devrev_mcp.tools import slas as _slas_tools # noqa: E402, F401
249
249
  from devrev_mcp.tools import tags as _tags_tools # noqa: E402, F401
250
250
  from devrev_mcp.tools import timeline as _timeline_tools # noqa: E402, F401
251
251
  from devrev_mcp.tools import users as _users_tools # noqa: E402, F401
252
+ from devrev_mcp.tools import webhooks as _webhooks_tools # noqa: E402, F401
252
253
  from devrev_mcp.tools import works as _works_tools # noqa: E402, F401
253
254
 
254
255
  # Beta tools (only if beta tools are enabled)
@@ -0,0 +1,153 @@
1
+ """MCP tools for DevRev webhook operations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from typing import Any
7
+
8
+ from mcp.server.fastmcp import Context
9
+
10
+ from devrev.exceptions import DevRevError
11
+ from devrev.models.webhooks import (
12
+ WebhooksCreateRequest,
13
+ WebhooksDeleteRequest,
14
+ WebhooksGetRequest,
15
+ WebhooksListRequest,
16
+ WebhookStatus,
17
+ WebhooksUpdateRequest,
18
+ )
19
+ from devrev_mcp.server import _config, mcp
20
+ from devrev_mcp.utils.don_id import validate_don_id
21
+ from devrev_mcp.utils.errors import format_devrev_error
22
+ from devrev_mcp.utils.formatting import serialize_model, serialize_models
23
+ from devrev_mcp.utils.pagination import clamp_page_size
24
+
25
+ logger = logging.getLogger(__name__)
26
+
27
+
28
+ @mcp.tool()
29
+ async def devrev_webhooks_list(
30
+ ctx: Context[Any, Any, Any],
31
+ cursor: str | None = None,
32
+ limit: int | None = None,
33
+ ) -> dict[str, Any]:
34
+ """List DevRev webhooks.
35
+
36
+ Args:
37
+ cursor: Pagination cursor from a previous response.
38
+ limit: Maximum number of items to return (default: 25, max: 100).
39
+ """
40
+ app = ctx.request_context.lifespan_context
41
+ try:
42
+ request = WebhooksListRequest(
43
+ cursor=cursor,
44
+ limit=clamp_page_size(
45
+ limit, default=app.config.default_page_size, maximum=app.config.max_page_size
46
+ ),
47
+ )
48
+ webhooks = await app.get_client().webhooks.list(request)
49
+ items = serialize_models(list(webhooks))
50
+ return {"count": len(items), "webhooks": items}
51
+ except DevRevError as e:
52
+ raise RuntimeError(format_devrev_error(e)) from e
53
+
54
+
55
+ @mcp.tool()
56
+ async def devrev_webhooks_get(
57
+ ctx: Context[Any, Any, Any],
58
+ id: str,
59
+ ) -> dict[str, Any]:
60
+ """Get a DevRev webhook by ID.
61
+
62
+ Args:
63
+ id: Webhook ID (e.g., "don:integration:dvrv-us-1:devo/1:webhook/123").
64
+ """
65
+ validate_don_id(id, "webhook", "devrev_webhooks_get")
66
+ app = ctx.request_context.lifespan_context
67
+ try:
68
+ request = WebhooksGetRequest(id=id)
69
+ webhook = await app.get_client().webhooks.get(request)
70
+ return serialize_model(webhook)
71
+ except DevRevError as e:
72
+ raise RuntimeError(format_devrev_error(e)) from e
73
+
74
+
75
+ # Destructive tools (only registered when enabled)
76
+ if _config.enable_destructive_tools:
77
+
78
+ @mcp.tool()
79
+ async def devrev_webhooks_create(
80
+ ctx: Context[Any, Any, Any],
81
+ url: str,
82
+ event_types: list[str] | None = None,
83
+ secret: str | None = None,
84
+ ) -> dict[str, Any]:
85
+ """Create a new DevRev webhook.
86
+
87
+ Args:
88
+ url: Target URL that will receive webhook event POSTs.
89
+ event_types: Event types to subscribe to (default: all events).
90
+ secret: Shared secret used to sign and verify webhook payloads.
91
+ """
92
+ app = ctx.request_context.lifespan_context
93
+ try:
94
+ request = WebhooksCreateRequest(url=url, event_types=event_types, secret=secret)
95
+ webhook = await app.get_client().webhooks.create(request)
96
+ return serialize_model(webhook)
97
+ except DevRevError as e:
98
+ raise RuntimeError(format_devrev_error(e)) from e
99
+
100
+ @mcp.tool()
101
+ async def devrev_webhooks_update(
102
+ ctx: Context[Any, Any, Any],
103
+ id: str,
104
+ url: str | None = None,
105
+ event_types: list[str] | None = None,
106
+ status: str | None = None,
107
+ ) -> dict[str, Any]:
108
+ """Update a DevRev webhook.
109
+
110
+ Args:
111
+ id: Webhook ID to update.
112
+ url: New target URL.
113
+ event_types: New list of event types to subscribe to.
114
+ status: New status (active, inactive, unverified).
115
+ """
116
+ validate_don_id(id, "webhook", "devrev_webhooks_update")
117
+ app = ctx.request_context.lifespan_context
118
+ try:
119
+ resolved_status: WebhookStatus | None = None
120
+ if status is not None:
121
+ try:
122
+ resolved_status = WebhookStatus(status.lower())
123
+ except ValueError as e:
124
+ raise RuntimeError(
125
+ f"Invalid webhook status '{status}'. "
126
+ "Valid values: active, inactive, unverified."
127
+ ) from e
128
+ request = WebhooksUpdateRequest(
129
+ id=id, url=url, event_types=event_types, status=resolved_status
130
+ )
131
+ webhook = await app.get_client().webhooks.update(request)
132
+ return serialize_model(webhook)
133
+ except DevRevError as e:
134
+ raise RuntimeError(format_devrev_error(e)) from e
135
+
136
+ @mcp.tool()
137
+ async def devrev_webhooks_delete(
138
+ ctx: Context[Any, Any, Any],
139
+ id: str,
140
+ ) -> dict[str, Any]:
141
+ """Delete a DevRev webhook.
142
+
143
+ Args:
144
+ id: Webhook ID to delete.
145
+ """
146
+ validate_don_id(id, "webhook", "devrev_webhooks_delete")
147
+ app = ctx.request_context.lifespan_context
148
+ try:
149
+ request = WebhooksDeleteRequest(id=id)
150
+ await app.get_client().webhooks.delete(request)
151
+ return {"deleted": True, "id": id}
152
+ except DevRevError as e:
153
+ raise RuntimeError(format_devrev_error(e)) from e
@@ -35,6 +35,7 @@ DON_TYPE_MAP: dict[str, str] = {
35
35
  "qa": "question_answer",
36
36
  "question_answer": "question_answer",
37
37
  "timeline_entry": "timeline_entry",
38
+ "webhook": "webhook",
38
39
  }
39
40
 
40
41
  TOOL_SUGGESTIONS: dict[str, str] = {
@@ -57,6 +58,7 @@ TOOL_SUGGESTIONS: dict[str, str] = {
57
58
  "qa": "devrev_question_answers_get",
58
59
  "question_answer": "devrev_question_answers_get",
59
60
  "timeline_entry": "devrev_timeline_get",
61
+ "webhook": "devrev_webhooks_get",
60
62
  }
61
63
 
62
64
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: devrev-Python-SDK
3
- Version: 3.0.4
3
+ Version: 3.1.1
4
4
  Summary: A modern, type-safe Python SDK for the DevRev API
5
5
  Project-URL: Homepage, https://github.com/mgmonteleone/py-dev-rev
6
6
  Project-URL: Documentation, https://github.com/mgmonteleone/py-dev-rev
@@ -75,7 +75,7 @@ Description-Content-Type: text/markdown
75
75
 
76
76
  # py-devrev
77
77
 
78
- A modern, type-safe Python SDK for the DevRev API.
78
+ A modern, type-safe Python SDK and MCP for the DevRev API.
79
79
 
80
80
  [![Built with Augment](https://img.shields.io/badge/Built%20with-Auggie-6366f1?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0id2hpdGUiPjxwYXRoIGQ9Ik0xMiAyTDIgMTloMjBMMTIgMnptMCAzLjc1TDE4LjI1IDE3SDUuNzVMMTIgNS43NXoiLz48L3N2Zz4=)](https://www.augmentcode.com/)
81
81
  [![PyPI Version](https://img.shields.io/pypi/v/devrev-python-sdk.svg)](https://pypi.org/project/devrev-Python-SDK/)
@@ -159,7 +159,7 @@ This SDK is generated and maintained from the official DevRev OpenAPI specificat
159
159
 
160
160
  ### MCP Server (AI Integration)
161
161
 
162
- - ✅ **78+ MCP Tools** — Full CRUD for tickets, accounts, users, articles, and all DevRev resources
162
+ - ✅ **83+ MCP Tools** — Full CRUD for tickets, accounts, users, articles, webhooks, and all DevRev resources
163
163
  - ✅ **7 Resource Templates** — `devrev://` URI scheme for AI-accessible data browsing
164
164
  - ✅ **8 Workflow Prompts** — Pre-built triage, escalation, investigation, and reporting workflows
165
165
  - ✅ **3 Transport Modes** — stdio (local), Streamable HTTP (production), SSE (legacy)
@@ -215,17 +215,6 @@ for account in accounts:
215
215
  work = client.works.get(id="don:core:...")
216
216
  print(f"Work: {work.title} - Status: {work.stage.name}")
217
217
 
218
- # Ticket integrations can read optional account/sentiment/SLA fields
219
- ticket = client.works.get(id="don:core:dvrv-us-1:devo/1:ticket/123")
220
- print(ticket.rev_org, ticket.account, ticket.needs_response)
221
-
222
- # Use a supported raw escape hatch when the API returns newer fields
223
- raw_ticket = client.works.get_raw(id="don:core:dvrv-us-1:devo/1:ticket/123")
224
- print(raw_ticket["work"].keys())
225
-
226
- # List survey/CSAT responses for a ticket without using private _http
227
- survey_responses = client.survey_responses.list(object_id=ticket.id)
228
-
229
218
  # Create a new ticket
230
219
  ticket = client.works.create(
231
220
  title="Bug: Login page not loading",
@@ -308,7 +297,6 @@ The SDK provides complete coverage of all 209 DevRev public API endpoints, organ
308
297
  |---------|-----------|-------------|
309
298
  | **Articles** | 5 | Knowledge base articles |
310
299
  | **Conversations** | 5 | Customer conversations |
311
- | **Survey Responses** | 1 | Survey and CSAT response listing |
312
300
  | **Timeline Entries** | 5 | Activity timeline management |
313
301
  | **Tags** | 5 | Tagging and categorization |
314
302
 
@@ -737,7 +725,7 @@ The DevRev MCP Server exposes the full DevRev platform as [Model Context Protoco
737
725
 
738
726
  ### MCP Server Features
739
727
 
740
- - **78+ MCP Tools** — Full CRUD for tickets, accounts, users, conversations, articles, parts, tags, groups, timeline, links, SLAs, plus beta tools (search, recommendations, incidents, engagements)
728
+ - **83+ MCP Tools** — Full CRUD for tickets, accounts, users, conversations, articles, parts, tags, groups, timeline, links, SLAs, webhooks, plus beta tools (search, recommendations, incidents, engagements)
741
729
  - **7 Resource Templates** — `devrev://` URI scheme for browsing tickets, accounts, articles, users, parts, conversations
742
730
  - **8 Workflow Prompts** — Triage, draft response, escalate, summarize account, investigate, weekly report, find similar, onboard customer
743
731
  - **3 Transports** — stdio (local dev), Streamable HTTP (production), SSE (legacy)
@@ -1,9 +1,9 @@
1
1
  devrev/__init__.py,sha256=iBKIRvS10mFWpBgnMjQQiQR04rgb8ZyXVk1-7cYJikI,1555
2
- devrev/client.py,sha256=-1brQGZzGYceA9pv3moeTQy8riMSHAz3_9eBy6TtYKM,27038
2
+ devrev/client.py,sha256=FXEadZd0NzBUzXXY60e4qnN2Osv5vHE_9rj8nPpVPxI,26458
3
3
  devrev/config.py,sha256=BKFhD8lMJvq-I9kpchiA50fYefVFhnNwcK9ReFogh4k,8122
4
4
  devrev/exceptions.py,sha256=Bs0pYgOgG26cyI785rdJeTR72gM-rXHaCEt24HAJzEk,7540
5
5
  devrev/py.typed,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
6
- devrev/models/__init__.py,sha256=T0ZSZIo43Qe51XCKs05lYagJDjJMsOIiclzrYL1OtJw,24339
6
+ devrev/models/__init__.py,sha256=D9J3kwZrAUJijh4wuLbfvb7WbokL84_dRg93OxtT_k4,24033
7
7
  devrev/models/accounts.py,sha256=LrXAit2gIr34XyRO1T0fL6EwdXHsfJOyXwcegPnKnaE,6974
8
8
  devrev/models/articles.py,sha256=DgrZC_wtLsXIfilAvHJBoQkhbGDg3Vx5UX7h9MD63xA,16732
9
9
  devrev/models/artifacts.py,sha256=3iA58RyVlX0S0U5iID3Cnoc096Y70QfGqYfKEhxfE9g,4375
@@ -25,7 +25,6 @@ devrev/models/rev_orgs.py,sha256=tVJiPezfBe6MN-jgfQtp0Efh6RkLIJs4LAXutuWbwp8,621
25
25
  devrev/models/rev_users.py,sha256=8psDrbQQQkG2rM7JRfRZYgyxv2FFvhSxXaDMZy0Y8_4,10136
26
26
  devrev/models/search.py,sha256=_5OhgVz1yaqK00-rSJrG3xacp22qByYQq5HSnS1inV8,4650
27
27
  devrev/models/slas.py,sha256=U7nForRREIBV-KpTxrDsPPpyzCNwb7yHeeB94pk7Mfw,3272
28
- devrev/models/survey_responses.py,sha256=fHJoW4jvGHJM7W2guPzEJ1G-ErgH3gXOYqJfUc4PwdQ,3484
29
28
  devrev/models/sync.py,sha256=_Wef7zgI1aYG9GBWXVTO3_oktY0SIdMuEbwLcGTJTUM,5407
30
29
  devrev/models/tags.py,sha256=5IDRerA3bUxSRVcGjvwCheRzOpgjI4AU8Rh1LYNT6tk,2473
31
30
  devrev/models/tasks.py,sha256=OLffCAEegv-8z0oXDCGXB4KiXuobizrOZ-RjILGs6f4,5055
@@ -35,8 +34,8 @@ devrev/models/track_events.py,sha256=bb9belz1W3XvrUEgp9mGdOKELhRcWL-59wS9cIa1geY
35
34
  devrev/models/uoms.py,sha256=bxjk2YhJ3qrX6C52xuokgLCHD3K4-8DRDeu2QwjnK4E,5700
36
35
  devrev/models/webhooks.py,sha256=DzrLJiW1GYWvfaB-aVPcYCf4XkEGHz3dkyzbBKKdhFI,3655
37
36
  devrev/models/widgets.py,sha256=7WWN17_ySqnu1pjYSIS5B8J5dEaqkoB8X8GWzvI0ZYc,4577
38
- devrev/models/works.py,sha256=n6iIkUMmhGbT9bXCeDc9QphOlHSNdLK8X4dLLqW0Qec,12870
39
- devrev/services/__init__.py,sha256=Uhhc3TY15iwPe1DV-QqZoX0H5kKbyBwWVWmwMitbkGc,4160
37
+ devrev/models/works.py,sha256=sHZ_eJ6eCadWxPkM6HGcmbkiGRDYT2RnH3QZRO4T3tY,11198
38
+ devrev/services/__init__.py,sha256=LWy_0xGNH692d6Wc4S4E9v6AoxjgfExFMzFmbrL2NTY,3975
40
39
  devrev/services/_pagination.py,sha256=J6AXu1P3iNRyC8_nH709Z8nOLhHeSctOLRmY_eYI6QA,2100
41
40
  devrev/services/accounts.py,sha256=X7FgcODex0XKLiV_VvXKDl2Jm8XsNpn9qp40oRjZqME,9704
42
41
  devrev/services/articles.py,sha256=xOpJOG9f29a5W3IFROplL1a9eJdGucbUFkK-MAIIYlc,41637
@@ -59,13 +58,12 @@ devrev/services/rev_orgs.py,sha256=I7oiZZNKJ1PRApUyfjFab2ke-Ox39JBGambzvAMusKY,7
59
58
  devrev/services/rev_users.py,sha256=-QfGNUzz6MQbG4n51F5WzjRxcdIGrrHB_PzjUX7rI38,15472
60
59
  devrev/services/search.py,sha256=qxXtYRgGCxkw35CazNxIkCUWsSuv1NCWxr6nVTyKFvQ,12341
61
60
  devrev/services/slas.py,sha256=9n6mdZ8E9vDrO4CeV4snc6IwyjDdoTQjQpjFw1oT4ag,2786
62
- devrev/services/survey_responses.py,sha256=vSmlMIQnKQxc10-3GNBM21NMuRZ9wk73s_8yIMKjKu8,4647
63
61
  devrev/services/tags.py,sha256=1Xmq6VFIvL2OTCJ48PeLkTcZm2aa2BJ7OjbZVHd8rbU,2642
64
62
  devrev/services/timeline_entries.py,sha256=6nbVPcWlE3-ohLhvkM421eqYS5ztKtHmGsPek5WoT_Q,3362
65
63
  devrev/services/track_events.py,sha256=lI4wXkWu3uUuXtuRg1MGNkTZ7B0Lc1PjM8Kw-6sUnWc,1439
66
64
  devrev/services/uoms.py,sha256=AA3ymoHj24FIbsZpYC4tg2elSdQ3iINTVOz7MraZcj8,8163
67
65
  devrev/services/webhooks.py,sha256=-TSkcaya1y48WB24_vHd-bqO5xSqxRsCLiilncNzQZU,3917
68
- devrev/services/works.py,sha256=kt7B9goqgSJqAwTWDa4tvBZ-OdERMsTow5GHviWxUG4,21127
66
+ devrev/services/works.py,sha256=hAK7ZUqLph5Db15p4RDbeRFLZUALAF5tCFOQSYytj_g,20456
69
67
  devrev/utils/__init__.py,sha256=NOrbpkjDVLH8n9xf-xpZJiIIa_GVI_6vqTm3E8L3Udw,857
70
68
  devrev/utils/content_converter.py,sha256=emRBLiVoOfDGpPDzrMRnqQr4-QkqN13OdWlYOyU_LCg,28141
71
69
  devrev/utils/deprecation.py,sha256=7qB2Dx531oP7mNi7q2txOYsOKC9YwdHqlKPMFHOW9Ws,1275
@@ -75,7 +73,7 @@ devrev/utils/pagination.py,sha256=zsAZdGw2eGs2p5XEFX-Dng3zjsP-ERsUqQn7PWmI9Oc,48
75
73
  devrev_mcp/__init__.py,sha256=-VAlWWe5rx2UqfOUK8L2Evr28FEfapEmMKgYpCbVxjQ,216
76
74
  devrev_mcp/__main__.py,sha256=PfuBYR0I4yIj1CqTikFBcqB_TNo34R1I5_8bv0D2ekc,1521
77
75
  devrev_mcp/config.py,sha256=4GllGfYM6k7OixEKfR9JH_TE1F7LFeCbDo1bLEC9ACA,4002
78
- devrev_mcp/server.py,sha256=ZI0ZzMkcv8Ug-F7Ez1wLI2slJ2e3KyHZhxYtyW1eaGg,18597
76
+ devrev_mcp/server.py,sha256=4Zhkom-2LQ0qo91o70Uif9U0uSqwFAZ9Xip74ihhmxw,18674
79
77
  devrev_mcp/middleware/__init__.py,sha256=QphqWGURVzKXWJ0oLJ5Qub6V33z5YyQwN5r6Gue6hd8,52
80
78
  devrev_mcp/middleware/audit.py,sha256=PRnyNCobXSJnSqVh4Z5K8b7jauNOTMSiMEIjKcd1s2A,13459
81
79
  devrev_mcp/middleware/auth.py,sha256=wgdYZEWxBIAj7XAc8c95ct9aZ1aUQ6s29SiWuUW6IiU,16214
@@ -113,13 +111,14 @@ devrev_mcp/tools/slas.py,sha256=q7eYC7nMxCGoHMDp1QbtCgSWiG4oHk78sydPtYwsh10,4902
113
111
  devrev_mcp/tools/tags.py,sha256=zj_my9CkPQu8_TTOqszfLULPNgxm83kHux-rWFxHvXQ,4711
114
112
  devrev_mcp/tools/timeline.py,sha256=p7P699Oq205jrzCVyYS6v4bXHEQizircHVyS5JE-GJ4,5326
115
113
  devrev_mcp/tools/users.py,sha256=7CtrxjgxniEb5-DaPh0rwL680a2fDFLJSIU5huuTjYE,4896
114
+ devrev_mcp/tools/webhooks.py,sha256=UdoKxZprZygVopqYYf02RF84HVCL-gJBpTNm0jrw_QI,5166
116
115
  devrev_mcp/tools/works.py,sha256=IFaIXYR4j_2pZ39ykZgdHdo5nCk8OfgWU5bxBdHwp5E,15241
117
116
  devrev_mcp/utils/__init__.py,sha256=2_5b1KC5kjoUqFY1ZSdB2Tefd2ekjbZ-eHyFWBKI-0A,49
118
- devrev_mcp/utils/don_id.py,sha256=PAVzOSgaiqJQSdo1fwohFHq2x7PDNUZoBTN4LFGYM48,6294
117
+ devrev_mcp/utils/don_id.py,sha256=jbVKXW_BeKjPHhz1F9p14fNmrXP2R36rgWZqdC4QlOc,6358
119
118
  devrev_mcp/utils/errors.py,sha256=5mRAo76rJvvEVi6b1ZokPxDtX5JKkptaqmiYDLCkwBE,2110
120
119
  devrev_mcp/utils/formatting.py,sha256=6JssG5x1BxjdgSiQ8Ou3H-9Wo3wgWTWmejsrGez4wKc,2431
121
120
  devrev_mcp/utils/pagination.py,sha256=EOUgL-ZdSToM1Q-ydXmjhibsef5K1u1g3CaS9K8I2fY,1286
122
- devrev_python_sdk-3.0.4.dist-info/METADATA,sha256=33y0aBX1_t124x48Ng5w-pSBTBc6DNEaT4dXYV3qsKo,41490
123
- devrev_python_sdk-3.0.4.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
124
- devrev_python_sdk-3.0.4.dist-info/entry_points.txt,sha256=XiV4J_yy0yzVZVxg7T66YERVIlqdPNp3O-NHTHkllqQ,63
125
- devrev_python_sdk-3.0.4.dist-info/RECORD,,
121
+ devrev_python_sdk-3.1.1.dist-info/METADATA,sha256=KuDpsWwhLZQ-048S8B7FchJkkjP1ATp3a2upRwVfxJM,40934
122
+ devrev_python_sdk-3.1.1.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
123
+ devrev_python_sdk-3.1.1.dist-info/entry_points.txt,sha256=XiV4J_yy0yzVZVxg7T66YERVIlqdPNp3O-NHTHkllqQ,63
124
+ devrev_python_sdk-3.1.1.dist-info/RECORD,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.29.0
2
+ Generator: hatchling 1.30.1
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,77 +0,0 @@
1
- """Survey response models for DevRev SDK.
2
-
3
- This module contains Pydantic models for the ``surveys.responses.list`` API.
4
- """
5
-
6
- from __future__ import annotations
7
-
8
- from datetime import datetime
9
- from enum import StrEnum
10
- from typing import Any
11
-
12
- from pydantic import ConfigDict, Field
13
-
14
- from devrev.models.base import DevRevBaseModel, DevRevResponseModel, PaginatedResponse
15
-
16
-
17
- class SurveyResponsesListMode(StrEnum):
18
- """Survey response cursor iteration mode."""
19
-
20
- AFTER = "after"
21
- BEFORE = "before"
22
-
23
-
24
- class SurveyResponse(DevRevResponseModel):
25
- """DevRev survey response model."""
26
-
27
- model_config = ConfigDict(extra="allow", populate_by_name=True, str_strip_whitespace=True)
28
-
29
- id: str = Field(..., description="Survey response ID")
30
- display_id: str | None = Field(default=None, description="Human-readable display ID")
31
- created_by: dict[str, Any] | None = Field(default=None, description="Creator user summary")
32
- created_date: datetime | None = Field(default=None, description="Creation timestamp")
33
- modified_by: dict[str, Any] | None = Field(default=None, description="Modifier user summary")
34
- modified_date: datetime | None = Field(default=None, description="Last modification timestamp")
35
- object_version: int | None = Field(default=None, description="Object version")
36
- dispatch_id: str | None = Field(default=None, description="Dispatched survey ID")
37
- dispatched_channels: list[dict[str, Any]] | None = Field(
38
- default=None,
39
- description="Channels on which the survey was dispatched",
40
- )
41
- object: str | None = Field(default=None, description="Object for which the survey was taken")
42
- recipient: dict[str, Any] | str | None = Field(default=None, description="Survey recipient")
43
- response: dict[str, Any] | str | int | float | bool | None = Field(
44
- default=None,
45
- description="Survey response payload",
46
- )
47
- stage: dict[str, Any] | int | str | None = Field(default=None, description="Survey stage")
48
- survey: dict[str, Any] | str | None = Field(default=None, description="Survey summary or ID")
49
-
50
-
51
- class SurveyResponsesListRequest(DevRevBaseModel):
52
- """Request to list survey responses."""
53
-
54
- created_by: list[str] | None = Field(default=None, description="Creator user filters")
55
- cursor: str | None = Field(default=None, description="Pagination cursor")
56
- dispatch_ids: list[str] | None = Field(default=None, description="Survey dispatch IDs")
57
- limit: int | None = Field(default=None, ge=1, le=100, description="Maximum results")
58
- mode: SurveyResponsesListMode | None = Field(default=None, description="Cursor iteration mode")
59
- object_id: str | None = Field(
60
- default=None,
61
- alias="object",
62
- description="Single object ID to filter responses by",
63
- )
64
- objects: list[str] | None = Field(default=None, description="Object IDs to filter responses by")
65
- recipient: list[str] | None = Field(default=None, description="Recipient user filters")
66
- sort_by: list[str] | None = Field(default=None, description="Sort order entries")
67
- stages: list[int] | None = Field(default=None, description="Survey response stage filters")
68
- surveys: list[str] | None = Field(default=None, description="Survey IDs to filter by")
69
-
70
-
71
- class SurveyResponsesListResponse(PaginatedResponse):
72
- """Response from listing survey responses."""
73
-
74
- survey_responses: list[SurveyResponse] = Field(
75
- default_factory=list,
76
- description="List of survey responses",
77
- )
@@ -1,122 +0,0 @@
1
- """Survey response service for DevRev SDK."""
2
-
3
- from __future__ import annotations
4
-
5
- from collections.abc import Sequence
6
-
7
- from devrev.models.survey_responses import (
8
- SurveyResponsesListMode,
9
- SurveyResponsesListRequest,
10
- SurveyResponsesListResponse,
11
- )
12
- from devrev.services.base import AsyncBaseService, BaseService
13
-
14
-
15
- def _merge_object_filters(object_id: str | None, objects: Sequence[str] | None) -> list[str] | None:
16
- """Merge singular and plural object filters without duplicates."""
17
- merged = list(objects or [])
18
- if object_id and object_id not in merged:
19
- merged.insert(0, object_id)
20
- return merged or None
21
-
22
-
23
- class SurveyResponsesService(BaseService):
24
- """Synchronous service for survey/CSAT responses."""
25
-
26
- def list(
27
- self,
28
- *,
29
- object_id: str | None = None,
30
- objects: Sequence[str] | None = None,
31
- created_by: Sequence[str] | None = None,
32
- cursor: str | None = None,
33
- dispatch_ids: Sequence[str] | None = None,
34
- limit: int | None = None,
35
- mode: SurveyResponsesListMode | None = None,
36
- recipient: Sequence[str] | None = None,
37
- sort_by: Sequence[str] | None = None,
38
- stages: Sequence[int] | None = None,
39
- surveys: Sequence[str] | None = None,
40
- ) -> SurveyResponsesListResponse:
41
- """List survey responses.
42
-
43
- Args:
44
- object_id: Convenience filter for a single ticket/work/object ID.
45
- objects: Object IDs to filter responses by.
46
- created_by: Creator user filters.
47
- cursor: Pagination cursor.
48
- dispatch_ids: Survey dispatch IDs.
49
- limit: Maximum number of responses to return.
50
- mode: Cursor iteration mode.
51
- recipient: Recipient user filters.
52
- sort_by: Sort order entries.
53
- stages: Survey response stage filters.
54
- surveys: Survey IDs to filter by.
55
-
56
- Returns:
57
- Paginated survey response list.
58
- """
59
- request = SurveyResponsesListRequest(
60
- created_by=list(created_by) if created_by else None,
61
- cursor=cursor,
62
- dispatch_ids=list(dispatch_ids) if dispatch_ids else None,
63
- limit=limit,
64
- mode=mode,
65
- objects=_merge_object_filters(object_id, objects),
66
- recipient=list(recipient) if recipient else None,
67
- sort_by=list(sort_by) if sort_by else None,
68
- stages=list(stages) if stages else None,
69
- surveys=list(surveys) if surveys else None,
70
- )
71
- return self._post("/surveys.responses.list", request, SurveyResponsesListResponse)
72
-
73
-
74
- class AsyncSurveyResponsesService(AsyncBaseService):
75
- """Asynchronous service for survey/CSAT responses."""
76
-
77
- async def list(
78
- self,
79
- *,
80
- object_id: str | None = None,
81
- objects: Sequence[str] | None = None,
82
- created_by: Sequence[str] | None = None,
83
- cursor: str | None = None,
84
- dispatch_ids: Sequence[str] | None = None,
85
- limit: int | None = None,
86
- mode: SurveyResponsesListMode | None = None,
87
- recipient: Sequence[str] | None = None,
88
- sort_by: Sequence[str] | None = None,
89
- stages: Sequence[int] | None = None,
90
- surveys: Sequence[str] | None = None,
91
- ) -> SurveyResponsesListResponse:
92
- """List survey responses.
93
-
94
- Args:
95
- object_id: Convenience filter for a single ticket/work/object ID.
96
- objects: Object IDs to filter responses by.
97
- created_by: Creator user filters.
98
- cursor: Pagination cursor.
99
- dispatch_ids: Survey dispatch IDs.
100
- limit: Maximum number of responses to return.
101
- mode: Cursor iteration mode.
102
- recipient: Recipient user filters.
103
- sort_by: Sort order entries.
104
- stages: Survey response stage filters.
105
- surveys: Survey IDs to filter by.
106
-
107
- Returns:
108
- Paginated survey response list.
109
- """
110
- request = SurveyResponsesListRequest(
111
- created_by=list(created_by) if created_by else None,
112
- cursor=cursor,
113
- dispatch_ids=list(dispatch_ids) if dispatch_ids else None,
114
- limit=limit,
115
- mode=mode,
116
- objects=_merge_object_filters(object_id, objects),
117
- recipient=list(recipient) if recipient else None,
118
- sort_by=list(sort_by) if sort_by else None,
119
- stages=list(stages) if stages else None,
120
- surveys=list(surveys) if surveys else None,
121
- )
122
- return await self._post("/surveys.responses.list", request, SurveyResponsesListResponse)