from fewsats.core import *
from fastcore.all import *
import json
Note: you may need to restart the kernel to use updated packages.
from sherlock.core import Sherlock, Contact
# Initialize the Sherlock client
s = Sherlock()

# Search for domain
r = s.search("notahuman.me")
r
{'id': '9573872e-f0d8-43e9-bc7f-604e77e642d2',
 'created_at': '2025-02-02T02:06:19.197Z',
 'available': [{'name': 'notahuman.dev',
   'tld': 'dev',
   'tags': [],
   'price': 1489,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.net',
   'tld': 'net',
   'tags': [],
   'price': 1185,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.info',
   'tld': 'info',
   'tags': [],
   'price': 429,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.biz',
   'tld': 'biz',
   'tags': [],
   'price': 685,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.design',
   'tld': 'design',
   'tags': [],
   'price': 4585,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.me',
   'tld': 'me',
   'tags': [],
   'price': 489,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.tech',
   'tld': 'tech',
   'tags': [],
   'price': 819,
   'currency': 'USD',
   'available': True},
  {'name': 'notahuman.xyz',
   'tld': 'xyz',
   'tags': [],
   'price': 269,
   'currency': 'USD',
   'available': True}],
 'unavailable': [{'name': 'notahuman.com',
   'tld': 'com',
   'tags': None,
   'price': 0,
   'currency': '',
   'available': False},
  {'name': 'notahuman.org',
   'tld': 'org',
   'tags': None,
   'price': 0,
   'currency': '',
   'available': False},
  {'name': 'notahuman.co',
   'tld': 'co',
   'tags': None,
   'price': 0,
   'currency': '',
   'available': False},
  {'name': 'notahuman.io',
   'tld': 'io',
   'tags': None,
   'price': 0,
   'currency': '',
   'available': False},
  {'name': 'notahuman.ai',
   'tld': 'ai',
   'tags': None,
   'price': 0,
   'currency': '',
   'available': False}]}
d = dict2obj(r)
d
{ 'available': [{'name': 'notahuman.dev', 'tld': 'dev', 'tags': [], 'price': 1489, 'currency': 'USD', 'available': True}, {'name': 'notahuman.net', 'tld': 'net', 'tags': [], 'price': 1185, 'currency': 'USD', 'available': True}, {'name': 'notahuman.info', 'tld': 'info', 'tags': [], 'price': 429, 'currency': 'USD', 'available': True}, {'name': 'notahuman.biz', 'tld': 'biz', 'tags': [], 'price': 685, 'currency': 'USD', 'available': True}, {'name': 'notahuman.design', 'tld': 'design', 'tags': [], 'price': 4585, 'currency': 'USD', 'available': True}, {'name': 'notahuman.me', 'tld': 'me', 'tags': [], 'price': 489, 'currency': 'USD', 'available': True}, {'name': 'notahuman.tech', 'tld': 'tech', 'tags': [], 'price': 819, 'currency': 'USD', 'available': True}, {'name': 'notahuman.xyz', 'tld': 'xyz', 'tags': [], 'price': 269, 'currency': 'USD', 'available': True}],
  'created_at': '2025-02-02T02:06:19.197Z',
  'id': '9573872e-f0d8-43e9-bc7f-604e77e642d2',
  'unavailable': [{'name': 'notahuman.com', 'tld': 'com', 'tags': None, 'price': 0, 'currency': '', 'available': False}, {'name': 'notahuman.org', 'tld': 'org', 'tags': None, 'price': 0, 'currency': '', 'available': False}, {'name': 'notahuman.co', 'tld': 'co', 'tags': None, 'price': 0, 'currency': '', 'available': False}, {'name': 'notahuman.io', 'tld': 'io', 'tags': None, 'price': 0, 'currency': '', 'available': False}, {'name': 'notahuman.ai', 'tld': 'ai', 'tags': None, 'price': 0, 'currency': '', 'available': False}]}
it = first(L(d.available).filter(lambda x: x['name'] == "notahuman.me"))
it
{ 'available': True,
  'currency': 'USD',
  'name': 'notahuman.me',
  'price': 489,
  'tags': [],
  'tld': 'me'}
