persona-sdk-python 0.2.18__tar.gz → 0.2.20__tar.gz

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.
Files changed (35) hide show
  1. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/PKG-INFO +1 -1
  2. persona_sdk_python-0.2.20/bitbucket-pipelines.yml +18 -0
  3. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/__init__.py +14 -5
  4. persona_sdk_python-0.2.20/persona_sdk/api/human_tasks.py +55 -0
  5. persona_sdk_python-0.2.20/persona_sdk/api/markup_rules.py +44 -0
  6. persona_sdk_python-0.2.20/persona_sdk/api/providers.py +65 -0
  7. persona_sdk_python-0.2.20/persona_sdk/api/workflows.py +234 -0
  8. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/pyproject.toml +1 -1
  9. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/uv.lock +1 -9
  10. persona_sdk_python-0.2.18/bitbucket-pipelines.yml +0 -17
  11. persona_sdk_python-0.2.18/persona_sdk/api/known_models.py +0 -49
  12. persona_sdk_python-0.2.18/persona_sdk/api/workflows.py +0 -72
  13. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/.gitignore +0 -0
  14. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/DEPLOY.md +0 -0
  15. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/README.md +0 -0
  16. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/_serde.py +0 -0
  17. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/__init__.py +0 -0
  18. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/agents.py +0 -0
  19. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/credentials.py +0 -0
  20. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/features.py +0 -0
  21. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/knowledge_bases.py +0 -0
  22. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/missions.py +0 -0
  23. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/projects.py +0 -0
  24. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/service_prices.py +0 -0
  25. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/sessions.py +0 -0
  26. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/api/triggers.py +0 -0
  27. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/auth/__init__.py +0 -0
  28. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/auth/api_key_auth.py +0 -0
  29. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/auth/base.py +0 -0
  30. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/auth/bearer_token_auth.py +0 -0
  31. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/client.py +0 -0
  32. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/runners/__init__.py +0 -0
  33. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/runners/agent_runner.py +0 -0
  34. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/runners/resource_retriever.py +0 -0
  35. {persona_sdk_python-0.2.18 → persona_sdk_python-0.2.20}/persona_sdk/runners/tool_invoker.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: persona-sdk-python
3
- Version: 0.2.18
3
+ Version: 0.2.20
4
4
  Summary: Async Python SDK for the Persona AI platform
5
5
  Project-URL: Homepage, https://persona.applica.guru
6
6
  Project-URL: Repository, https://bitbucket.org/applicaguru/persona-sdk-python
