From 25345d0593667392d532843ff01d09a23a9d3a2d Mon Sep 17 00:00:00 2001 From: Bahattin Cinic Date: Thu, 21 May 2026 14:13:21 +0300 Subject: [PATCH] =?UTF-8?q?feat:=20rename=20webhook=5Ftriggers=20=E2=86=92?= =?UTF-8?q?=20agent=5Ftriggers,=20add=20AgentVFS,=20v0.4.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Trigger surface on the platform now spans generic webhook, Slack, Telegram, Microsoft Teams, WhatsApp Business, and cron schedules. The SDK follows suit: - WebhookTriggersResource → AgentTriggersResource (sync + async). client.webhook_triggers → client.agent_triggers. create() accepts source, source_config, and reply_config so callers can configure any of the six sources. - New AgentVFSResource (sync + async) exposing the per-agent Virtual Filesystem: list, read (with line_offset/line_limit), write (overwrite or append), stat, mkdir, move, copy, delete, grep, glob, usage. client.agent_vfs. - types.py: AgentTrigger / AgentTriggerCreateResponse pick up source, source_config, reply_config. New AgentVFSFile and AgentVFSGrepMatch types. - Routes updated to /api/v1/triggers (was /api/v1/webhook-triggers) and /api/v1/agents/:agentId/vfs/*. Minor version bump (0.3.0 → 0.4.0): renaming the resource class and client attribute is a breaking change for anyone calling client.webhook_triggers directly. README capability table updated to match. Co-Authored-By: Claude Opus 4.7 (1M context) --- README.md | 3 +- promptrails/__init__.py | 8 + promptrails/_version.py | 2 +- promptrails/async_client.py | 6 +- promptrails/client.py | 6 +- promptrails/resources/__init__.py | 9 +- promptrails/resources/agent_triggers.py | 101 +++++++++ promptrails/resources/agent_vfs.py | 244 ++++++++++++++++++++++ promptrails/resources/webhook_triggers.py | 81 ------- promptrails/types.py | 47 ++++- pyproject.toml | 2 +- uv.lock | 2 +- 12 files changed, 415 insertions(+), 96 deletions(-) create mode 100644 promptrails/resources/agent_triggers.py create mode 100644 promptrails/resources/agent_vfs.py delete mode 100644 promptrails/resources/webhook_triggers.py diff --git a/README.md b/README.md index 40c9464..e590906 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,8 @@ except NotFoundError as e: | `client.scores` | `list`, `get`, `create`, `update`, `delete`, `list_configs`, `get_config`, `create_config`, `update_config`, `delete_config`, `aggregates` | | `client.mcp_tools` | `list`, `get`, `create`, `update`, `delete` | | `client.approvals` | `list`, `get`, `decide` | -| `client.webhook_triggers` | `list`, `get`, `create`, `update`, `delete` | +| `client.agent_triggers` | `list`, `get`, `create` (with `source` + `source_config`), `update`, `delete` | +| `client.agent_vfs` | `list`, `read`, `write`, `stat`, `mkdir`, `move`, `copy`, `delete`, `grep`, `glob`, `usage` | | `client.a2a` | `get_agent_card`, `send_message`, `get_task`, `list_tasks`, `cancel_task` | | `client.media_models` | `list` | | `client.media` | `generate` | diff --git a/promptrails/__init__.py b/promptrails/__init__.py index 35db86b..bfe56a4 100644 --- a/promptrails/__init__.py +++ b/promptrails/__init__.py @@ -39,7 +39,11 @@ Agent, AgentExecution, AgentMemory, + AgentTrigger, + AgentTriggerCreateResponse, AgentVersion, + AgentVFSFile, + AgentVFSGrepMatch, ApprovalRequest, Asset, AssetSignedURL, @@ -79,6 +83,10 @@ "AgentConfig", "AgentExecution", "AgentMemory", + "AgentTrigger", + "AgentTriggerCreateResponse", + "AgentVFSFile", + "AgentVFSGrepMatch", "AgentVersion", "ApprovalRequest", "Asset", diff --git a/promptrails/_version.py b/promptrails/_version.py index 45ca4cf..bb9db69 100644 --- a/promptrails/_version.py +++ b/promptrails/_version.py @@ -1,3 +1,3 @@ """SDK version — kept in sync with pyproject.toml and git tags.""" -VERSION = "0.3.0" +VERSION = "0.4.0" diff --git a/promptrails/async_client.py b/promptrails/async_client.py index cc02ddd..b89fd26 100644 --- a/promptrails/async_client.py +++ b/promptrails/async_client.py @@ -5,6 +5,8 @@ from .resources import ( AsyncA2AResource, AsyncAgentsResource, + AsyncAgentTriggersResource, + AsyncAgentVFSResource, AsyncApprovalsResource, AsyncAssetsResource, AsyncChatResource, @@ -25,7 +27,6 @@ AsyncSessionsResource, AsyncTemplatesResource, AsyncTracesResource, - AsyncWebhookTriggersResource, ) @@ -67,7 +68,8 @@ def __init__( self.dashboard = AsyncDashboardResource(self._http) self.sessions = AsyncSessionsResource(self._http) self.a2a = AsyncA2AResource(self._http) - self.webhook_triggers = AsyncWebhookTriggersResource(self._http) + self.agent_triggers = AsyncAgentTriggersResource(self._http) + self.agent_vfs = AsyncAgentVFSResource(self._http) self.media_models = AsyncMediaModelsResource(self._http) self.media = AsyncMediaResource(self._http) self.assets = AsyncAssetsResource(self._http) diff --git a/promptrails/client.py b/promptrails/client.py index 32592f9..ef99665 100644 --- a/promptrails/client.py +++ b/promptrails/client.py @@ -5,6 +5,8 @@ from .resources import ( A2AResource, AgentsResource, + AgentTriggersResource, + AgentVFSResource, ApprovalsResource, AssetsResource, ChatResource, @@ -25,7 +27,6 @@ SessionsResource, TemplatesResource, TracesResource, - WebhookTriggersResource, ) @@ -67,7 +68,8 @@ def __init__( self.dashboard = DashboardResource(self._http) self.sessions = SessionsResource(self._http) self.a2a = A2AResource(self._http) - self.webhook_triggers = WebhookTriggersResource(self._http) + self.agent_triggers = AgentTriggersResource(self._http) + self.agent_vfs = AgentVFSResource(self._http) self.media_models = MediaModelsResource(self._http) self.media = MediaResource(self._http) self.assets = AssetsResource(self._http) diff --git a/promptrails/resources/__init__.py b/promptrails/resources/__init__.py index cd66fe7..02fdf79 100644 --- a/promptrails/resources/__init__.py +++ b/promptrails/resources/__init__.py @@ -1,4 +1,6 @@ from .a2a import A2AResource, AsyncA2AResource +from .agent_triggers import AgentTriggersResource, AsyncAgentTriggersResource +from .agent_vfs import AgentVFSResource, AsyncAgentVFSResource from .agents import AgentsResource, AsyncAgentsResource from .approvals import ApprovalsResource, AsyncApprovalsResource from .assets import AssetsResource, AsyncAssetsResource @@ -20,14 +22,17 @@ from .sessions import AsyncSessionsResource, SessionsResource from .templates import AsyncTemplatesResource, TemplatesResource from .traces import AsyncTracesResource, TracesResource -from .webhook_triggers import AsyncWebhookTriggersResource, WebhookTriggersResource __all__ = [ "A2AResource", + "AgentTriggersResource", + "AgentVFSResource", "AgentsResource", "ApprovalsResource", "AssetsResource", "AsyncA2AResource", + "AsyncAgentTriggersResource", + "AsyncAgentVFSResource", "AsyncAgentsResource", "AsyncApprovalsResource", "AsyncAssetsResource", @@ -49,7 +54,6 @@ "AsyncSessionsResource", "AsyncTemplatesResource", "AsyncTracesResource", - "AsyncWebhookTriggersResource", "ChatResource", "CostsResource", "CredentialsResource", @@ -68,5 +72,4 @@ "SessionsResource", "TemplatesResource", "TracesResource", - "WebhookTriggersResource", ] diff --git a/promptrails/resources/agent_triggers.py b/promptrails/resources/agent_triggers.py new file mode 100644 index 0000000..69222fb --- /dev/null +++ b/promptrails/resources/agent_triggers.py @@ -0,0 +1,101 @@ +from __future__ import annotations + +from typing import Any, Dict, Optional + +from ..pagination import PaginatedResponse +from ..types import AgentTrigger, AgentTriggerCreateResponse +from .base import AsyncBaseResource, BaseResource + + +class AgentTriggersResource(BaseResource): + """Manage agent triggers: generic webhook, Slack, Telegram, Teams, WhatsApp, schedule.""" + + def list( + self, *, agent_id: Optional[str] = None, page: int = 1, limit: int = 20 + ) -> PaginatedResponse[AgentTrigger]: + params: Dict[str, Any] = {"page": page, "limit": limit} + if agent_id: + params["agent_id"] = agent_id + body = self._http.get("/api/v1/triggers", params=params) + return PaginatedResponse.from_response(body, AgentTrigger.from_dict) + + def get(self, trigger_id: str) -> AgentTrigger: + body = self._http.get(f"/api/v1/triggers/{trigger_id}") + return AgentTrigger.from_dict(self._unwrap(body)) + + def create( + self, + *, + name: str, + agent_id: str, + source: str = "generic", + source_config: Optional[Dict[str, Any]] = None, + reply_config: Optional[Dict[str, Any]] = None, + generate_secret: bool = False, + ) -> AgentTriggerCreateResponse: + payload: Dict[str, Any] = { + "name": name, + "agent_id": agent_id, + "source": source, + "generate_secret": generate_secret, + } + if source_config is not None: + payload["source_config"] = source_config + if reply_config is not None: + payload["reply_config"] = reply_config + body = self._http.post("/api/v1/triggers", json=payload) + return AgentTriggerCreateResponse.from_dict(self._unwrap(body)) + + def update(self, trigger_id: str, **kwargs: Any) -> AgentTrigger: + body = self._http.patch(f"/api/v1/triggers/{trigger_id}", json=kwargs) + return AgentTrigger.from_dict(self._unwrap(body)) + + def delete(self, trigger_id: str) -> None: + self._http.delete(f"/api/v1/triggers/{trigger_id}") + + +class AsyncAgentTriggersResource(AsyncBaseResource): + """Async variant of AgentTriggersResource.""" + + async def list( + self, *, agent_id: Optional[str] = None, page: int = 1, limit: int = 20 + ) -> PaginatedResponse[AgentTrigger]: + params: Dict[str, Any] = {"page": page, "limit": limit} + if agent_id: + params["agent_id"] = agent_id + body = await self._http.get("/api/v1/triggers", params=params) + return PaginatedResponse.from_response(body, AgentTrigger.from_dict) + + async def get(self, trigger_id: str) -> AgentTrigger: + body = await self._http.get(f"/api/v1/triggers/{trigger_id}") + return AgentTrigger.from_dict(self._unwrap(body)) + + async def create( + self, + *, + name: str, + agent_id: str, + source: str = "generic", + source_config: Optional[Dict[str, Any]] = None, + reply_config: Optional[Dict[str, Any]] = None, + generate_secret: bool = False, + ) -> AgentTriggerCreateResponse: + payload: Dict[str, Any] = { + "name": name, + "agent_id": agent_id, + "source": source, + "generate_secret": generate_secret, + } + if source_config is not None: + payload["source_config"] = source_config + if reply_config is not None: + payload["reply_config"] = reply_config + body = await self._http.post("/api/v1/triggers", json=payload) + return AgentTriggerCreateResponse.from_dict(self._unwrap(body)) + + async def update(self, trigger_id: str, **kwargs: Any) -> AgentTrigger: + body = await self._http.patch(f"/api/v1/triggers/{trigger_id}", json=kwargs) + return AgentTrigger.from_dict(self._unwrap(body)) + + async def delete(self, trigger_id: str) -> None: + await self._http.delete(f"/api/v1/triggers/{trigger_id}") diff --git a/promptrails/resources/agent_vfs.py b/promptrails/resources/agent_vfs.py new file mode 100644 index 0000000..e5ed3eb --- /dev/null +++ b/promptrails/resources/agent_vfs.py @@ -0,0 +1,244 @@ +from __future__ import annotations + +from typing import Any, Dict, List, Optional + +from ..types import AgentVFSFile, AgentVFSGrepMatch +from .base import AsyncBaseResource, BaseResource + + +def _build_list_params( + path: Optional[str], recursive: Optional[bool], offset: Optional[int], limit: Optional[int] +) -> Dict[str, Any]: + params: Dict[str, Any] = {} + if path is not None: + params["path"] = path + if recursive: + params["recursive"] = "true" + if offset is not None: + params["offset"] = offset + if limit is not None: + params["limit"] = limit + return params + + +class AgentVFSResource(BaseResource): + """Per-agent Virtual Filesystem: list, read, write, mkdir, move, copy, delete, grep, glob. + + Files persist across executions and double as long-term memory for the agent. + """ + + def list( + self, + agent_id: str, + *, + path: str = "/", + recursive: bool = False, + offset: Optional[int] = None, + limit: Optional[int] = None, + ) -> List[AgentVFSFile]: + params = _build_list_params(path, recursive, offset, limit) + body = self._http.get(f"/api/v1/agents/{agent_id}/vfs", params=params) + items = self._unwrap(body).get("items", []) or [] + return [AgentVFSFile.from_dict(item) for item in items] + + def read( + self, + agent_id: str, + path: str, + *, + line_offset: Optional[int] = None, + line_limit: Optional[int] = None, + ) -> Dict[str, Any]: + params: Dict[str, Any] = {"path": path} + if line_offset is not None: + params["line_offset"] = line_offset + if line_limit is not None: + params["line_limit"] = line_limit + body = self._http.get(f"/api/v1/agents/{agent_id}/vfs/file", params=params) + return self._unwrap(body) + + def write( + self, + agent_id: str, + path: str, + content: str, + *, + mode: str = "overwrite", + mime_type: Optional[str] = None, + ) -> AgentVFSFile: + payload: Dict[str, Any] = {"path": path, "content": content, "mode": mode} + if mime_type: + payload["mime_type"] = mime_type + body = self._http.put(f"/api/v1/agents/{agent_id}/vfs/file", json=payload) + return AgentVFSFile.from_dict(self._unwrap(body)) + + def stat(self, agent_id: str, path: str) -> AgentVFSFile: + body = self._http.get(f"/api/v1/agents/{agent_id}/vfs/stat", params={"path": path}) + return AgentVFSFile.from_dict(self._unwrap(body)) + + def mkdir(self, agent_id: str, path: str) -> AgentVFSFile: + body = self._http.post(f"/api/v1/agents/{agent_id}/vfs/mkdir", json={"path": path}) + return AgentVFSFile.from_dict(self._unwrap(body)) + + def move(self, agent_id: str, src: str, dst: str) -> None: + self._http.post(f"/api/v1/agents/{agent_id}/vfs/move", json={"from": src, "to": dst}) + + def copy(self, agent_id: str, src: str, dst: str) -> None: + self._http.post(f"/api/v1/agents/{agent_id}/vfs/copy", json={"from": src, "to": dst}) + + def delete(self, agent_id: str, path: str, *, recursive: bool = False) -> int: + params: Dict[str, Any] = {"path": path} + if recursive: + params["recursive"] = "true" + body = self._http.delete(f"/api/v1/agents/{agent_id}/vfs", params=params) + if body is None: + return 0 + return int(self._unwrap(body).get("deleted", 0)) + + def grep( + self, + agent_id: str, + query: str, + *, + path: Optional[str] = None, + limit: Optional[int] = None, + ) -> List[AgentVFSGrepMatch]: + params: Dict[str, Any] = {"q": query} + if path: + params["path"] = path + if limit is not None: + params["limit"] = limit + body = self._http.get(f"/api/v1/agents/{agent_id}/vfs/grep", params=params) + matches = self._unwrap(body).get("matches", []) or [] + return [AgentVFSGrepMatch.from_dict(m) for m in matches] + + def glob( + self, + agent_id: str, + pattern: str, + *, + path: Optional[str] = None, + limit: Optional[int] = None, + ) -> List[AgentVFSFile]: + params: Dict[str, Any] = {"pattern": pattern} + if path: + params["path"] = path + if limit is not None: + params["limit"] = limit + body = self._http.get(f"/api/v1/agents/{agent_id}/vfs/glob", params=params) + items = self._unwrap(body).get("items", []) or [] + return [AgentVFSFile.from_dict(item) for item in items] + + def usage(self, agent_id: str) -> int: + body = self._http.get(f"/api/v1/agents/{agent_id}/vfs/usage") + return int(self._unwrap(body).get("bytes_used", 0)) + + +class AsyncAgentVFSResource(AsyncBaseResource): + """Async variant of AgentVFSResource.""" + + async def list( + self, + agent_id: str, + *, + path: str = "/", + recursive: bool = False, + offset: Optional[int] = None, + limit: Optional[int] = None, + ) -> List[AgentVFSFile]: + params = _build_list_params(path, recursive, offset, limit) + body = await self._http.get(f"/api/v1/agents/{agent_id}/vfs", params=params) + items = self._unwrap(body).get("items", []) or [] + return [AgentVFSFile.from_dict(item) for item in items] + + async def read( + self, + agent_id: str, + path: str, + *, + line_offset: Optional[int] = None, + line_limit: Optional[int] = None, + ) -> Dict[str, Any]: + params: Dict[str, Any] = {"path": path} + if line_offset is not None: + params["line_offset"] = line_offset + if line_limit is not None: + params["line_limit"] = line_limit + body = await self._http.get(f"/api/v1/agents/{agent_id}/vfs/file", params=params) + return self._unwrap(body) + + async def write( + self, + agent_id: str, + path: str, + content: str, + *, + mode: str = "overwrite", + mime_type: Optional[str] = None, + ) -> AgentVFSFile: + payload: Dict[str, Any] = {"path": path, "content": content, "mode": mode} + if mime_type: + payload["mime_type"] = mime_type + body = await self._http.put(f"/api/v1/agents/{agent_id}/vfs/file", json=payload) + return AgentVFSFile.from_dict(self._unwrap(body)) + + async def stat(self, agent_id: str, path: str) -> AgentVFSFile: + body = await self._http.get(f"/api/v1/agents/{agent_id}/vfs/stat", params={"path": path}) + return AgentVFSFile.from_dict(self._unwrap(body)) + + async def mkdir(self, agent_id: str, path: str) -> AgentVFSFile: + body = await self._http.post(f"/api/v1/agents/{agent_id}/vfs/mkdir", json={"path": path}) + return AgentVFSFile.from_dict(self._unwrap(body)) + + async def move(self, agent_id: str, src: str, dst: str) -> None: + await self._http.post(f"/api/v1/agents/{agent_id}/vfs/move", json={"from": src, "to": dst}) + + async def copy(self, agent_id: str, src: str, dst: str) -> None: + await self._http.post(f"/api/v1/agents/{agent_id}/vfs/copy", json={"from": src, "to": dst}) + + async def delete(self, agent_id: str, path: str, *, recursive: bool = False) -> int: + params: Dict[str, Any] = {"path": path} + if recursive: + params["recursive"] = "true" + body = await self._http.delete(f"/api/v1/agents/{agent_id}/vfs", params=params) + if body is None: + return 0 + return int(self._unwrap(body).get("deleted", 0)) + + async def grep( + self, + agent_id: str, + query: str, + *, + path: Optional[str] = None, + limit: Optional[int] = None, + ) -> List[AgentVFSGrepMatch]: + params: Dict[str, Any] = {"q": query} + if path: + params["path"] = path + if limit is not None: + params["limit"] = limit + body = await self._http.get(f"/api/v1/agents/{agent_id}/vfs/grep", params=params) + matches = self._unwrap(body).get("matches", []) or [] + return [AgentVFSGrepMatch.from_dict(m) for m in matches] + + async def glob( + self, + agent_id: str, + pattern: str, + *, + path: Optional[str] = None, + limit: Optional[int] = None, + ) -> List[AgentVFSFile]: + params: Dict[str, Any] = {"pattern": pattern} + if path: + params["path"] = path + if limit is not None: + params["limit"] = limit + body = await self._http.get(f"/api/v1/agents/{agent_id}/vfs/glob", params=params) + items = self._unwrap(body).get("items", []) or [] + return [AgentVFSFile.from_dict(item) for item in items] + + async def usage(self, agent_id: str) -> int: + body = await self._http.get(f"/api/v1/agents/{agent_id}/vfs/usage") + return int(self._unwrap(body).get("bytes_used", 0)) diff --git a/promptrails/resources/webhook_triggers.py b/promptrails/resources/webhook_triggers.py deleted file mode 100644 index 774f413..0000000 --- a/promptrails/resources/webhook_triggers.py +++ /dev/null @@ -1,81 +0,0 @@ -from __future__ import annotations - -from typing import Any, Dict, Optional - -from ..pagination import PaginatedResponse -from ..types import WebhookTrigger, WebhookTriggerCreateResponse -from .base import AsyncBaseResource, BaseResource - - -class WebhookTriggersResource(BaseResource): - def list( - self, *, agent_id: Optional[str] = None, page: int = 1, limit: int = 20 - ) -> PaginatedResponse[WebhookTrigger]: - params: Dict[str, Any] = {"page": page, "limit": limit} - if agent_id: - params["agent_id"] = agent_id - body = self._http.get("/api/v1/webhook-triggers", params=params) - return PaginatedResponse.from_response(body, WebhookTrigger.from_dict) - - def get(self, trigger_id: str) -> WebhookTrigger: - body = self._http.get(f"/api/v1/webhook-triggers/{trigger_id}") - return WebhookTrigger.from_dict(self._unwrap(body)) - - def create( - self, - *, - name: str, - agent_id: str, - generate_secret: bool = False, - ) -> WebhookTriggerCreateResponse: - payload: Dict[str, Any] = { - "name": name, - "agent_id": agent_id, - "generate_secret": generate_secret, - } - body = self._http.post("/api/v1/webhook-triggers", json=payload) - return WebhookTriggerCreateResponse.from_dict(self._unwrap(body)) - - def update(self, trigger_id: str, **kwargs: Any) -> WebhookTrigger: - body = self._http.patch(f"/api/v1/webhook-triggers/{trigger_id}", json=kwargs) - return WebhookTrigger.from_dict(self._unwrap(body)) - - def delete(self, trigger_id: str) -> None: - self._http.delete(f"/api/v1/webhook-triggers/{trigger_id}") - - -class AsyncWebhookTriggersResource(AsyncBaseResource): - async def list( - self, *, agent_id: Optional[str] = None, page: int = 1, limit: int = 20 - ) -> PaginatedResponse[WebhookTrigger]: - params: Dict[str, Any] = {"page": page, "limit": limit} - if agent_id: - params["agent_id"] = agent_id - body = await self._http.get("/api/v1/webhook-triggers", params=params) - return PaginatedResponse.from_response(body, WebhookTrigger.from_dict) - - async def get(self, trigger_id: str) -> WebhookTrigger: - body = await self._http.get(f"/api/v1/webhook-triggers/{trigger_id}") - return WebhookTrigger.from_dict(self._unwrap(body)) - - async def create( - self, - *, - name: str, - agent_id: str, - generate_secret: bool = False, - ) -> WebhookTriggerCreateResponse: - payload: Dict[str, Any] = { - "name": name, - "agent_id": agent_id, - "generate_secret": generate_secret, - } - body = await self._http.post("/api/v1/webhook-triggers", json=payload) - return WebhookTriggerCreateResponse.from_dict(self._unwrap(body)) - - async def update(self, trigger_id: str, **kwargs: Any) -> WebhookTrigger: - body = await self._http.patch(f"/api/v1/webhook-triggers/{trigger_id}", json=kwargs) - return WebhookTrigger.from_dict(self._unwrap(body)) - - async def delete(self, trigger_id: str) -> None: - await self._http.delete(f"/api/v1/webhook-triggers/{trigger_id}") diff --git a/promptrails/types.py b/promptrails/types.py index 969d026..69e6bc5 100644 --- a/promptrails/types.py +++ b/promptrails/types.py @@ -776,13 +776,16 @@ def from_dict(cls, data: Dict[str, Any]) -> "A2AAgentSkill": @dataclass -class WebhookTrigger: +class AgentTrigger: id: str = "" workspace_id: str = "" agent_id: str = "" name: str = "" token: str = "" token_prefix: str = "" + source: str = "generic" + source_config: Dict[str, Any] = field(default_factory=dict) + reply_config: Dict[str, Any] = field(default_factory=dict) is_active: bool = True has_secret: bool = False last_used_at: Optional[str] = None @@ -791,18 +794,21 @@ class WebhookTrigger: updated_at: str = "" @classmethod - def from_dict(cls, data: Dict[str, Any]) -> "WebhookTrigger": + def from_dict(cls, data: Dict[str, Any]) -> "AgentTrigger": return _from_dict(cls, data) @dataclass -class WebhookTriggerCreateResponse: +class AgentTriggerCreateResponse: id: str = "" workspace_id: str = "" agent_id: str = "" name: str = "" token: str = "" token_prefix: str = "" + source: str = "generic" + source_config: Dict[str, Any] = field(default_factory=dict) + reply_config: Dict[str, Any] = field(default_factory=dict) is_active: bool = True has_secret: bool = False last_used_at: Optional[str] = None @@ -812,7 +818,40 @@ class WebhookTriggerCreateResponse: secret: Optional[str] = None @classmethod - def from_dict(cls, data: Dict[str, Any]) -> "WebhookTriggerCreateResponse": + def from_dict(cls, data: Dict[str, Any]) -> "AgentTriggerCreateResponse": + return _from_dict(cls, data) + + +@dataclass +class AgentVFSFile: + id: str = "" + workspace_id: str = "" + agent_id: str = "" + path: str = "" + parent_path: str = "" + name: str = "" + is_dir: bool = False + content: str = "" + size_bytes: int = 0 + mime_type: str = "" + metadata: Dict[str, Any] = field(default_factory=dict) + last_writer_kind: str = "user" + created_at: str = "" + updated_at: str = "" + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "AgentVFSFile": + return _from_dict(cls, data) + + +@dataclass +class AgentVFSGrepMatch: + path: str = "" + line_number: int = 0 + line: str = "" + + @classmethod + def from_dict(cls, data: Dict[str, Any]) -> "AgentVFSGrepMatch": return _from_dict(cls, data) diff --git a/pyproject.toml b/pyproject.toml index e62adc2..639fbc3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "promptrails" -version = "0.3.0" +version = "0.4.0" description = "Official Python SDK for the PromptRails API" readme = "README.md" license = {text = "MIT"} diff --git a/uv.lock b/uv.lock index de990d7..ed30c1a 100644 --- a/uv.lock +++ b/uv.lock @@ -191,7 +191,7 @@ wheels = [ [[package]] name = "promptrails" -version = "0.3.0" +version = "0.4.0" source = { editable = "." } dependencies = [ { name = "httpx" },