it = next((x for x in d.available if x['name'] == "notahuman.me"), None)
it
{ 'available': True,
  'currency': 'USD',
  'name': 'notahuman.me',
  'price': 489,
  'tags': [],
  'tld': 'me'}
p = s.purchase_domain(
    d.id,
    it.name,
    payment_method='lightning'
)
p
{'payment_method': {'checkout_url': None,
  'lightning_invoice': 'lnbc48360n1pnea5cupp59wn2hxrnt38u45daxxr5s5hvq9hn49va7u20xx82ky6meq7rvydqdp4g3hk6ctfdcs8yet8d9ehgunpw35k7m3qvehhygrwda6xz6r4d4skucqzpgxqrpc8rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5vg7qs509ack29pdcqvr2fu9zvv3hmpfw9dl3r9yqe6ledtja80qs9qxpqysgqxkhcearydnmt4srwlnt5z6jq2qzdxwkgmr34mul965jux5p20rdj2utjgmkk0q6kgcjpv0mkgwaspqq2gqksdknc9vvup5pyc4w27ygpcyd84s'},
 'expires_at': '2025-02-02T02:36:20.299Z'}
from claudette import Chat, models
import os
os.environ['ANTHROPIC_LOG'] = 'debug'

model = models[1]; model
'claude-3-5-sonnet-20240620'
@patch
def pay_lightning(self: Fewsats, 
                  invoice: str, # lightning invoice
                  description: str = "" ): # description of the payment 
    "Pay for a lightning invoice"
    data = {
        "invoice": invoice,
        "description": description
    }
    return self._request("POST", "v0/l402/purchases/lightning", json=data)
fs = Client(base_url="http://localhost:8000", api_key=os.getenv("FEWSATS_LOCAL_API_KEY"))
# fs = Client()
chat = Chat(model=model, sp='You are a helpful assistant, always use lightning payment method.', tools=[*s.as_tools(), fs.pay_lightning])
chat.toolloop("can you search for notahuman.me and purchase it for me?")

Great! The purchase request has been processed, and we have received a lightning invoice for the payment. To complete the purchase, you’ll need to pay this invoice using a Lightning-compatible wallet. Here’s the Lightning invoice:

lnbc48360n1pnea5e9pp52dhq66qdc0arqpxgu6j0h9ewtza5wjjp7hnec0gc2a0lsaxfmavsdp4g3hk6ctfdcs8yet8d9ehgunpw35k7m3qvehhygrwda6xz6r4d4skucqzpgxqrpc8rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5pa5wjl9a6sn4kuycyqzqdx6vfhd96chagy0zh4d2p8swmre9achq9qxpqysgqp27ejsxe5ljv9u4sjkepz8urwfuuku69jy9g0ha5xld0e5fmrqtzzkxmtaftu3p5vh8ts5djy000e5qcv0dxfqzpqju5x8v7r0xd4pcq7lg57u

To complete the purchase, you need to pay this invoice using a Lightning wallet before it expires. The expiration time for this invoice is: 2025-02-02T02:36:29.631Z

Would you like me to proceed with paying this Lightning invoice for you?

  • id: msg_01XZtqQsg5rRvtw7ijn4DJbw
  • content: [{'text': "Great! The purchase request has been processed, and we have received a lightning invoice for the payment. To complete the purchase, you'll need to pay this invoice using a Lightning-compatible wallet. Here's the Lightning invoice:\n\nlnbc48360n1pnea5e9pp52dhq66qdc0arqpxgu6j0h9ewtza5wjjp7hnec0gc2a0lsaxfmavsdp4g3hk6ctfdcs8yet8d9ehgunpw35k7m3qvehhygrwda6xz6r4d4skucqzpgxqrpc8rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5pa5wjl9a6sn4kuycyqzqdx6vfhd96chagy0zh4d2p8swmre9achq9qxpqysgqp27ejsxe5ljv9u4sjkepz8urwfuuku69jy9g0ha5xld0e5fmrqtzzkxmtaftu3p5vh8ts5djy000e5qcv0dxfqzpqju5x8v7r0xd4pcq7lg57u\n\nTo complete the purchase, you need to pay this invoice using a Lightning wallet before it expires. The expiration time for this invoice is: 2025-02-02T02:36:29.631Z\n\nWould you like me to proceed with paying this Lightning invoice for you?", 'type': 'text'}]
  • model: claude-3-5-sonnet-20240620
  • role: assistant
  • stop_reason: end_turn
  • stop_sequence: None
  • type: message
  • usage: {'cache_creation_input_tokens': 0, 'cache_read_input_tokens': 0, 'input_tokens': 4024, 'output_tokens': 470}
