pushary 2.2.1__tar.gz → 2.3.0__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.
- {pushary-2.2.1 → pushary-2.3.0}/PKG-INFO +6 -1
- {pushary-2.2.1 → pushary-2.3.0}/README.md +5 -0
- {pushary-2.2.1 → pushary-2.3.0}/pyproject.toml +1 -1
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/__init__.py +3 -1
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/client.py +2 -0
- pushary-2.3.0/src/pushary/reminders.py +25 -0
- pushary-2.3.0/tests/test_reminders.py +17 -0
- {pushary-2.2.1 → pushary-2.3.0}/.gitignore +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/LICENSE +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/examples/agno/README.md +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/examples/dify/README.md +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/examples/llamaindex/README.md +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/examples/microsoft/README.md +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/examples/strands/README.md +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/_types.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/_util.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/adapters.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/decisions.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/errors.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/keys.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/py.typed +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/src/pushary/webhook.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/tests/test_adapters.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/tests/test_agent.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/tests/test_client.py +0 -0
- {pushary-2.2.1 → pushary-2.3.0}/tests/test_webhook.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: pushary
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.3.0
|
|
4
4
|
Summary: The decision layer for AI agents. Your agent asks, your user decides on their phone.
|
|
5
5
|
Project-URL: Homepage, https://pushary.com
|
|
6
6
|
Project-URL: Documentation, https://pushary.com/docs
|
|
@@ -291,3 +291,8 @@ These keys intentionally differ from 2.0. Do not replay completed operations dur
|
|
|
291
291
|
### Upgrading to 2.2
|
|
292
292
|
|
|
293
293
|
`ApprovalAsk` accepts `context`. The shared approval gate sends it with the decision, so the approver can read what the notification cannot fit, such as a tool's full arguments. Context is part of the approval identity when set. An ask without context keeps the key it had in 2.1, so pending approvals carry over.
|
|
294
|
+
## Personal reminders
|
|
295
|
+
|
|
296
|
+
On an active Agent workspace, `client.reminders.schedule("Check the deploy", in_minutes=30)` saves a one-time reminder that survives the agent exiting. Use `at` with an explicit UTC offset for calendar times, up to 30 days away. `client.reminders.list()` lists your pending reminders; `client.reminders.cancel(reminder_id)` cancels one before dispatch starts. Confirm the returned `reminder.fireAt`. Delivery requires a connected phone and can be about a minute late. These personal reminders do not schedule agent work or Partner customer campaigns.
|
|
297
|
+
|
|
298
|
+
Personal reminder bodies must fit 180 UTF-16 units after secret redaction (most emoji use two); titles must fit 100. Oversized text is rejected. Listing and cancelling accepted reminders remain available when billing access closes.
|
|
@@ -263,3 +263,8 @@ These keys intentionally differ from 2.0. Do not replay completed operations dur
|
|
|
263
263
|
### Upgrading to 2.2
|
|
264
264
|
|
|
265
265
|
`ApprovalAsk` accepts `context`. The shared approval gate sends it with the decision, so the approver can read what the notification cannot fit, such as a tool's full arguments. Context is part of the approval identity when set. An ask without context keeps the key it had in 2.1, so pending approvals carry over.
|
|
266
|
+
## Personal reminders
|
|
267
|
+
|
|
268
|
+
On an active Agent workspace, `client.reminders.schedule("Check the deploy", in_minutes=30)` saves a one-time reminder that survives the agent exiting. Use `at` with an explicit UTC offset for calendar times, up to 30 days away. `client.reminders.list()` lists your pending reminders; `client.reminders.cancel(reminder_id)` cancels one before dispatch starts. Confirm the returned `reminder.fireAt`. Delivery requires a connected phone and can be about a minute late. These personal reminders do not schedule agent work or Partner customer campaigns.
|
|
269
|
+
|
|
270
|
+
Personal reminder bodies must fit 180 UTF-16 units after secret redaction (most emoji use two); titles must fit 100. Oversized text is rejected. Listing and cancelling accepted reminders remain available when billing access closes.
|
|
@@ -19,15 +19,17 @@ from ._util import deterministic_key, is_approved
|
|
|
19
19
|
from .client import PusharyServer
|
|
20
20
|
from .decisions import DecisionsResource
|
|
21
21
|
from .keys import KeysResource
|
|
22
|
+
from .reminders import RemindersResource
|
|
22
23
|
from .errors import PusharyError
|
|
23
24
|
from .webhook import SIGNATURE_HEADER, parse_decision_callback, verify_webhook_signature
|
|
24
25
|
|
|
25
|
-
__version__ = "2.
|
|
26
|
+
__version__ = "2.3.0"
|
|
26
27
|
|
|
27
28
|
__all__ = [
|
|
28
29
|
"PusharyServer",
|
|
29
30
|
"DecisionsResource",
|
|
30
31
|
"KeysResource",
|
|
32
|
+
"RemindersResource",
|
|
31
33
|
"PusharyError",
|
|
32
34
|
"verify_webhook_signature",
|
|
33
35
|
"parse_decision_callback",
|
|
@@ -15,6 +15,7 @@ from urllib.parse import quote, urlencode
|
|
|
15
15
|
|
|
16
16
|
from .decisions import DecisionsResource
|
|
17
17
|
from .keys import KeysResource
|
|
18
|
+
from .reminders import RemindersResource
|
|
18
19
|
from .errors import PusharyError
|
|
19
20
|
|
|
20
21
|
DEFAULT_BASE_URL = "https://pushary.com/api/v1/server"
|
|
@@ -49,6 +50,7 @@ class PusharyServer:
|
|
|
49
50
|
self._timeout = DEFAULT_TIMEOUT_SECONDS
|
|
50
51
|
self.decisions = DecisionsResource(self._request)
|
|
51
52
|
self.keys = KeysResource(self._request)
|
|
53
|
+
self.reminders = RemindersResource(self._request)
|
|
52
54
|
|
|
53
55
|
def evaluate_authorization(
|
|
54
56
|
self,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Callable, Dict, Optional
|
|
3
|
+
|
|
4
|
+
RequestFn = Callable[..., Dict[str, object]]
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class RemindersResource:
|
|
8
|
+
def __init__(self, request: RequestFn) -> None:
|
|
9
|
+
self._request = request
|
|
10
|
+
|
|
11
|
+
def schedule(
|
|
12
|
+
self, body: str, *, in_minutes: Optional[int] = None, at: Optional[str] = None,
|
|
13
|
+
title: Optional[str] = None, agent_name: Optional[str] = None,
|
|
14
|
+
session_id: Optional[str] = None, machine_id: Optional[str] = None,
|
|
15
|
+
env: Optional[str] = None,
|
|
16
|
+
) -> Dict[str, object]:
|
|
17
|
+
values = {"body": body, "inMinutes": in_minutes, "at": at, "title": title,
|
|
18
|
+
"agentName": agent_name, "sessionId": session_id, "machineId": machine_id, "env": env}
|
|
19
|
+
return self._request("POST", "/reminders", body={key: value for key, value in values.items() if value is not None})
|
|
20
|
+
|
|
21
|
+
def list(self) -> Dict[str, object]:
|
|
22
|
+
return self._request("GET", "/reminders")
|
|
23
|
+
|
|
24
|
+
def cancel(self, reminder_id: str) -> Dict[str, object]:
|
|
25
|
+
return self._request("POST", "/reminders", body={"cancelReminderId": reminder_id})
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
from unittest import mock
|
|
3
|
+
from pushary import PusharyServer
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ReminderTests(unittest.TestCase):
|
|
7
|
+
def test_schedule_list_and_cancel_use_authenticated_reminder_resource(self):
|
|
8
|
+
with mock.patch.object(PusharyServer, '_request', return_value={'pending': []}) as request:
|
|
9
|
+
client = PusharyServer('pk_test.secret')
|
|
10
|
+
client.reminders.schedule('Check deploy', in_minutes=30)
|
|
11
|
+
client.reminders.list()
|
|
12
|
+
client.reminders.cancel('id')
|
|
13
|
+
self.assertEqual(request.call_args_list, [
|
|
14
|
+
mock.call('POST', '/reminders', body={'body': 'Check deploy', 'inMinutes': 30}),
|
|
15
|
+
mock.call('GET', '/reminders'),
|
|
16
|
+
mock.call('POST', '/reminders', body={'cancelReminderId': 'id'}),
|
|
17
|
+
])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|