oneshot-python 0.12.0__tar.gz → 0.14.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.
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/PKG-INFO +1 -1
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/README.md +1 -1
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/oneshot/client.py +44 -9
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/pyproject.toml +1 -1
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_tag_receipt_value.py +36 -2
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/uv.lock +1 -1
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/.gitignore +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/oneshot/__init__.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/oneshot/_errors.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/oneshot/_types.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/oneshot/x402.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/__init__.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_balance.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_compute.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_email_payload.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_emergency_error.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_max_cost_header.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_phones_pending.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_request_id.py +0 -0
- {oneshot_python-0.12.0 → oneshot_python-0.14.0}/tests/test_x402.py +0 -0
|
@@ -127,7 +127,7 @@ Every method has an `a*` async mirror (`acompute`, `aget_compute_goal`, …).
|
|
|
127
127
|
## Links
|
|
128
128
|
|
|
129
129
|
- [Documentation](https://docs.oneshotagent.com/sdk/installation#install-via-pip-python)
|
|
130
|
-
- [LangChain integration](https://pypi.org/project/langchain-oneshot/) —
|
|
130
|
+
- [LangChain integration](https://pypi.org/project/langchain-oneshot/) — 31 tools as LangChain BaseTool
|
|
131
131
|
- [GAME plugin](https://pypi.org/project/game-plugin-oneshot/) — Virtuals Protocol integration
|
|
132
132
|
- [TypeScript SDK](https://www.npmjs.com/package/@oneshot-agent/sdk)
|
|
133
133
|
- [MCP Server](https://www.npmjs.com/package/@oneshot-agent/mcp-server)
|
|
@@ -31,7 +31,14 @@ from oneshot.x402 import (
|
|
|
31
31
|
sign_payment_authorization,
|
|
32
32
|
)
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
# Derived from the installed package metadata so it never drifts from
|
|
35
|
+
# pyproject.toml. Falls back to a literal for editable/uninstalled runs.
|
|
36
|
+
try:
|
|
37
|
+
from importlib.metadata import version as _pkg_version
|
|
38
|
+
|
|
39
|
+
SDK_VERSION = _pkg_version("oneshot-python")
|
|
40
|
+
except Exception: # pragma: no cover - editable/source runs without dist metadata
|
|
41
|
+
SDK_VERSION = "0.12.1"
|
|
35
42
|
|
|
36
43
|
# ---------------------------------------------------------------------------
|
|
37
44
|
# Environment configuration
|
|
@@ -821,6 +828,22 @@ class OneShotClient:
|
|
|
821
828
|
"""Enrich a person's profile from LinkedIn URL, email, or name. Async."""
|
|
822
829
|
return await self.acall_tool("/v1/tools/enrich/profile", kwargs)
|
|
823
830
|
|
|
831
|
+
def company_search(self, **kwargs: Any) -> Any:
|
|
832
|
+
"""Search for companies by name, domain, industry, location, size, etc. Blocking."""
|
|
833
|
+
return self.call_tool("/v1/tools/research/company", kwargs)
|
|
834
|
+
|
|
835
|
+
async def acompany_search(self, **kwargs: Any) -> Any:
|
|
836
|
+
"""Search for companies by name, domain, industry, location, size, etc. Async."""
|
|
837
|
+
return await self.acall_tool("/v1/tools/research/company", kwargs)
|
|
838
|
+
|
|
839
|
+
def enrich_company(self, **kwargs: Any) -> Any:
|
|
840
|
+
"""Enrich a company from domain, name, LinkedIn URL, or ticker. Blocking."""
|
|
841
|
+
return self.call_tool("/v1/tools/enrich/company", kwargs)
|
|
842
|
+
|
|
843
|
+
async def aenrich_company(self, **kwargs: Any) -> Any:
|
|
844
|
+
"""Enrich a company from domain, name, LinkedIn URL, or ticker. Async."""
|
|
845
|
+
return await self.acall_tool("/v1/tools/enrich/company", kwargs)
|
|
846
|
+
|
|
824
847
|
def find_email(self, company_domain: str, *, full_name: Optional[str] = None, first_name: Optional[str] = None, last_name: Optional[str] = None, **kwargs: Any) -> Any:
|
|
825
848
|
"""Find a person's email address. Blocking."""
|
|
826
849
|
payload: dict[str, Any] = {"company_domain": company_domain, **kwargs}
|
|
@@ -941,32 +964,44 @@ class OneShotClient:
|
|
|
941
964
|
|
|
942
965
|
def tag_receipt_value(
|
|
943
966
|
self,
|
|
944
|
-
receipt_id: str,
|
|
945
|
-
value_tag: dict[str, Any],
|
|
967
|
+
receipt_id: Optional[str] = None,
|
|
968
|
+
value_tag: Optional[dict[str, Any]] = None,
|
|
969
|
+
*,
|
|
970
|
+
request_id: Optional[str] = None,
|
|
946
971
|
) -> dict:
|
|
947
972
|
"""Tag a receipt with a value for RoCS computation. Blocking.
|
|
948
973
|
|
|
974
|
+
Identify the receipt by ``receipt_id`` (``rcpt_…``) or, equivalently, by
|
|
975
|
+
the ``request_id`` returned from the originating tool call — the API
|
|
976
|
+
resolves a ``request_id`` via the receipt's ``job_id``, so you can tag
|
|
977
|
+
value without a prior receipts lookup.
|
|
978
|
+
|
|
949
979
|
``value_tag`` shape: ``{"type": ..., "amount": ..., "label": ...}``.
|
|
950
980
|
``type`` must be one of ``revenue``, ``lead``, ``conversion``,
|
|
951
981
|
``savings``, ``engagement``. Tags are stored as ``pending`` until a
|
|
952
982
|
judge service confirms them against inbound signals.
|
|
953
983
|
"""
|
|
954
984
|
return asyncio.get_event_loop().run_until_complete(
|
|
955
|
-
self.atag_receipt_value(receipt_id, value_tag)
|
|
985
|
+
self.atag_receipt_value(receipt_id, value_tag, request_id=request_id)
|
|
956
986
|
)
|
|
957
987
|
|
|
958
988
|
async def atag_receipt_value(
|
|
959
989
|
self,
|
|
960
|
-
receipt_id: str,
|
|
961
|
-
value_tag: dict[str, Any],
|
|
990
|
+
receipt_id: Optional[str] = None,
|
|
991
|
+
value_tag: Optional[dict[str, Any]] = None,
|
|
992
|
+
*,
|
|
993
|
+
request_id: Optional[str] = None,
|
|
962
994
|
) -> dict:
|
|
963
995
|
"""Tag a receipt with a value for RoCS computation. Async."""
|
|
964
|
-
|
|
965
|
-
|
|
996
|
+
target = receipt_id or request_id
|
|
997
|
+
if not target:
|
|
998
|
+
raise ValidationError(
|
|
999
|
+
"receipt_id or request_id is required", "receipt_id"
|
|
1000
|
+
)
|
|
966
1001
|
if not isinstance(value_tag, dict) or not value_tag.get("type"):
|
|
967
1002
|
raise ValidationError("value_tag.type is required", "value_tag.type")
|
|
968
1003
|
return await self.acall_free_patch(
|
|
969
|
-
f"/v1/analytics/receipts/{
|
|
1004
|
+
f"/v1/analytics/receipts/{target}/value",
|
|
970
1005
|
value_tag,
|
|
971
1006
|
)
|
|
972
1007
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "oneshot-python"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.14.0"
|
|
4
4
|
description = "Core Python SDK for the OneShot API — HTTP client with x402 payment handling"
|
|
5
5
|
readme = {text = "Core Python SDK for the OneShot API", content-type = "text/plain"}
|
|
6
6
|
license = "MIT"
|
|
@@ -70,18 +70,52 @@ async def test_accepts_minimal_valid_tag_with_just_type():
|
|
|
70
70
|
mock.assert_awaited_once()
|
|
71
71
|
|
|
72
72
|
|
|
73
|
+
# ── Resolving by request_id (== job_id) instead of receipt_id ────────────
|
|
74
|
+
|
|
75
|
+
@pytest.mark.asyncio
|
|
76
|
+
async def test_tags_by_request_id():
|
|
77
|
+
# A request_id from the original tool call resolves server-side via job_id.
|
|
78
|
+
c, mock = _client_with_mocked_patch()
|
|
79
|
+
tag = {"type": "lead", "amount": 1}
|
|
80
|
+
await c.atag_receipt_value(value_tag=tag, request_id="0cbb87ee-1f2a-4c3d-9e8b-7a6f5d4c3b2a")
|
|
81
|
+
mock.assert_awaited_once_with(
|
|
82
|
+
"/v1/analytics/receipts/0cbb87ee-1f2a-4c3d-9e8b-7a6f5d4c3b2a/value", tag
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@pytest.mark.asyncio
|
|
87
|
+
async def test_receipt_id_preferred_over_request_id():
|
|
88
|
+
c, mock = _client_with_mocked_patch()
|
|
89
|
+
tag = {"type": "revenue", "amount": 2}
|
|
90
|
+
await c.atag_receipt_value("rcpt_01HX", tag, request_id="some-uuid")
|
|
91
|
+
mock.assert_awaited_once_with("/v1/analytics/receipts/rcpt_01HX/value", tag)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
@pytest.mark.asyncio
|
|
95
|
+
async def test_raises_when_neither_id_provided():
|
|
96
|
+
c, _ = _client_with_mocked_patch()
|
|
97
|
+
with pytest.raises(ValidationError) as excinfo:
|
|
98
|
+
await c.atag_receipt_value(value_tag={"type": "revenue", "amount": 1})
|
|
99
|
+
assert excinfo.value.field == "receipt_id"
|
|
100
|
+
|
|
101
|
+
|
|
73
102
|
def test_sync_wrapper_delegates_to_async(monkeypatch):
|
|
74
103
|
# The blocking ``tag_receipt_value`` should call through to the async
|
|
75
104
|
# version via the event loop, matching every other tool method.
|
|
76
105
|
c = OneShotClient(TEST_PRIVATE_KEY)
|
|
77
106
|
called: dict = {}
|
|
78
107
|
|
|
79
|
-
async def fake_async(receipt_id, value_tag):
|
|
108
|
+
async def fake_async(receipt_id=None, value_tag=None, *, request_id=None):
|
|
80
109
|
called["receipt_id"] = receipt_id
|
|
81
110
|
called["value_tag"] = value_tag
|
|
111
|
+
called["request_id"] = request_id
|
|
82
112
|
return {"ok": True}
|
|
83
113
|
|
|
84
114
|
c.atag_receipt_value = fake_async # type: ignore[method-assign]
|
|
85
115
|
result = c.tag_receipt_value("rcpt_01HX", {"type": "savings", "amount": 12})
|
|
86
116
|
assert result == {"ok": True}
|
|
87
|
-
assert called == {
|
|
117
|
+
assert called == {
|
|
118
|
+
"receipt_id": "rcpt_01HX",
|
|
119
|
+
"value_tag": {"type": "savings", "amount": 12},
|
|
120
|
+
"request_id": None,
|
|
121
|
+
}
|
|
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
|