oneshot-python 0.38.0__tar.gz → 0.39.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.
Files changed (49) hide show
  1. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/PKG-INFO +1 -1
  2. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/README.md +1 -1
  3. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/client.py +54 -50
  4. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/lookup_manifest.py +245 -127
  5. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/pyproject.toml +1 -1
  6. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_declared_routes.py +4 -4
  7. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_lookup.py +8 -0
  8. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_paid_call_proof.py +1 -1
  9. oneshot_python-0.39.0/tests/test_person_quote_credits.py +82 -0
  10. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_phones_pending.py +7 -1
  11. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/.gitignore +0 -0
  12. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/__init__.py +0 -0
  13. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/_errors.py +0 -0
  14. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/_types.py +0 -0
  15. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/lookup.py +0 -0
  16. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/physical_mail.py +0 -0
  17. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/oneshot/x402.py +0 -0
  18. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/__init__.py +0 -0
  19. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/conftest.py +0 -0
  20. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_access_token.py +0 -0
  21. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_approvals.py +0 -0
  22. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_balance.py +0 -0
  23. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_browser.py +0 -0
  24. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_budgets.py +0 -0
  25. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_charge_amount.py +0 -0
  26. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_compute.py +0 -0
  27. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_compute_manifest.py +0 -0
  28. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_compute_outputs.py +0 -0
  29. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_declared_worker_reads.py +0 -0
  30. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_domains.py +0 -0
  31. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_domains_signed.py +0 -0
  32. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_email_payload.py +0 -0
  33. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_emergency_error.py +0 -0
  34. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_hunts.py +0 -0
  35. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_inbound_voice.py +0 -0
  36. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_inbox_notifications.py +0 -0
  37. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_linkedin.py +0 -0
  38. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_max_cost_header.py +0 -0
  39. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_payment_rejection.py +0 -0
  40. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_physical_mail.py +0 -0
  41. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_poll_backoff.py +0 -0
  42. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_request_id.py +0 -0
  43. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_signed_job_and_analytics.py +0 -0
  44. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_tag_receipt_value.py +0 -0
  45. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_top_up_credits.py +0 -0
  46. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_update_build.py +0 -0
  47. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_wait_false.py +0 -0
  48. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/tests/test_x402.py +0 -0
  49. {oneshot_python-0.38.0 → oneshot_python-0.39.0}/uv.lock +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: oneshot-python
3
- Version: 0.38.0
3
+ Version: 0.39.0
4
4
  Summary: Core Python SDK for the OneShot API — HTTP client with x402 payment handling — 48 tools
5
5
  License-Expression: MIT
6
6
  Requires-Python: >=3.10
@@ -244,7 +244,7 @@ except LinkedInConnectRequiredError:
244
244
 
245
245
  Account reads stop offering reconnect after confirming upstream deletion.
246
246
  Missing accounts are excluded from the active list; `include_revoked=True`
247
- lets you inspect their `deleted_upstream` status and `reconnect_required=False`.
247
+ lets you inspect their `connection_deleted` status and `reconnect_required=False`.
248
248
  Authentication failures and timeouts remain ordinary errors and do not instruct
249
249
  the consumer to create a new connection.
250
250
 
@@ -60,13 +60,13 @@ try:
60
60
 
61
61
  SDK_VERSION = _pkg_version("oneshot-python")
62
62
  except Exception: # pragma: no cover - editable/source runs without dist metadata
63
- SDK_VERSION = "0.38.0"
63
+ SDK_VERSION = "0.39.0"
64
64
 
65
65
  _BASE_URL = "https://win.oneshotagent.com"
66
66
  _HUNT_BASE_URL = "https://api.soulhunt.ai"
67
67
  _ACCESS_TOKEN_RE = re.compile(r"^oneshot_[0-9a-f]{64}$")
68
68
  # Endpoints whose admission reads a "submit"-scoped agent proof (same list as the TypeScript SDK).
69
- _DURABLE_ADMISSION_ENDPOINT = re.compile(r"(enrich/(profile|email)|verify/email|physical-mail/send)$")
69
+ _DURABLE_ADMISSION_ENDPOINT = re.compile(r"(lookup/person-(profile|email|email-status)|lookup/place-permits|physical-mail/send)$")
70
70
  _CHAIN_ID = 8453
71
71
  _USDC_ADDRESS = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
72
72
 
@@ -2073,37 +2073,37 @@ class OneShotClient:
2073
2073
  approval_id = kwargs.pop("approval_id", None)