@@ -0,0 +1,18 @@
1
+ image: python:3.12
2
+
3
+ pipelines:
4
+ branches:
5
+ main:
6
+ - step:
7
+ name: Publish to PyPI
8
+ caches:
9
+ - pip
10
+ script:
11
+ - apt-get update && apt-get install -y git
12
+ - pip install build twine
13
+ - export VERSION=0.2.$BITBUCKET_BUILD_NUMBER
14
+ - sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
15
+ - python -m build
16
+ - twine upload dist/* -u __token__ -p $PYPI_TOKEN
17
+ - git tag -a $VERSION -m "$VERSION"
18
+ - git push origin $VERSION
@@ -3,14 +3,16 @@ from typing import Union
3
3
  from persona_sdk.api.agents import AgentsApi
4
4
  from persona_sdk.api.credentials import CredentialsApi
5
5
  from persona_sdk.api.features import FeaturesApi
6
- from persona_sdk.api.known_models import KnownModelsApi
7
6
  from persona_sdk.api.knowledge_bases import KnowledgeBasesApi
7
+ from persona_sdk.api.markup_rules import MarkupRulesApi
8
8
  from persona_sdk.api.missions import MissionsApi
9
9
  from persona_sdk.api.projects import ProjectsApi
10
+ from persona_sdk.api.providers import ProvidersApi
10
11
  from persona_sdk.api.service_prices import ServicePricesApi
11
12
  from persona_sdk.api.sessions import SessionsApi
12
13
  from persona_sdk.api.triggers import TriggersApi
13
14
  from persona_sdk.api.workflows import WorkflowsApi
15
+ from persona_sdk.api.human_tasks import HumanTasksApi
14
16
  from persona_sdk.auth import (
15
17
  ApiKeyAuthenticationProvider,
16
18
  AuthenticationProvider,
@@ -30,10 +32,11 @@ from persona_models.knowledge_bases import (
30
32
  KnowledgeBaseDocument,
31
33
  SearchChunksRequest,
32
34
  )
33
- from persona_models.known_models import KnownModel
35
+ from persona_models.markup import MarkupRule
34
36
  from persona_models.mcp import GenerationRequest
35
37
  from persona_models.missions import CreateMissionRequest, Mission
36
38
  from persona_models.projects import Project
39
+ from persona_models.providers import Provider, ProviderModel
37
40
  from persona_models.service_prices import ServicePrice, UsageCost
38
41
  from persona_models.sessions import GenerationResponse, Message, Session
39
42
  from persona_models.triggers import Trigger, TriggerExecutionResult
@@ -48,14 +51,16 @@ __all__ = [
48
51
  "AgentsApi",
49
52
  "CredentialsApi",
50
53
  "FeaturesApi",
51
- "KnownModelsApi",
52
54
  "KnowledgeBasesApi",
55
+ "MarkupRulesApi",
53
56
  "MissionsApi",
54
57
  "ProjectsApi",
58
+ "ProvidersApi",
55
59
  "ServicePricesApi",
56
60
  "SessionsApi",
57
61
  "TriggersApi",
58
62
  "WorkflowsApi",
63
+ "HumanTasksApi",
59
64
  # Domain models (re-exported from persona-models)
60
65
  "Paginated",
61
66
  "AgentConfiguration",
@@ -66,12 +71,14 @@ __all__ = [
66
71
  "KnowledgeBase",
67
72
  "KnowledgeBaseDocument",
68
73
  "SearchChunksRequest",
69
- "KnownModel",
70
74
  "GenerationRequest",
71
75
  "GenerationResponse",
72
76
  "CreateMissionRequest",
73
77
  "Mission",
74
78
  "Project",
79
+ "Provider",
80
+ "ProviderModel",
81
+ "MarkupRule",
75
82
  "ServicePrice",
76
83
  "UsageCost",
77
84
  "Message",
@@ -131,6 +138,7 @@ class PersonaSdk:
131
138
  )
132
139
  self.agents = AgentsApi(self.client)
133
140
  self.workflows = WorkflowsApi(self.workflows_client)
141
+ self.human_tasks = HumanTasksApi(self.workflows_client)
134
142
  self.triggers = TriggersApi(self.client)
135
143
  self.sessions = SessionsApi(self.client)
136
144
  self.credentials = CredentialsApi(self.client)
@@ -139,7 +147,8 @@ class PersonaSdk:
139
147
  self.features = FeaturesApi(self.client)
140
148
  self.missions = MissionsApi(self.client)
141
149
  self.service_prices = ServicePricesApi(self.client)
142
- self.known_models = KnownModelsApi(self.client)
150
+ self.providers = ProvidersApi(self.client)
151
+ self.markup_rules = MarkupRulesApi(self.client)
143
152
 
144
153
  async def close(self):
145
154
  await self.client.close()
@@ -0,0 +1,55 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from persona_sdk.client import PersonaClient
6
+
7
+
8
+ class HumanTasksApi:
9
+ """
10
+ Human-in-the-loop tasks. A task is created when a workflow step
11
+ suspends waiting for a human (a declared ``human`` node or an agent
12
+ escalation); responding to it resumes the run.
13
+
14
+ Lives on the workflows service (same client as ``WorkflowsApi``).
15
+ Tasks are returned as plain dicts — the contract is owned by the
16
+ workflows service and intentionally not constrained here.
17
+ """
18
+
19
+ def __init__(self, client: PersonaClient):
20
+ self._client = client
21
+
22
+ async def list(
23
+ self,
24
+ status: str | None = "pending",
25
+ assignee: str | None = None,
26
+ workflow_id: str | None = None,
27
+ execution_id: str | None = None,
28
+ page: int = 1,
29
+ size: int = 50,
30
+ ) -> dict[str, Any]:
31
+ """The project's human-task inbox (``Paginated[HumanTask]`` shape)."""
32
+ params: dict[str, Any] = {"page": page, "size": size}
33
+ if status:
34
+ params["status"] = status
35
+ if assignee:
36
+ params["assignee"] = assignee
37
+ if workflow_id:
38
+ params["workflowId"] = workflow_id
39
+ if execution_id:
40
+ params["executionId"] = execution_id
41
+ return await self._client.get("/human-tasks", params=params)
42
+
43
+ async def respond(
44
+ self,
45
+ human_task_id: str,
46
+ response: Any,
47
+ responded_by: str | None = None,
48
+ ) -> dict[str, Any]:
49
+ """Answer a pending human task and resume the suspended execution."""
50
+ body: dict[str, Any] = {"response": response}
51
+ if responded_by:
52
+ body["respondedBy"] = responded_by
53
+ return await self._client.post(
54
+ f"/human-tasks/{human_task_id}/respond", json=body
55
+ )
@@ -0,0 +1,44 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from persona_models.common import Paginated
6
+ from persona_models.markup import MarkupRule
7
+
8
+ from persona_sdk._serde import dump_payload
9
+ from persona_sdk.client import PersonaClient
10
+
11
+
12
+ class MarkupRulesApi:
13
+ """Global markup rules (super admin)."""
14
+
15
+ def __init__(self, client: PersonaClient):
16
+ self._client = client
17
+
18
+ async def list(
19
+ self, keyword: str | None = None, page: int = 1, size: int = 50
20
+ ) -> Paginated[MarkupRule]:
21
+ params: dict[str, Any] = {"page": page, "size": size}
22
+ if keyword:
23
+ params["keyword"] = keyword
24
+ data = await self._client.get("/markup-rules", params=params)
25
+ return Paginated[MarkupRule].model_validate(data)
26
+
27
+ async def get(self, markup_rule_id: str) -> MarkupRule:
28
+ data = await self._client.get(f"/markup-rules/{markup_rule_id}")
29
+ return MarkupRule.model_validate(data)
30
+
31
+ async def create(self, markup_rule: MarkupRule | dict[str, Any]) -> MarkupRule:
32
+ data = await self._client.post("/markup-rules", json=dump_payload(markup_rule))
33
+ return MarkupRule.model_validate(data)
34
+
35
+ async def update(
36
+ self, markup_rule_id: str, markup_rule: MarkupRule | dict[str, Any]
37
+ ) -> MarkupRule:
38
+ data = await self._client.put(
39
+ f"/markup-rules/{markup_rule_id}", json=dump_payload(markup_rule)
40
+ )
41
+ return MarkupRule.model_validate(data)
42
+
43
+ async def delete(self, markup_rule_id: str) -> None:
44
+ await self._client.delete(f"/markup-rules/{markup_rule_id}")
@@ -0,0 +1,65 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from persona_models.common import Paginated
6
+ from persona_models.providers import Provider, ProviderModel
7
+
8
+ from persona_sdk._serde import dump_payload
9
+ from persona_sdk.client import PersonaClient
10
+
11
+
12
+ class ProvidersApi:
13
+ """Managed LLM providers (super admin). Global or per-project; api keys are
14
+ stored encrypted and returned masked."""
15
+
16
+ def __init__(self, client: PersonaClient):
17
+ self._client = client
18
+
19
+ async def list(
20
+ self,
21
+ project_id: str | None = None,
22
+ keyword: str | None = None,
23
+ page: int = 1,
24
+ size: int = 100,
25
+ ) -> Paginated[Provider]:
26
+ params: dict[str, Any] = {"page": page, "size": size}
27
+ if project_id:
28
+ params["projectId"] = project_id
29
+ if keyword:
30
+ params["keyword"] = keyword
31
+ data = await self._client.get("/providers", params=params)
32
+ return Paginated[Provider].model_validate(data)
33
+
34
+ async def get(self, provider_id: str) -> Provider:
35
+ data = await self._client.get(f"/providers/{provider_id}")
36
+ return Provider.model_validate(data)
37
+
38
+ async def create(self, provider: Provider | dict[str, Any]) -> Provider:
39
+ data = await self._client.post("/providers", json=dump_payload(provider))
40
+ return Provider.model_validate(data)
41
+
42
+ async def update(
43
+ self, provider_id: str, provider: Provider | dict[str, Any]
44
+ ) -> Provider:
45
+ data = await self._client.put(
46
+ f"/providers/{provider_id}", json=dump_payload(provider)
47
+ )
48
+ return Provider.model_validate(data)
49
+
50
+ async def delete(self, provider_id: str) -> None:
51
+ await self._client.delete(f"/providers/{provider_id}")
52
+
53
+ async def available(self) -> list[str]:
54
+ """Provider names litellm supports (for the 'add provider' picker). Admin."""
55
+ return await self._client.get("/providers/available")
56
+
57
+ async def names(self) -> list[str]:
58
+ """Names of providers configured for the caller (global + their project),
59
+ no credentials. Authenticated (not admin) — for the model selector."""
60
+ return await self._client.get("/provider-names")
61
+
62
+ async def models(self, provider: str) -> list[ProviderModel]:
63
+ """Model suggestions (chat, with capabilities) for a provider, from litellm."""
64
+ data = await self._client.get("/provider-models", params={"provider": provider})
65
+ return [ProviderModel.model_validate(m) for m in data]
@@ -0,0 +1,234 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+ from persona_models.common import Paginated
6
+ from persona_models.workflows import Workflow
7
+
8
+ from persona_sdk._serde import dump_payload
9
+ from persona_sdk.client import PersonaClient
10
+
11
+
12
+ class WorkflowsApi:
13
+ def __init__(self, client: PersonaClient):
14
+ self._client = client
15
+
16
+ async def list(
17
+ self, keyword: str | None = None, page: int = 1, size: int = 20
18
+ ) -> Paginated[Workflow]:
19
+ params: dict[str, Any] = {"page": page, "size": size}
20
+ if keyword:
21
+ params["keyword"] = keyword
22
+ data = await self._client.get("/workflows", params=params)
23
+ return Paginated[Workflow].model_validate(data)
24
+
25
+ async def get(self, workflow_id: str) -> Workflow:
26
+ data = await self._client.get(f"/workflows/{workflow_id}")
27
+ return Workflow.model_validate(data)
28
+
29
+ async def create(self, workflow: Workflow | dict[str, Any]) -> Workflow:
30
+ data = await self._client.post("/workflows", json=dump_payload(workflow))
31
+ return Workflow.model_validate(data)
32
+
33
+ async def update(
34
+ self, workflow_id: str, workflow: Workflow | dict[str, Any]
35
+ ) -> Workflow:
36
+ data = await self._client.put(
37
+ f"/workflows/{workflow_id}", json=dump_payload(workflow)
38
+ )
39
+ return Workflow.model_validate(data)
40
+
41
+ async def delete(self, workflow_id: str) -> dict[str, Any]:
42
+ return await self._client.delete(f"/workflows/{workflow_id}")
43
+
44
+ # ------------------------------------------------------------------ #
45
+ # Executions
46
+ #
47
+ # Executions, human tasks, traces and stats are returned as plain
48
+ # dicts: the execution contract is owned by the workflows service and
49
+ # intentionally not constrained here.
50
+ # ------------------------------------------------------------------ #
51
+
52
+ def _run_body(
53
+ self,
54
+ data: dict[str, Any] | None,
55
+ user_id: str | None,
56
+ callback_url: str | None,
57
+ events_hook: str | None,
58
+ ) -> dict[str, Any]:
59
+ body: dict[str, Any] = {"initialData": data or {}}
60
+ if user_id:
61
+ body["userId"] = user_id
62
+ if callback_url:
63
+ body["callbackUrl"] = callback_url
64
+ if events_hook:
65
+ body["eventsHook"] = events_hook
66
+ return body
67
+
68
+ async def execute(
69
+ self,
70
+ workflow_id: str,
71
+ data: dict[str, Any] | None = None,
72
+ user_id: str | None = None,
73
+ callback_url: str | None = None,
74
+ events_hook: str | None = None,
75
+ ) -> dict[str, Any]:
76
+ """Run a workflow synchronously (returns when terminal or suspended)."""
77
+ return await self._client.post(
78
+ f"/workflows/{workflow_id}/executions",
79
+ json=self._run_body(data, user_id, callback_url, events_hook),
80
+ )
81
+
82
+ async def queue(
83
+ self,
84
+ workflow_id: str,
85
+ data: dict[str, Any] | None = None,
86
+ user_id: str | None = None,
87
+ callback_url: str | None = None,
88
+ events_hook: str | None = None,
89
+ ) -> dict[str, Any]:
90
+ """Queue a workflow for asynchronous execution (returns an ``Execution``)."""
91
+ return await self._client.post(
92
+ f"/workflows/{workflow_id}/executions/queue",
93
+ json=self._run_body(data, user_id, callback_url, events_hook),
94
+ )
95
+
96
+ async def list_executions(
97
+ self, workflow_id: str, page: int = 1, size: int = 20
98
+ ) -> dict[str, Any]:
99
+ """List executions for a workflow (``Paginated[Execution]`` shape)."""
100
+ params: dict[str, Any] = {"page": page, "size": size}
101
+ return await self._client.get(
102
+ f"/workflows/{workflow_id}/executions", params=params
103
+ )
104
+
105
+ async def get_execution(
106
+ self, workflow_id: str, execution_id: str
107
+ ) -> dict[str, Any]:
108
+ """Get a single execution (run) with its steps, status and outputs."""
109
+ return await self._client.get(
110
+ f"/workflows/{workflow_id}/executions/{execution_id}"
111
+ )
112
+
113
+ async def list_runs(
114
+ self,
115
+ status: str | None = None,
116
+ workflow_id: str | None = None,
117
+ date_from: str | None = None,
118
+ date_to: str | None = None,
119
+ page: int = 1,
120
+ size: int = 20,
121
+ ) -> dict[str, Any]:
122
+ """List runs across all workflows in the project."""
123
+ params: dict[str, Any] = {"page": page, "size": size}
124
+ if status:
125
+ params["status"] = status
126
+ if workflow_id:
127
+ params["workflowId"] = workflow_id
128
+ if date_from:
129
+ params["dateFrom"] = date_from
130
+ if date_to:
131
+ params["dateTo"] = date_to
132
+ return await self._client.get("/executions", params=params)
133
+
134
+ async def cancel_execution(
135
+ self, workflow_id: str, execution_id: str
136
+ ) -> dict[str, Any]:
137
+ """Request cancellation of a running/waiting execution."""
138
+ return await self._client.post(
139
+ f"/workflows/{workflow_id}/executions/{execution_id}/cancel", json={}
140
+ )
141
+
142
+ async def rerun_execution(
143
+ self,
144
+ workflow_id: str,
145
+ execution_id: str,
146
+ from_node_id: str,
147
+ mode: str = "reuse_outputs",
148
+ user_id: str | None = None,
149
+ ) -> dict[str, Any]:
150
+ """Re-run an execution from a given node. mode: 'reuse_outputs' | 'fresh'."""
151
+ body: dict[str, Any] = {"fromNodeId": from_node_id, "mode": mode}
152
+ if user_id:
153
+ body["userId"] = user_id
154
+ return await self._client.post(
155
+ f"/workflows/{workflow_id}/executions/{execution_id}/rerun", json=body
156
+ )
157
+
158
+ async def dry_run_node(
159
+ self,
160
+ workflow_id: str,
161
+ node_id: str,
162
+ inputs: dict[str, Any] | None = None,
163
+ user_id: str | None = None,
164
+ ) -> dict[str, Any]:
165
+ """Execute a single node in isolation with the given inputs (debugging)."""
166
+ body: dict[str, Any] = {"inputs": inputs or {}}
167
+ if user_id:
168
+ body["userId"] = user_id
169
+ return await self._client.post(
170
+ f"/workflows/{workflow_id}/nodes/{node_id}/dry-run", json=body
171
+ )
172
+
173
+ async def get_step_trace(
174
+ self,
175
+ workflow_id: str,
176
+ execution_id: str,
177
+ step_id: str,
178
+ page: int = 1,
179
+ size: int = 200,
180
+ ) -> dict[str, Any]:
181
+ """Normalized action trace of an agent step (reasoning, tool calls, messages)."""
182
+ params: dict[str, Any] = {"page": page, "size": size}
183
+ return await self._client.get(
184
+ f"/workflows/{workflow_id}/executions/{execution_id}/steps/{step_id}/trace",
185
+ params=params,
186
+ )
187
+
188
+ # ------------------------------------------------------------------ #
189
+ # Stats
190
+ # ------------------------------------------------------------------ #
191
+
192
+ async def stats_overview(self) -> dict[str, Any]:
193
+ return await self._client.get("/stats/overview")
194
+
195
+ async def stats_executions_timeseries(
196
+ self,
197
+ date_from: str | None = None,
198
+ date_to: str | None = None,
199
+ workflow_id: str | None = None,
200
+ bucket: str = "day",
201
+ ) -> Any:
202
+ params: dict[str, Any] = {"bucket": bucket}
203
+ if date_from:
204
+ params["dateFrom"] = date_from
205
+ if date_to:
206
+ params["dateTo"] = date_to
207
+ if workflow_id:
208
+ params["workflowId"] = workflow_id
209
+ return await self._client.get("/stats/executions/timeseries", params=params)
210
+
211
+ async def stats_failing_nodes(
212
+ self,
213
+ date_from: str | None = None,
214
+ workflow_id: str | None = None,
215
+ limit: int = 10,
216
+ ) -> Any:
217
+ params: dict[str, Any] = {"limit": limit}
218
+ if date_from:
219
+ params["dateFrom"] = date_from
220
+ if workflow_id:
221
+ params["workflowId"] = workflow_id
222
+ return await self._client.get(
223
+ "/stats/executions/failing-nodes", params=params
224
+ )
225
+
226
+ async def stats_human_response_times(
227
+ self, date_from: str | None = None
228
+ ) -> dict[str, Any]:
229
+ params: dict[str, Any] = {}
230
+ if date_from:
231
+ params["dateFrom"] = date_from
232
+ return await self._client.get(
233
+ "/stats/human-tasks/response-times", params=params
234
+ )
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "persona-sdk-python"
3
- version = "0.2.18"
3
+ version = "0.2.20"
4
4
  description = "Async Python SDK for the Persona AI platform"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.10"
@@ -116,7 +116,7 @@ dependencies = [
116
116
  [package.metadata]
117
117
  requires-dist = [
118
118
  { name = "httpx", specifier = ">=0.27.0" },
119
- { name = "persona-models", specifier = ">=0.2.2" },
119
+ { name = "persona-models", specifier = ">=0.2.4" },
120
120
  ]
121
121
 
122
122
  [[package]]
@@ -226,14 +226,6 @@ wheels = [
226
226
  { url = "https://files.pythonhosted.org/packages/5c/96/5fb7d8c3c17bc8c62fdb031c47d77a1af698f1d7a406b0f79aaa1338f9ad/pydantic_core-2.41.5-cp314-cp314t-win32.whl", hash = "sha256:b4ececa40ac28afa90871c2cc2b9ffd2ff0bf749380fbdf57d165fd23da353aa", size = 1988906 },
227
227
  { url = "https://files.pythonhosted.org/packages/22/ed/182129d83032702912c2e2d8bbe33c036f342cc735737064668585dac28f/pydantic_core-2.41.5-cp314-cp314t-win_amd64.whl", hash = "sha256:80aa89cad80b32a912a65332f64a4450ed00966111b6615ca6816153d3585a8c", size = 1981607 },
228
228
  { url = "https://files.pythonhosted.org/packages/9f/ed/068e41660b832bb0b1aa5b58011dea2a3fe0ba7861ff38c4d4904c1c1a99/pydantic_core-2.41.5-cp314-cp314t-win_arm64.whl", hash = "sha256:35b44f37a3199f771c3eaa53051bc8a70cd7b54f333531c59e29fd4db5d15008", size = 1974769 },
229
- { url = "https://files.pythonhosted.org/packages/11/72/90fda5ee3b97e51c494938a4a44c3a35a9c96c19bba12372fb9c634d6f57/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:b96d5f26b05d03cc60f11a7761a5ded1741da411e7fe0909e27a5e6a0cb7b034", size = 2115441 },
230
- { url = "https://files.pythonhosted.org/packages/1f/53/8942f884fa33f50794f119012dc6a1a02ac43a56407adaac20463df8e98f/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:634e8609e89ceecea15e2d61bc9ac3718caaaa71963717bf3c8f38bfde64242c", size = 1930291 },
231
- { url = "https://files.pythonhosted.org/packages/79/c8/ecb9ed9cd942bce09fc888ee960b52654fbdbede4ba6c2d6e0d3b1d8b49c/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:93e8740d7503eb008aa2df04d3b9735f845d43ae845e6dcd2be0b55a2da43cd2", size = 1948632 },
232
- { url = "https://files.pythonhosted.org/packages/2e/1b/687711069de7efa6af934e74f601e2a4307365e8fdc404703afc453eab26/pydantic_core-2.41.5-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f15489ba13d61f670dcc96772e733aad1a6f9c429cc27574c6cdaed82d0146ad", size = 2138905 },
233
- { url = "https://files.pythonhosted.org/packages/09/32/59b0c7e63e277fa7911c2fc70ccfb45ce4b98991e7ef37110663437005af/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:7da7087d756b19037bc2c06edc6c170eeef3c3bafcb8f532ff17d64dc427adfd", size = 2110495 },
234
- { url = "https://files.pythonhosted.org/packages/aa/81/05e400037eaf55ad400bcd318c05bb345b57e708887f07ddb2d20e3f0e98/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:aabf5777b5c8ca26f7824cb4a120a740c9588ed58df9b2d196ce92fba42ff8dc", size = 1915388 },
235
- { url = "https://files.pythonhosted.org/packages/6e/0d/e3549b2399f71d56476b77dbf3cf8937cec5cd70536bdc0e374a421d0599/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c007fe8a43d43b3969e8469004e9845944f1a80e6acd47c150856bb87f230c56", size = 1942879 },
236
- { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017 },
237
229
  { url = "https://files.pythonhosted.org/packages/e6/b0/1a2aa41e3b5a4ba11420aba2d091b2d17959c8d1519ece3627c371951e73/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:b5819cd790dbf0c5eb9f82c73c16b39a65dd6dd4d1439dcdea7816ec9adddab8", size = 2103351 },
238
230
  { url = "https://files.pythonhosted.org/packages/a4/ee/31b1f0020baaf6d091c87900ae05c6aeae101fa4e188e1613c80e4f1ea31/pydantic_core-2.41.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:5a4e67afbc95fa5c34cf27d9089bca7fcab4e51e57278d710320a70b956d1b9a", size = 1925363 },
239
231
  { url = "https://files.pythonhosted.org/packages/e1/89/ab8e86208467e467a80deaca4e434adac37b10a9d134cd2f99b28a01e483/pydantic_core-2.41.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ece5c59f0ce7d001e017643d8d24da587ea1f74f6993467d85ae8a5ef9d4f42b", size = 2135615 },
@@ -1,17 +0,0 @@
1
- image: python:3.12
2
-
3
- pipelines:
4
- default:
5
- - step:
6
- name: Publish to PyPI
7
- caches:
8
- - pip
9
- script:
10
- - apt-get update && apt-get install -y git
11
- - pip install build twine
12
- - export VERSION=0.2.$BITBUCKET_BUILD_NUMBER
13
- - sed -i "s/^version = .*/version = \"$VERSION\"/" pyproject.toml
14
- - python -m build
15
- - twine upload dist/* -u __token__ -p $PYPI_TOKEN
16
- - git tag -a $VERSION -m "$VERSION"
17
- - git push origin $VERSION
@@ -1,49 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Any
4
-
5
- from persona_models.common import Paginated
6
- from persona_models.known_models import KnownModel
7
-
8
- from persona_sdk._serde import dump_payload
9
- from persona_sdk.client import PersonaClient
10
-
11
-
12
- class KnownModelsApi:
13
- def __init__(self, client: PersonaClient):
14
- self._client = client
15
-
16
- async def list(
17
- self, keyword: str | None = None, page: int = 1, size: int = 100
18
- ) -> Paginated[KnownModel]:
19
- params: dict[str, Any] = {"page": page, "size": size}
20
- if keyword:
21
- params["keyword"] = keyword
22
- data = await self._client.get("/known-models", params=params)
23
- return Paginated[KnownModel].model_validate(data)
24
-
25
- async def get(self, known_model_id: str) -> KnownModel:
26
- data = await self._client.get(f"/known-models/{known_model_id}")
27
- return KnownModel.model_validate(data)
28
-
29
- async def create(
30
- self, known_model: KnownModel | dict[str, Any]
31
- ) -> KnownModel:
32
- data = await self._client.post(
33
- "/known-models", json=dump_payload(known_model)
34
- )
35
- return KnownModel.model_validate(data)
36
-
37
- async def update(
38
- self,
39
- known_model_id: str,
40
- known_model: KnownModel | dict[str, Any],
41
- ) -> KnownModel:
42
- data = await self._client.put(
43
- f"/known-models/{known_model_id}", json=dump_payload(known_model)
44
- )
45
- return KnownModel.model_validate(data)
46
-
47
- async def delete(self, known_model_id: str) -> KnownModel:
48
- data = await self._client.delete(f"/known-models/{known_model_id}")
49
- return KnownModel.model_validate(data)
@@ -1,72 +0,0 @@
1
- from __future__ import annotations
2
-
3
- from typing import Any
4
-
5
- from persona_models.common import Paginated
6
- from persona_models.workflows import Workflow
7
-
8
- from persona_sdk._serde import dump_payload
9
- from persona_sdk.client import PersonaClient
10
-
11
-
12
- class WorkflowsApi:
13
- def __init__(self, client: PersonaClient):
14
- self._client = client
15
-
16
- async def list(
17
- self, keyword: str | None = None, page: int = 1, size: int = 20
18
- ) -> Paginated[Workflow]:
19
- params: dict[str, Any] = {"page": page, "size": size}
20
- if keyword:
21
- params["keyword"] = keyword
22
- data = await self._client.get("/workflows", params=params)
23
- return Paginated[Workflow].model_validate(data)
24
-
25
- async def get(self, workflow_id: str) -> Workflow:
26
- data = await self._client.get(f"/workflows/{workflow_id}")
27
- return Workflow.model_validate(data)
28
-
29
- async def create(self, workflow: Workflow | dict[str, Any]) -> Workflow:
30
- data = await self._client.post("/workflows", json=dump_payload(workflow))
31
- return Workflow.model_validate(data)
32
-
33
- async def update(
34
- self, workflow_id: str, workflow: Workflow | dict[str, Any]
35
- ) -> Workflow:
36
- data = await self._client.put(
37
- f"/workflows/{workflow_id}", json=dump_payload(workflow)
38
- )
39
- return Workflow.model_validate(data)
40
-
41
- async def delete(self, workflow_id: str) -> dict[str, Any]:
42
- return await self._client.delete(f"/workflows/{workflow_id}")
43
-
44
- async def execute(
45
- self, workflow_id: str, data: dict[str, Any] | None = None
46
- ) -> dict[str, Any]:
47
- """Execute a workflow synchronously.
48
-
49
- Returns the workflow ``Execution`` (``status``, ``steps``, ``output``,
50
- ``error``, ...) as a plain dict; the execution contract is owned by the
51
- workflows service and intentionally not constrained here.
52
- """
53
- return await self._client.post(
54
- f"/workflows/{workflow_id}/execute", json=data or {}
55
- )
56
-
57
- async def queue(
58
- self, workflow_id: str, data: dict[str, Any] | None = None
59
- ) -> dict[str, Any]:
60
- """Queue a workflow for asynchronous execution (returns an ``Execution``)."""
61
- return await self._client.post(
62
- f"/workflows/{workflow_id}/queue", json=data or {}
63
- )
64
-
65
- async def list_executions(
66
- self, workflow_id: str, page: int = 1, size: int = 20
67
- ) -> dict[str, Any]:
68
- """List executions for a workflow (``Paginated[Execution]`` shape)."""
69
- params: dict[str, Any] = {"page": page, "size": size}
70
- return await self._client.get(
71
- f"/workflows/{workflow_id}/executions", params=params
72
- )