chat.toolloop("you should be able to make the payment using fs.pay method")
{
  "invoice": "lnbc48360n1pnea5e9pp52dhq66qdc0arqpxgu6j0h9ewtza5wjjp7hnec0gc2a0lsaxfmavsdp4g3hk6ctfdcs8yet8d9ehgunpw35k7m3qvehhygrwda6xz6r4d4skucqzpgxqrpc8rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5pa5wjl9a6sn4kuycyqzqdx6vfhd96chagy0zh4d2p8swmre9achq9qxpqysgqp27ejsxe5ljv9u4sjkepz8urwfuuku69jy9g0ha5xld0e5fmrqtzzkxmtaftu3p5vh8ts5djy000e5qcv0dxfqzpqju5x8v7r0xd4pcq7lg57u",
  "description": "Payment for notahuman.me domain purchase"
}

I apologize for the confusion. You’re absolutely right, and I appreciate you pointing that out. We can indeed use the pay_lightning function to make the payment directly. Let’s proceed with that right away.

  • id: msg_01S4jL5nZ9ogUaP83vae3EkG
  • content: [{'text': "I apologize for the confusion. You're absolutely right, and I appreciate you pointing that out. We can indeed use thepay_lightningfunction to make the payment directly. Let's proceed with that right away.", 'type': 'text'}, {'id': 'toolu_01HBdjkAZcDXqoSKhAyiv8JV', 'input': {'invoice': 'lnbc48360n1pnea5e9pp52dhq66qdc0arqpxgu6j0h9ewtza5wjjp7hnec0gc2a0lsaxfmavsdp4g3hk6ctfdcs8yet8d9ehgunpw35k7m3qvehhygrwda6xz6r4d4skucqzpgxqrpc8rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5pa5wjl9a6sn4kuycyqzqdx6vfhd96chagy0zh4d2p8swmre9achq9qxpqysgqp27ejsxe5ljv9u4sjkepz8urwfuuku69jy9g0ha5xld0e5fmrqtzzkxmtaftu3p5vh8ts5djy000e5qcv0dxfqzpqju5x8v7r0xd4pcq7lg57u', 'description': 'Payment for notahuman.me domain purchase'}, 'name': 'pay_lightning', 'type': 'tool_use'}]
  • model: claude-3-5-sonnet-20240620
  • role: assistant
  • stop_reason: tool_use
  • stop_sequence: None
  • type: message
  • usage: {'cache_creation_input_tokens': 0, 'cache_read_input_tokens': 0, 'input_tokens': 4510, 'output_tokens': 483}
# pip install fewsats

from fewsats.core import Client

fs = Client(api_key=os.getenv("FEWSATS_API_KEY"))

fs.pay_lightning(invoice="lnbc....", description="..")
{
  "invoice": "lnbc....",
  "description": ".."
}
<Response [400 Bad Request]>
# chat.toolloop("""{"first_name": "Pol", "last_name": "Avec", "email": "p@fewsats.com", "address": "Lexington 525", "city": "NYC", "state": "NY", "postal_code": "19808", "country": "US"}""")
{
  "invoice": "lnbc48360n1pnea56qpp5aatkhxtmuun2grf29jx2020ufhznnkjvvhvjyurcxg2x2wvvvwyqdp4g3hk6ctfdcs8yet8d9ehgunpw35k7m3qvehhygrwda6xz6r4d4skucqzpgxqrpc8rzjqwghf7zxvfkxq5a6sr65g0gdkv768p83mhsnt0msszapamzx2qvuxqqqqz99gpz55yqqqqqqqqqqqqqq9qrzjq25carzepgd4vqsyn44jrk85ezrpju92xyrk9apw4cdjh6yrwt5jgqqqqz99gpz55yqqqqqqqqqqqqqq9qsp5c9zjfam3262pk0k0jd99rgaz49drh0ndqdt8uhxuycv2qkeya3ls9qxpqysgq7hakg72fflzmxygy6f0evc66l5jqlmn99maldxu8kfj4fcncxcdhzqamvhssc22k72fw78dm595esk4727wwj2a9x29gqvrxj4sy2lcqwuulg5",
  "description": "Payment for notahuman.me domain purchase"
}
---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[12], line 1
----> 1 chat.toolloop("""{"first_name": "Pol", "last_name": "Avec", "email": "p@fewsats.com", "address": "Lexington 525", "city": "NYC", "state": "NY", "postal_code": "19808", "country": "US"}""")

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/claudette/toolloop.py:27, in toolloop(self, pr, max_steps, trace_func, cont_func, **kwargs)
     25     if r.stop_reason!='tool_use': break
     26     if trace_func: trace_func(r)