2074
2074
  return await self.acall_tool("/v1/tools/sms/send", {"message": message, "to_number": to_number, **kwargs}, approval_id=approval_id)
2075
2075
 
2076
- def people_search(self, **kwargs: Any) -> Any:
2076
+ def person_find(self, **kwargs: Any) -> Any:
2077
2077
  """Search for people by job title, company, etc. Blocking."""
2078
- return self.call_tool("/v1/tools/research/people", kwargs)
2078
+ return self.call_tool("/v1/tools/find/person", kwargs)
2079
2079
 
2080
- async def apeople_search(self, **kwargs: Any) -> Any:
2080
+ async def aperson_find(self, **kwargs: Any) -> Any:
2081
2081
  """Search for people by job title, company, etc. Async."""
2082
- return await self.acall_tool("/v1/tools/research/people", kwargs)
2082
+ return await self.acall_tool("/v1/tools/find/person", kwargs)
2083
2083
 
2084
- def enrich_profile(self, **kwargs: Any) -> Any:
2084
+ def person_profile(self, **kwargs: Any) -> Any:
2085
2085
  """Enrich a person's profile from LinkedIn URL, email, or name. Blocking."""
2086
- return self.call_tool("/v1/tools/enrich/profile", kwargs)
2086
+ return self.call_tool("/v1/tools/lookup/person-profile", kwargs)
2087
2087
 
2088
- async def aenrich_profile(self, **kwargs: Any) -> Any:
2088
+ async def aperson_profile(self, **kwargs: Any) -> Any:
2089
2089
  """Enrich a person's profile from LinkedIn URL, email, or name. Async."""
2090
- return await self.acall_tool("/v1/tools/enrich/profile", kwargs)
2090
+ return await self.acall_tool("/v1/tools/lookup/person-profile", kwargs)
2091
2091
 
2092
- def company_search(self, **kwargs: Any) -> Any:
2092
+ def company_find(self, **kwargs: Any) -> Any:
2093
2093
  """Search for companies by name, domain, industry, location, size, etc. Blocking."""
2094
- return self.call_tool("/v1/tools/research/company", kwargs)
2094
+ return self.call_tool("/v1/tools/find/company", kwargs)
2095
2095
 
2096
- async def acompany_search(self, **kwargs: Any) -> Any:
2096
+ async def acompany_find(self, **kwargs: Any) -> Any:
2097
2097
  """Search for companies by name, domain, industry, location, size, etc. Async."""
2098
- return await self.acall_tool("/v1/tools/research/company", kwargs)
2098
+ return await self.acall_tool("/v1/tools/find/company", kwargs)
2099
2099
 
2100
- def enrich_company(self, **kwargs: Any) -> Any:
2100
+ def company_profile(self, **kwargs: Any) -> Any:
2101
2101
  """Enrich a company from domain, name, LinkedIn URL, or ticker. Blocking."""
2102
- return self.call_tool("/v1/tools/enrich/company", kwargs)
2102
+ return self.call_tool("/v1/tools/lookup/company-profile", kwargs)
2103
2103
 
2104
- async def aenrich_company(self, **kwargs: Any) -> Any:
2104
+ async def acompany_profile(self, **kwargs: Any) -> Any:
2105
2105
  """Enrich a company from domain, name, LinkedIn URL, or ticker. Async."""
2106
- return await self.acall_tool("/v1/tools/enrich/company", kwargs)
2106
+ return await self.acall_tool("/v1/tools/lookup/company-profile", kwargs)
2107
2107
 
2108
2108
  def business_find(self, **kwargs: Any) -> Any:
2109
2109
  """Discover local businesses (restaurants, contractors, practices) by category/keywords x location. Blocking."""
@@ -2129,7 +2129,7 @@ class OneShotClient:
2129
2129
  """Federal Sources Sought / Presolicitation notices (SAM.gov) by NAICS code with the contracting officer's contact. Result carries `data_as_of` (snapshot behind the rows). Async."""
2130
2130
  return await self.acall_tool("/v1/tools/find/record-solicitations", {"naics": naics, **kwargs})
2131
2131
 
2132
- 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:
2132
+ def person_email(self, company_domain: str, *, full_name: Optional[str] = None, first_name: Optional[str] = None, last_name: Optional[str] = None, **kwargs: Any) -> Any:
2133
2133
  """Find a person's email address. Blocking."""
2134
2134
  payload: dict[str, Any] = {"company_domain": company_domain, **kwargs}
2135
2135
  if full_name:
@@ -2138,9 +2138,9 @@ class OneShotClient:
2138
2138
  payload["first_name"] = first_name
2139
2139
  if last_name:
2140
2140
  payload["last_name"] = last_name
2141
- return self.call_tool("/v1/tools/enrich/email", payload)
2141
+ return self.call_tool("/v1/tools/lookup/person-email", payload)
2142
2142
 
2143
- async def afind_email(self, company_domain: str, *, full_name: Optional[str] = None, first_name: Optional[str] = None, last_name: Optional[str] = None, **kwargs: Any) -> Any:
2143
+ async def aperson_email(self, company_domain: str, *, full_name: Optional[str] = None, first_name: Optional[str] = None, last_name: Optional[str] = None, **kwargs: Any) -> Any:
2144
2144
  """Find a person's email address. Async."""
2145
2145
  payload: dict[str, Any] = {"company_domain": company_domain, **kwargs}
2146
2146
  if full_name:
@@ -2149,63 +2149,63 @@ class OneShotClient:
2149
2149
  payload["first_name"] = first_name
2150
2150
  if last_name:
2151
2151
  payload["last_name"] = last_name
2152
- return await self.acall_tool("/v1/tools/enrich/email", payload)
2152
+ return await self.acall_tool("/v1/tools/lookup/person-email", payload)
2153
2153
 
2154
- def verify_email(self, email: str) -> Any:
2154
+ def person_email_status(self, email: str) -> Any:
2155
2155
  """Verify email deliverability. Blocking."""
2156
- return self.call_tool("/v1/tools/verify/email", {"email": email})
2156
+ return self.call_tool("/v1/tools/lookup/person-email-status", {"email": email})
2157
2157
 
2158
- async def averify_email(self, email: str) -> Any:
2158
+ async def aperson_email_status(self, email: str) -> Any:
2159
2159
  """Verify email deliverability. Async."""
2160
- return await self.acall_tool("/v1/tools/verify/email", {"email": email})
2160
+ return await self.acall_tool("/v1/tools/lookup/person-email-status", {"email": email})
2161
2161
 
2162
- def deep_research_person(self, **kwargs: Any) -> Any:
2162
+ def person_dossier(self, **kwargs: Any) -> Any:
2163
2163
  """Deep research on a person. Blocking."""
2164
- return self.call_tool("/v1/tools/research/person", kwargs)
2164
+ return self.call_tool("/v1/tools/lookup/person-dossier", kwargs)
2165
2165
 
2166
- async def adeep_research_person(self, **kwargs: Any) -> Any:
2166
+ async def aperson_dossier(self, **kwargs: Any) -> Any:
2167
2167
  """Deep research on a person. Async."""
2168
- return await self.acall_tool("/v1/tools/research/person", kwargs)
2168
+ return await self.acall_tool("/v1/tools/lookup/person-dossier", kwargs)
2169
2169
 
2170
- def social_profiles(self, **kwargs: Any) -> Any:
2170
+ def person_social_accounts(self, **kwargs: Any) -> Any:
2171
2171
  """Discover social media profiles. Blocking."""
2172
- return self.call_tool("/v1/tools/research/social", kwargs)
2172
+ return self.call_tool("/v1/tools/lookup/person-social-accounts", kwargs)
2173
2173
 
2174
- async def asocial_profiles(self, **kwargs: Any) -> Any:
2174
+ async def aperson_social_accounts(self, **kwargs: Any) -> Any:
2175
2175
  """Discover social media profiles. Async."""
2176
- return await self.acall_tool("/v1/tools/research/social", kwargs)
2176
+ return await self.acall_tool("/v1/tools/lookup/person-social-accounts", kwargs)
2177
2177
 
2178
- def article_search(self, name: str, company: str, **kwargs: Any) -> Any:
2178
+ def person_articles(self, name: str, company: str, **kwargs: Any) -> Any:
2179
2179
  """Find articles by or about a person. Blocking."""
2180
- return self.call_tool("/v1/tools/research/articles", {"name": name, "company": company, **kwargs})
2180
+ return self.call_tool("/v1/tools/lookup/person-articles", {"name": name, "company": company, **kwargs})
2181
2181
 
2182
- async def aarticle_search(self, name: str, company: str, **kwargs: Any) -> Any:
2182
+ async def aperson_articles(self, name: str, company: str, **kwargs: Any) -> Any:
2183
2183
  """Find articles by or about a person. Async."""