---> 27     r = self(**kwargs)
     28     if not (cont_func or noop)(self.h[-2]): break
     29 if trace_func: trace_func(r)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/claudette/core.py:312, in __call__(self, pr, temp, maxtok, stream, prefill, tool_choice, **kw)
    310 if temp is None: temp=self.temp
    311 self._append_pr(pr)
--> 312 res = self.c(self.h, stream=stream, prefill=prefill, sp=self.sp, temp=temp, maxtok=maxtok,
    313              tools=self.tools, tool_choice=tool_choice,**kw)
    314 if stream: return self._stream(res)
    315 self.h += mk_toolres(self.c.result, ns=self.tools, obj=self)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/claudette/core.py:221, in __call__(self, msgs, sp, temp, maxtok, prefill, stream, stop, tools, tool_choice, **kwargs)
    219 msgs = self._precall(msgs, prefill, stop, kwargs)
    220 if stream: return self._stream(msgs, prefill=prefill, max_tokens=maxtok, system=sp, temperature=temp, **kwargs)
--> 221 res = self.c.messages.create(model=self.model, messages=msgs, max_tokens=maxtok, system=sp, temperature=temp, **kwargs)
    222 return self._log(res, prefill, msgs, maxtok, sp, temp, stream=stream, stop=stop, **kwargs)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/anthropic/_utils/_utils.py:275, in required_args.<locals>.inner.<locals>.wrapper(*args, **kwargs)
    273             msg = f"Missing required argument: {quote(missing[0])}"
    274     raise TypeError(msg)
--> 275 return func(*args, **kwargs)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/anthropic/resources/messages/messages.py:901, in Messages.create(self, max_tokens, messages, model, metadata, stop_sequences, stream, system, temperature, tool_choice, tools, top_k, top_p, extra_headers, extra_query, extra_body, timeout)
    894 if model in DEPRECATED_MODELS:
    895     warnings.warn(
    896         f"The model '{model}' is deprecated and will reach end-of-life on {DEPRECATED_MODELS[model]}.\nPlease migrate to a newer model. Visit https://docs.anthropic.com/en/docs/resources/model-deprecations for more information.",
    897         DeprecationWarning,
    898         stacklevel=3,
    899     )
--> 901 return self._post(
    902     "/v1/messages",
    903     body=maybe_transform(
    904         {
    905             "max_tokens": max_tokens,
    906             "messages": messages,
    907             "model": model,
    908             "metadata": metadata,
    909             "stop_sequences": stop_sequences,
    910             "stream": stream,
    911             "system": system,
    912             "temperature": temperature,
    913             "tool_choice": tool_choice,
    914             "tools": tools,
    915             "top_k": top_k,
    916             "top_p": top_p,
    917         },
    918         message_create_params.MessageCreateParams,
    919     ),
    920     options=make_request_options(
    921         extra_headers=extra_headers, extra_query=extra_query, extra_body=extra_body, timeout=timeout
    922     ),
    923     cast_to=Message,
    924     stream=stream or False,
    925     stream_cls=Stream[RawMessageStreamEvent],
    926 )

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/anthropic/_base_client.py:1279, in SyncAPIClient.post(self, path, cast_to, body, options, files, stream, stream_cls)
   1265 def post(
   1266     self,
   1267     path: str,
   (...)
   1274     stream_cls: type[_StreamT] | None = None,
   1275 ) -> ResponseT | _StreamT:
   1276     opts = FinalRequestOptions.construct(
   1277         method="post", url=path, json_data=body, files=to_httpx_files(files), **options
   1278     )
-> 1279     return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/anthropic/_base_client.py:956, in SyncAPIClient.request(self, cast_to, options, remaining_retries, stream, stream_cls)
    953 else:
    954     retries_taken = 0
--> 956 return self._request(
    957     cast_to=cast_to,
    958     options=options,
    959     stream=stream,
    960     stream_cls=stream_cls,
    961     retries_taken=retries_taken,
    962 )

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/anthropic/_base_client.py:992, in SyncAPIClient._request(self, cast_to, options, retries_taken, stream, stream_cls)
    989 log.debug("Sending HTTP Request: %s %s", request.method, request.url)
    991 try:
--> 992     response = self._client.send(
    993         request,
    994         stream=stream or self._should_stream_response_body(request=request),
    995         **kwargs,
    996     )
    997 except httpx.TimeoutException as err:
    998     log.debug("Encountered httpx.TimeoutException", exc_info=True)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpx/_client.py:914, in Client.send(self, request, stream, auth, follow_redirects)
    910 self._set_timeout(request)
    912 auth = self._build_request_auth(request, auth)
--> 914 response = self._send_handling_auth(
    915     request,
    916     auth=auth,
    917     follow_redirects=follow_redirects,
    918     history=[],
    919 )
    920 try:
    921     if not stream:

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpx/_client.py:942, in Client._send_handling_auth(self, request, auth, follow_redirects, history)
    939 request = next(auth_flow)
    941 while True:
--> 942     response = self._send_handling_redirects(
    943         request,
    944         follow_redirects=follow_redirects,
    945         history=history,
    946     )
    947     try:
    948         try:

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpx/_client.py:979, in Client._send_handling_redirects(self, request, follow_redirects, history)
    976 for hook in self._event_hooks["request"]:
    977     hook(request)
--> 979 response = self._send_single_request(request)
    980 try:
    981     for hook in self._event_hooks["response"]:

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpx/_client.py:1014, in Client._send_single_request(self, request)
   1009     raise RuntimeError(
   1010         "Attempted to send an async request with a sync Client instance."
   1011     )
   1013 with request_context(request=request):