2184
- return await self.acall_tool("/v1/tools/research/articles", {"name": name, "company": company, **kwargs})
2184
+ return await self.acall_tool("/v1/tools/lookup/person-articles", {"name": name, "company": company, **kwargs})
2185
2185
 
2186
- def person_newsfeed(self, social_media_url: str, **kwargs: Any) -> Any:
2186
+ def person_posts(self, social_media_url: str, **kwargs: Any) -> Any:
2187
2187
  """Get recent social posts from a person. Blocking."""
2188
- return self.call_tool("/v1/tools/research/newsfeed", {"social_media_url": social_media_url, **kwargs})
2188
+ return self.call_tool("/v1/tools/lookup/person-posts", {"social_media_url": social_media_url, **kwargs})
2189
2189
 
2190
- async def aperson_newsfeed(self, social_media_url: str, **kwargs: Any) -> Any:
2190
+ async def aperson_posts(self, social_media_url: str, **kwargs: Any) -> Any:
2191
2191
  """Get recent social posts from a person. Async."""
2192
- return await self.acall_tool("/v1/tools/research/newsfeed", {"social_media_url": social_media_url, **kwargs})
2192
+ return await self.acall_tool("/v1/tools/lookup/person-posts", {"social_media_url": social_media_url, **kwargs})
2193
2193
 
2194
2194
  def person_interests(self, **kwargs: Any) -> Any:
2195
2195
  """Analyze a person's interests from their digital footprint. Blocking."""
2196
- return self.call_tool("/v1/tools/research/interests", kwargs)
2196
+ return self.call_tool("/v1/tools/lookup/person-interests", kwargs)
2197
2197
 
2198
2198
  async def aperson_interests(self, **kwargs: Any) -> Any:
2199
2199
  """Analyze a person's interests from their digital footprint. Async."""
2200
- return await self.acall_tool("/v1/tools/research/interests", kwargs)
2200
+ return await self.acall_tool("/v1/tools/lookup/person-interests", kwargs)
2201
2201
 
2202
- def person_interactions(self, social_media_url: str, **kwargs: Any) -> Any:
2202
+ def person_followers(self, social_media_url: str, **kwargs: Any) -> Any:
2203
2203
  """Get a person's social interactions. Blocking."""
2204
- return self.call_tool("/v1/tools/research/interactions", {"social_media_url": social_media_url, **kwargs})
2204
+ return self.call_tool("/v1/tools/lookup/person-followers", {"social_media_url": social_media_url, **kwargs})
2205
2205
 
2206
- async def aperson_interactions(self, social_media_url: str, **kwargs: Any) -> Any:
2206
+ async def aperson_followers(self, social_media_url: str, **kwargs: Any) -> Any:
2207
2207
  """Get a person's social interactions. Async."""
2208
- return await self.acall_tool("/v1/tools/research/interactions", {"social_media_url": social_media_url, **kwargs})
2208
+ return await self.acall_tool("/v1/tools/lookup/person-followers", {"social_media_url": social_media_url, **kwargs})
2209
2209
 
2210
2210
  def commerce_search(self, query: str, *, limit: int = 10, **kwargs: Any) -> Any:
2211
2211
  """Search for products. Blocking."""
@@ -2515,8 +2515,8 @@ class OneShotClient:
2515
2515
  @staticmethod
2516
2516
  def _is_phones_pending(result: Any) -> bool:
2517
2517
  """Detects whether a result is awaiting Apollo's async phone-reveal
2518
- webhook. Tolerates two shapes: the unwrapped result ``{phones_pending}``
2519
- and the deep_research_person wrapper ``{result: {phones_pending}}``.
2518
+ webhook. Accepts legacy flat results and person_dossier's
2519
+ ``result.profile.data.phones_pending``.
2520
2520
 
2521
2521
  Mirrors the TS SDK's _isPhonesPending — kept in lockstep so the worker
2522
2522
  contract works for both SDKs.
@@ -2528,6 +2528,10 @@ class OneShotClient:
2528
2528
  inner = result.get("result")
2529
2529
  if isinstance(inner, dict) and inner.get("phones_pending") is True:
2530
2530
  return True
2531
+ profile = inner.get("profile") if isinstance(inner, dict) else None
2532
+ data = profile.get("data") if isinstance(profile, dict) else None
2533
+ if isinstance(data, dict) and data.get("phones_pending") is True:
2534
+ return True
2531
2535
  return False
2532
2536
 
2533
2537
  async def _poll_for_phones(