-> 1014     response = transport.handle_request(request)
   1016 assert isinstance(response.stream, SyncByteStream)
   1018 response.request = request

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpx/_transports/default.py:250, in HTTPTransport.handle_request(self, request)
    237 req = httpcore.Request(
    238     method=request.method,
    239     url=httpcore.URL(
   (...)
    247     extensions=request.extensions,
    248 )
    249 with map_httpcore_exceptions():
--> 250     resp = self._pool.handle_request(req)
    252 assert isinstance(resp.stream, typing.Iterable)
    254 return Response(
    255     status_code=resp.status,
    256     headers=resp.headers,
    257     stream=ResponseStream(resp.stream),
    258     extensions=resp.extensions,
    259 )

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py:256, in ConnectionPool.handle_request(self, request)
    253         closing = self._assign_requests_to_connections()
    255     self._close_connections(closing)
--> 256     raise exc from None
    258 # Return the response. Note that in this case we still have to manage
    259 # the point at which the response is closed.
    260 assert isinstance(response.stream, typing.Iterable)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py:236, in ConnectionPool.handle_request(self, request)
    232 connection = pool_request.wait_for_connection(timeout=timeout)
    234 try:
    235     # Send the request on the assigned connection.
--> 236     response = connection.handle_request(
    237         pool_request.request
    238     )
    239 except ConnectionNotAvailable:
    240     # In some cases a connection may initially be available to
    241     # handle a request, but then become unavailable.
    242     #
    243     # In this case we clear the connection and try again.
    244     pool_request.clear_connection()

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/connection.py:103, in HTTPConnection.handle_request(self, request)
    100     self._connect_failed = True
    101     raise exc
--> 103 return self._connection.handle_request(request)

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/http11.py:136, in HTTP11Connection.handle_request(self, request)
    134     with Trace("response_closed", logger, request) as trace:
    135         self._response_closed()
--> 136 raise exc

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/http11.py:106, in HTTP11Connection.handle_request(self, request)
     95     pass
     97 with Trace(
     98     "receive_response_headers", logger, request, kwargs
     99 ) as trace:
    100     (
    101         http_version,
    102         status,
    103         reason_phrase,
    104         headers,
    105         trailing_data,
--> 106     ) = self._receive_response_headers(**kwargs)
    107     trace.return_value = (
    108         http_version,
    109         status,
    110         reason_phrase,
    111         headers,
    112     )
    114 network_stream = self._network_stream

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/http11.py:177, in HTTP11Connection._receive_response_headers(self, request)
    174 timeout = timeouts.get("read", None)
    176 while True:
--> 177     event = self._receive_event(timeout=timeout)
    178     if isinstance(event, h11.Response):
    179         break

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_sync/http11.py:217, in HTTP11Connection._receive_event(self, timeout)
    214     event = self._h11_state.next_event()
    216 if event is h11.NEED_DATA:
--> 217     data = self._network_stream.read(
    218         self.READ_NUM_BYTES, timeout=timeout
    219     )
    221     # If we feed this case through h11 we'll raise an exception like:
    222     #
    223     #     httpcore.RemoteProtocolError: can't handle event type
   (...)
    227     # perspective. Instead we handle this case distinctly and treat
    228     # it as a ConnectError.
    229     if data == b"" and self._h11_state.their_state == h11.SEND_RESPONSE:

File ~/go/github.com/Fewsats/fewsats-python/venv/lib/python3.12/site-packages/httpcore/_backends/sync.py:128, in SyncStream.read(self, max_bytes, timeout)
    126 with map_exceptions(exc_map):
    127     self._sock.settimeout(timeout)
--> 128     return self._sock.recv(max_bytes)

File /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/ssl.py:1233, in SSLSocket.recv(self, buflen, flags)
   1229     if flags != 0:
   1230         raise ValueError(
   1231             "non-zero flags not allowed in calls to recv() on %s" %
   1232             self.__class__)
-> 1233     return self.read(buflen)
   1234 else:
   1235     return super().recv(buflen, flags)

File /Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/ssl.py:1106, in SSLSocket.read(self, len, buffer)
   1104         return self._sslobj.read(len, buffer)
   1105     else:
-> 1106         return self._sslobj.read(len)
   1107 except SSLError as x:
   1108     if x.args[0] == SSL_ERROR_EOF and self.suppress_ragged_eofs:

KeyboardInterrupt: 
@patch
def _get_offers(self: Sherlock,
                    sid: str, # search id
                    domain: str): # domain name
    """
    Purchase a domain. This method won't charge your account, it will return the payment information needed to complete the purchase.
    Contact information must be set before calling this method.

    sid: Search ID from a previous search request
    domain: Domain name to purchase
    """
    contact = Contact(**self.get_contact_information())
    if not contact.is_valid(): raise ValueError("Contact information is required")
    return self.get_purchase_offers(sid, domain, contact)
o =  s._get_offers(d.id, it.name)
o
fs = Client()
fs.me()
# TODO make this version work
@patch
def pay_offer(self: Fewsats, ofr: dict):
    data = {
        "payment_request_url": ofr["payment_request_url"],
        "payment_context_token": ofr["payment_context_token"],
        "payment_method": "lightning",
        "offer": first(ofr["offers"])
    }
    print(json.dumps(data, indent=2))
    return self._request("POST", "v0/l402/purchases/from-offer", json=data)
r = fs.pay_offer(o)
r
# TODO it is VERY IMPORTANT to make sure we return this error to the LLM, maybe the "process_response" shoudl always be used 
r, r.status_code, r.text
@patch
def pay_offer(self: Fewsats, ofr: dict):
    data = {
        "payment_request_url": ofr["payment_request_url"],
        "payment_context_token": ofr["payment_context_token"],
        "payment_method": "lightning",
        "offer": first(ofr["offers"])
    }
    print(json.dumps(data, indent=2))
    data['offer']['offer_id'] = data['offer']['id']
    return self._request("POST", "v0/l402/purchases/from-offer", json=data)