exa-py 1.8.3__tar.gz → 1.8.5__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.

Potentially problematic release.


This version of exa-py might be problematic. Click here for more details.

@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: exa-py
3
- Version: 1.8.3
3
+ Version: 1.8.5
4
4
  Summary: Python SDK for Exa API.
5
5
  Author: Exa AI
6
6
  Author-email: hello@exa.ai
@@ -58,11 +58,13 @@ def to_camel_case(data: dict) -> dict:
58
58
  Returns:
59
59
  dict: The dictionary with keys converted to camelCase format.
60
60
  """
61
- return {
62
- snake_to_camel(k): to_camel_case(v) if isinstance(v, dict) else v
63
- for k, v in data.items()
64
- if v is not None
65
- }
61
+ if isinstance(data, dict):
62
+ return {
63
+ snake_to_camel(k): to_camel_case(v) if isinstance(v, dict) else v
64
+ for k, v in data.items()
65
+ if v is not None
66
+ }
67
+ return data
66
68
 
67
69
 
68
70
  def camel_to_snake(camel_str: str) -> str:
@@ -88,10 +90,12 @@ def to_snake_case(data: dict) -> dict:
88
90
  Returns:
89
91
  dict: The dictionary with keys converted to snake_case format.
90
92
  """
91
- return {
92
- camel_to_snake(k): to_snake_case(v) if isinstance(v, dict) else v
93
- for k, v in data.items()
94
- }
93
+ if isinstance(data, dict):
94
+ return {
95
+ camel_to_snake(k): to_snake_case(v) if isinstance(v, dict) else v
96
+ for k, v in data.items()
97
+ }
98
+ return data
95
99
 
96
100
 
97
101
  SEARCH_OPTIONS_TYPES = {
@@ -106,9 +110,10 @@ SEARCH_OPTIONS_TYPES = {
106
110
  "include_text": [list], # Must be present in webpage text. (One string, up to 5 words)
107
111
  "exclude_text": [list], # Must not be present in webpage text. (One string, up to 5 words)
108
112
  "use_autoprompt": [bool], # Convert query to Exa. (Default: false)
109
- "type": [str], # 'keyword', 'neural', or 'auto' (Default: auto).'neural' uses embeddings search, 'keyword' is SERP and 'auto' decides the best search type based on your query
113
+ "type": [str], # 'keyword', 'neural', or 'auto' (Default: auto)
110
114
  "category": [str], # A data category to focus on: 'company', 'research paper', 'news', 'pdf', 'github', 'tweet', 'personal site', 'linkedin profile', 'financial report'
111
- "flags": [list], # Experimental flags array for Exa usage.
115
+ "flags": [list], # Experimental flags array for Exa usage.
116
+ "moderation": [bool], # If true, moderate search results for safety.
112
117
  }
113
118
 
114
119
  FIND_SIMILAR_OPTIONS_TYPES = {
@@ -124,7 +129,7 @@ FIND_SIMILAR_OPTIONS_TYPES = {
124
129
  "exclude_text": [list],
125
130
  "exclude_source_domain": [bool],
126
131
  "category": [str],
127
- "flags": [list], # Experimental flags array for Exa usage.
132
+ "flags": [list], # Experimental flags array for Exa usage.
128
133
  }
129
134
 
130
135
  # the livecrawl options
@@ -198,7 +203,7 @@ class HighlightsContentsOptions(TypedDict, total=False):
198
203
  """A class representing the options that you can specify when requesting highlights
199
204
 
200
205
  Attributes:
201
- query (str): The query string for the highlights.
206
+ query (str): The query string for the highlights.
202
207
  num_sentences (int): Size of highlights to return, in sentences. Default: 5
203
208
  highlights_per_url (int): Number of highlights to return per URL. Default: 1
204
209
  """
@@ -217,6 +222,7 @@ class SummaryContentsOptions(TypedDict, total=False):
217
222
 
218
223
  query: str
219
224
 
225
+
220
226
  class ExtrasOptions(TypedDict, total=False):
221
227
  """A class representing additional extraction fields (e.g. links, images)"""
222
228
 
@@ -495,6 +501,7 @@ class ResultWithTextAndHighlightsAndSummary(_Result):
495
501
  f"Summary: {self.summary}\n"
496
502
  )
497
503
 
504
+
498
505
  @dataclass
499
506
  class AnswerResult:
500
507
  """A class representing a source result for an answer.
@@ -510,15 +517,17 @@ class AnswerResult:
510
517
  url: str
511
518
  id: str
512
519
  title: Optional[str] = None
513
- published_date: Optional[str] = None
514
520
  author: Optional[str] = None
521
+ published_date: Optional[str] = None
522
+ text: Optional[str] = None
515
523
 
516
524
  def __init__(self, **kwargs):
517
525
  self.url = kwargs['url']
518
526
  self.id = kwargs['id']
519
527
  self.title = kwargs.get('title')
528
+ self.author = kwargs.get('author')
520
529
  self.published_date = kwargs.get('published_date')
521
- self.author = kwargs.get('author')
530
+ self.text = kwargs.get('text')
522
531
 
523
532
  def __str__(self):
524
533
  return (
@@ -527,8 +536,10 @@ class AnswerResult:
527
536
  f"ID: {self.id}\n"
528
537
  f"Published Date: {self.published_date}\n"
529
538
  f"Author: {self.author}\n"
539
+ f"Text: {self.text}\n"
530
540
  )
531
541
 
542
+
532
543
  @dataclass
533
544
  class AnswerResponse:
534
545
  """A class representing the response for an answer operation.
@@ -546,6 +557,7 @@ class AnswerResponse:
546
557
  output += "\n\n".join(str(source) for source in self.sources)
547
558
  return output
548
559
 
560
+
549
561
  T = TypeVar("T")
550
562
 
551
563
 
@@ -599,7 +611,7 @@ class Exa:
599
611
  self,
600
612
  api_key: Optional[str],
601
613
  base_url: str = "https://api.exa.ai",
602
- user_agent: str = "exa-py 1.8.3",
614
+ user_agent: str = "exa-py 1.8.5",
603
615
  ):
604
616
  """Initialize the Exa client with the provided API key and optional base URL and user agent.
605
617
 
@@ -619,12 +631,25 @@ class Exa:
619
631
  self.headers = {"x-api-key": api_key, "User-Agent": user_agent}
620
632
 
621
633
  def request(self, endpoint: str, data):
634
+ """Send a POST request to the Exa API, optionally streaming if data['stream'] is True.
635
+
636
+ Args:
637
+ endpoint (str): The API endpoint (path).
638
+ data (dict): The JSON payload to send.
639
+
640
+ Returns:
641
+ Union[dict, Iterator[str]]: If streaming, returns an iterator of strings (line-by-line).
642
+ Otherwise, returns the JSON-decoded response as a dict.
643
+
644
+ Raises:
645
+ ValueError: If the request fails (non-200 status code).
646
+ """
622
647
  if data.get("stream"):
623
648
  res = requests.post(self.base_url + endpoint, json=data, headers=self.headers, stream=True)
624
649
  if res.status_code != 200:
625
650
  raise ValueError(f"Request failed with status code {res.status_code}: {res.text}")
626
- return (line.decode('utf-8') for line in res.iter_lines() if line)
627
-
651
+ return (line.decode("utf-8") for line in res.iter_lines() if line)
652
+
628
653
  res = requests.post(self.base_url + endpoint, json=data, headers=self.headers)
629
654
  if res.status_code != 200:
630
655
  raise ValueError(f"Request failed with status code {res.status_code}: {res.text}")
@@ -647,6 +672,7 @@ class Exa:
647
672
  type: Optional[str] = None,
648
673
  category: Optional[str] = None,
649
674
  flags: Optional[List[str]] = None,
675
+ moderation: Optional[bool] = None,
650
676
  ) -> SearchResponse[_Result]:
651
677
  """Perform a search with a prompt-engineered query to retrieve relevant results.
652
678
 
@@ -665,6 +691,7 @@ class Exa:
665
691
  type (str, optional): 'keyword' or 'neural' (default 'neural').
666
692
  category (str, optional): e.g. 'company'
667
693
  flags (List[str], optional): Experimental flags for Exa usage.
694
+ moderation (bool, optional): If True, the search results will be moderated for safety.
668
695
 
669
696
  Returns:
670
697
  SearchResponse: The response containing search results, etc.
@@ -697,12 +724,13 @@ class Exa:
697
724
  use_autoprompt: Optional[bool] = None,
698
725
  type: Optional[str] = None,
699
726
  category: Optional[str] = None,
727
+ flags: Optional[List[str]] = None,
728
+ moderation: Optional[bool] = None,
700
729
  livecrawl_timeout: Optional[int] = None,
701
730
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
702
731
  filter_empty_results: Optional[bool] = None,
703
732
  subpages: Optional[int] = None,
704
733
  extras: Optional[ExtrasOptions] = None,
705
- flags: Optional[List[str]] = None,
706
734
  ) -> SearchResponse[ResultWithText]:
707
735
  ...
708
736
 
@@ -724,12 +752,13 @@ class Exa:
724
752
  use_autoprompt: Optional[bool] = None,
725
753
  type: Optional[str] = None,
726
754
  category: Optional[str] = None,
755
+ flags: Optional[List[str]] = None,
756
+ moderation: Optional[bool] = None,
727
757
  subpages: Optional[int] = None,
728
758
  livecrawl_timeout: Optional[int] = None,
729
759
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
730
760
  filter_empty_results: Optional[bool] = None,
731
761
  extras: Optional[ExtrasOptions] = None,
732
- flags: Optional[List[str]] = None,
733
762
  ) -> SearchResponse[ResultWithText]:
734
763
  ...
735
764
 
@@ -753,11 +782,12 @@ class Exa:
753
782
  category: Optional[str] = None,
754
783
  subpages: Optional[int] = None,
755
784
  subpage_target: Optional[Union[str, List[str]]] = None,
785
+ flags: Optional[List[str]] = None,
786
+ moderation: Optional[bool] = None,
756
787
  livecrawl_timeout: Optional[int] = None,
757
788
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
758
789
  filter_empty_results: Optional[bool] = None,
759
790
  extras: Optional[ExtrasOptions] = None,
760
- flags: Optional[List[str]] = None,
761
791
  ) -> SearchResponse[ResultWithHighlights]:
762
792
  ...
763
793
 
@@ -780,13 +810,14 @@ class Exa:
780
810
  use_autoprompt: Optional[bool] = None,
781
811
  type: Optional[str] = None,
782
812
  category: Optional[str] = None,
783
- livecrawl_timeout: Optional[int] = None,
784
- livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
785
813
  subpages: Optional[int] = None,
786
814
  subpage_target: Optional[Union[str, List[str]]] = None,
815
+ flags: Optional[List[str]] = None,
816
+ moderation: Optional[bool] = None,
817
+ livecrawl_timeout: Optional[int] = None,
818
+ livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
787
819
  filter_empty_results: Optional[bool] = None,
788
820
  extras: Optional[ExtrasOptions] = None,
789
- flags: Optional[List[str]] = None,
790
821
  ) -> SearchResponse[ResultWithTextAndHighlights]:
791
822
  ...
792
823
 
@@ -810,11 +841,12 @@ class Exa:
810
841
  category: Optional[str] = None,
811
842
  subpages: Optional[int] = None,
812
843
  subpage_target: Optional[Union[str, List[str]]] = None,
844
+ flags: Optional[List[str]] = None,
845
+ moderation: Optional[bool] = None,
813
846
  livecrawl_timeout: Optional[int] = None,
814
847
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
815
848
  filter_empty_results: Optional[bool] = None,
816
849
  extras: Optional[ExtrasOptions] = None,
817
- flags: Optional[List[str]] = None,
818
850
  ) -> SearchResponse[ResultWithSummary]:
819
851
  ...
820
852
 
@@ -839,11 +871,12 @@ class Exa:
839
871
  category: Optional[str] = None,
840
872
  subpages: Optional[int] = None,
841
873
  subpage_target: Optional[Union[str, List[str]]] = None,
874
+ flags: Optional[List[str]] = None,
875
+ moderation: Optional[bool] = None,
842
876
  livecrawl_timeout: Optional[int] = None,
843
877
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
844
878
  filter_empty_results: Optional[bool] = None,
845
879
  extras: Optional[ExtrasOptions] = None,
846
- flags: Optional[List[str]] = None,
847
880
  ) -> SearchResponse[ResultWithTextAndSummary]:
848
881
  ...
849
882
 
@@ -868,11 +901,12 @@ class Exa:
868
901
  category: Optional[str] = None,
869
902
  subpages: Optional[int] = None,
870
903
  subpage_target: Optional[Union[str, List[str]]] = None,
904
+ flags: Optional[List[str]] = None,
905
+ moderation: Optional[bool] = None,
871
906
  livecrawl_timeout: Optional[int] = None,
872
907
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
873
908
  filter_empty_results: Optional[bool] = None,
874
909
  extras: Optional[ExtrasOptions] = None,
875
- flags: Optional[List[str]] = None,
876
910
  ) -> SearchResponse[ResultWithHighlightsAndSummary]:
877
911
  ...
878
912
 
@@ -896,13 +930,14 @@ class Exa:
896
930
  use_autoprompt: Optional[bool] = None,
897
931
  type: Optional[str] = None,
898
932
  category: Optional[str] = None,
933
+ flags: Optional[List[str]] = None,
934
+ moderation: Optional[bool] = None,
899
935
  livecrawl_timeout: Optional[int] = None,
900
936
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
901
937
  subpages: Optional[int] = None,
902
938
  subpage_target: Optional[Union[str, List[str]]] = None,
903
939
  filter_empty_results: Optional[bool] = None,
904
940
  extras: Optional[ExtrasOptions] = None,
905
- flags: Optional[List[str]] = None,
906
941
  ) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]:
907
942
  ...
908
943
 
@@ -919,7 +954,11 @@ class Exa:
919
954
 
920
955
  validate_search_options(
921
956
  options,
922
- {**SEARCH_OPTIONS_TYPES, **CONTENTS_OPTIONS_TYPES, **CONTENTS_ENDPOINT_OPTIONS_TYPES},
957
+ {
958
+ **SEARCH_OPTIONS_TYPES,
959
+ **CONTENTS_OPTIONS_TYPES,
960
+ **CONTENTS_ENDPOINT_OPTIONS_TYPES,
961
+ },
923
962
  )
924
963
 
925
964
  # Nest the appropriate fields under "contents"
@@ -1076,13 +1115,19 @@ class Exa:
1076
1115
  flags: Optional[List[str]] = None,
1077
1116
  ) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]:
1078
1117
  ...
1118
+
1079
1119
  def get_contents(self, urls: Union[str, List[str], List[_Result]], **kwargs):
1080
1120
  options = {
1081
1121
  k: v
1082
1122
  for k, v in {"urls": urls, **kwargs}.items()
1083
1123
  if k != "self" and v is not None
1084
1124
  }
1085
- if "text" not in options and "highlights" not in options and "summary" not in options and "extras" not in options:
1125
+ if (
1126
+ "text" not in options
1127
+ and "highlights" not in options
1128
+ and "summary" not in options
1129
+ and "extras" not in options
1130
+ ):
1086
1131
  options["text"] = True
1087
1132
 
1088
1133
  validate_search_options(
@@ -1093,9 +1138,9 @@ class Exa:
1093
1138
  data = self.request("/contents", options)
1094
1139
  return SearchResponse(
1095
1140
  [Result(**to_snake_case(result)) for result in data["results"]],
1096
- data["autopromptString"] if "autopromptString" in data else None,
1097
- data["resolvedSearchType"] if "resolvedSearchType" in data else None,
1098
- data["autoDate"] if "autoDate" in data else None,
1141
+ data.get("autopromptString"),
1142
+ data.get("resolvedSearchType"),
1143
+ data.get("autoDate"),
1099
1144
  )
1100
1145
 
1101
1146
  def find_similar(
@@ -1115,15 +1160,35 @@ class Exa:
1115
1160
  category: Optional[str] = None,
1116
1161
  flags: Optional[List[str]] = None,
1117
1162
  ) -> SearchResponse[_Result]:
1163
+ """Finds similar pages to a given URL, potentially with domain filters and date filters.
1164
+
1165
+ Args:
1166
+ url (str): The URL to find similar pages for.
1167
+ num_results (int, optional): Number of results to return. Default is None (server default).
1168
+ include_domains (List[str], optional): Domains to include in the search.
1169
+ exclude_domains (List[str], optional): Domains to exclude from the search.
1170
+ start_crawl_date (str, optional): Only links crawled after this date.
1171
+ end_crawl_date (str, optional): Only links crawled before this date.
1172
+ start_published_date (str, optional): Only links published after this date.
1173
+ end_published_date (str, optional): Only links published before this date.
1174
+ include_text (List[str], optional): Strings that must appear in the page text.
1175
+ exclude_text (List[str], optional): Strings that must not appear in the page text.
1176
+ exclude_source_domain (bool, optional): Whether to exclude the source domain.
1177
+ category (str, optional): A data category to focus on.
1178
+ flags (List[str], optional): Experimental flags.
1179
+
1180
+ Returns:
1181
+ SearchResponse[_Result]
1182
+ """
1118
1183
  options = {k: v for k, v in locals().items() if k != "self" and v is not None}
1119
1184
  validate_search_options(options, FIND_SIMILAR_OPTIONS_TYPES)
1120
1185
  options = to_camel_case(options)
1121
1186
  data = self.request("/findSimilar", options)
1122
1187
  return SearchResponse(
1123
1188
  [Result(**to_snake_case(result)) for result in data["results"]],
1124
- data["autopromptString"] if "autopromptString" in data else None,
1125
- data["resolvedSearchType"] if "resolvedSearchType" in data else None,
1126
- data["autoDate"] if "autoDate" in data else None,
1189
+ data.get("autopromptString"),
1190
+ data.get("resolvedSearchType"),
1191
+ data.get("autoDate"),
1127
1192
  )
1128
1193
 
1129
1194
  @overload
@@ -1142,13 +1207,13 @@ class Exa:
1142
1207
  exclude_text: Optional[List[str]] = None,
1143
1208
  exclude_source_domain: Optional[bool] = None,
1144
1209
  category: Optional[str] = None,
1210
+ flags: Optional[List[str]] = None,
1145
1211
  livecrawl_timeout: Optional[int] = None,
1146
1212
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1213
+ filter_empty_results: Optional[bool] = None,
1147
1214
  subpages: Optional[int] = None,
1148
1215
  subpage_target: Optional[Union[str, List[str]]] = None,
1149
- filter_empty_results: Optional[bool] = None,
1150
1216
  extras: Optional[ExtrasOptions] = None,
1151
- flags: Optional[List[str]] = None,
1152
1217
  ) -> SearchResponse[ResultWithText]:
1153
1218
  ...
1154
1219
 
@@ -1169,13 +1234,13 @@ class Exa:
1169
1234
  exclude_text: Optional[List[str]] = None,
1170
1235
  exclude_source_domain: Optional[bool] = None,
1171
1236
  category: Optional[str] = None,
1237
+ flags: Optional[List[str]] = None,
1172
1238
  livecrawl_timeout: Optional[int] = None,
1173
1239
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1240
+ filter_empty_results: Optional[bool] = None,
1174
1241
  subpages: Optional[int] = None,
1175
1242
  subpage_target: Optional[Union[str, List[str]]] = None,
1176
- filter_empty_results: Optional[bool] = None,
1177
1243
  extras: Optional[ExtrasOptions] = None,
1178
- flags: Optional[List[str]] = None,
1179
1244
  ) -> SearchResponse[ResultWithText]:
1180
1245
  ...
1181
1246
 
@@ -1196,13 +1261,13 @@ class Exa:
1196
1261
  exclude_text: Optional[List[str]] = None,
1197
1262
  exclude_source_domain: Optional[bool] = None,
1198
1263
  category: Optional[str] = None,
1264
+ flags: Optional[List[str]] = None,
1199
1265
  subpages: Optional[int] = None,
1200
1266
  subpage_target: Optional[Union[str, List[str]]] = None,
1201
1267
  livecrawl_timeout: Optional[int] = None,
1202
1268
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1203
1269
  filter_empty_results: Optional[bool] = None,
1204
1270
  extras: Optional[ExtrasOptions] = None,
1205
- flags: Optional[List[str]] = None,
1206
1271
  ) -> SearchResponse[ResultWithHighlights]:
1207
1272
  ...
1208
1273
 
@@ -1224,13 +1289,13 @@ class Exa:
1224
1289
  exclude_text: Optional[List[str]] = None,
1225
1290
  exclude_source_domain: Optional[bool] = None,
1226
1291
  category: Optional[str] = None,
1292
+ flags: Optional[List[str]] = None,
1227
1293
  livecrawl_timeout: Optional[int] = None,
1228
1294
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1295
+ filter_empty_results: Optional[bool] = None,
1229
1296
  subpages: Optional[int] = None,
1230
1297
  subpage_target: Optional[Union[str, List[str]]] = None,
1231
- filter_empty_results: Optional[bool] = None,
1232
1298
  extras: Optional[ExtrasOptions] = None,
1233
- flags: Optional[List[str]] = None,
1234
1299
  ) -> SearchResponse[ResultWithTextAndHighlights]:
1235
1300
  ...
1236
1301
 
@@ -1251,13 +1316,13 @@ class Exa:
1251
1316
  exclude_text: Optional[List[str]] = None,
1252
1317
  exclude_source_domain: Optional[bool] = None,
1253
1318
  category: Optional[str] = None,
1319
+ flags: Optional[List[str]] = None,
1254
1320
  livecrawl_timeout: Optional[int] = None,
1255
1321
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1322
+ filter_empty_results: Optional[bool] = None,
1256
1323
  subpages: Optional[int] = None,
1257
1324
  subpage_target: Optional[Union[str, List[str]]] = None,
1258
- filter_empty_results: Optional[bool] = None,
1259
1325
  extras: Optional[ExtrasOptions] = None,
1260
- flags: Optional[List[str]] = None,
1261
1326
  ) -> SearchResponse[ResultWithSummary]:
1262
1327
  ...
1263
1328
 
@@ -1279,13 +1344,13 @@ class Exa:
1279
1344
  exclude_text: Optional[List[str]] = None,
1280
1345
  exclude_source_domain: Optional[bool] = None,
1281
1346
  category: Optional[str] = None,
1347
+ flags: Optional[List[str]] = None,
1282
1348
  livecrawl_timeout: Optional[int] = None,
1283
1349
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1350
+ filter_empty_results: Optional[bool] = None,
1284
1351
  subpages: Optional[int] = None,
1285
1352
  subpage_target: Optional[Union[str, List[str]]] = None,
1286
- filter_empty_results: Optional[bool] = None,
1287
1353
  extras: Optional[ExtrasOptions] = None,
1288
- flags: Optional[List[str]] = None,
1289
1354
  ) -> SearchResponse[ResultWithTextAndSummary]:
1290
1355
  ...
1291
1356
 
@@ -1307,13 +1372,13 @@ class Exa:
1307
1372
  exclude_text: Optional[List[str]] = None,
1308
1373
  exclude_source_domain: Optional[bool] = None,
1309
1374
  category: Optional[str] = None,
1310
- livecrawl_timeout: Optional[int] = None,
1375
+ flags: Optional[List[str]] = None,
1311
1376
  subpages: Optional[int] = None,
1312
1377
  subpage_target: Optional[Union[str, List[str]]] = None,
1378
+ livecrawl_timeout: Optional[int] = None,
1313
1379
  livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1314
1380
  filter_empty_results: Optional[bool] = None,
1315
1381
  extras: Optional[ExtrasOptions] = None,
1316
- flags: Optional[List[str]] = None,
1317
1382
  ) -> SearchResponse[ResultWithHighlightsAndSummary]:
1318
1383
  ...
1319
1384
 
@@ -1336,20 +1401,24 @@ class Exa:
1336
1401
  exclude_text: Optional[List[str]] = None,
1337
1402
  exclude_source_domain: Optional[bool] = None,
1338
1403
  category: Optional[str] = None,
1404
+ flags: Optional[List[str]] = None,
1339
1405
  livecrawl_timeout: Optional[int] = None,
1406
+ livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1407
+ filter_empty_results: Optional[bool] = None,
1340
1408
  subpages: Optional[int] = None,
1341
1409
  subpage_target: Optional[Union[str, List[str]]] = None,
1342
- filter_empty_results: Optional[bool] = None,
1343
- livecrawl: Optional[LIVECRAWL_OPTIONS] = None,
1344
1410
  extras: Optional[ExtrasOptions] = None,
1345
- flags: Optional[List[str]] = None,
1346
1411
  ) -> SearchResponse[ResultWithTextAndHighlightsAndSummary]:
1347
1412
  ...
1348
1413
 
1349
1414
  def find_similar_and_contents(self, url: str, **kwargs):
1350
1415
  options = {k: v for k, v in {"url": url, **kwargs}.items() if v is not None}
1351
1416
  # Default to text if none specified
1352
- if "text" not in options and "highlights" not in options and "summary" not in options:
1417
+ if (
1418
+ "text" not in options
1419
+ and "highlights" not in options
1420
+ and "summary" not in options
1421
+ ):
1353
1422
  options["text"] = True
1354
1423
 
1355
1424
  validate_search_options(
@@ -1379,9 +1448,9 @@ class Exa:
1379
1448
  data = self.request("/findSimilar", options)
1380
1449
  return SearchResponse(
1381
1450
  [Result(**to_snake_case(result)) for result in data["results"]],
1382
- data["autopromptString"] if "autopromptString" in data else None,
1383
- data["resolvedSearchType"] if "resolvedSearchType" in data else None,
1384
- data["autoDate"] if "autoDate" in data else None,
1451
+ data.get("autopromptString"),
1452
+ data.get("resolvedSearchType"),
1453
+ data.get("autoDate"),
1385
1454
  )
1386
1455
 
1387
1456
  def wrap(self, client: OpenAI):
@@ -1455,7 +1524,7 @@ class Exa:
1455
1524
  exa_kwargs=exa_kwargs,
1456
1525
  )
1457
1526
 
1458
- print("Wrapping OpenAI client with Exa functionality.", type(create_with_rag))
1527
+ print("Wrapping OpenAI client with Exa functionality.")
1459
1528
  client.chat.completions.create = create_with_rag # type: ignore
1460
1529
 
1461
1530
  return client
@@ -1499,6 +1568,7 @@ class Exa:
1499
1568
  completion=completion, exa_result=None
1500
1569
  )
1501
1570
 
1571
+ # We do a search_and_contents automatically
1502
1572
  exa_result = self.search_and_contents(query, **exa_kwargs)
1503
1573
  exa_str = format_exa_result(exa_result, max_len=max_len)
1504
1574
  new_messages = add_message_to_messages(completion, messages, exa_str)
@@ -1537,8 +1607,9 @@ class Exa:
1537
1607
  include_text (bool, optional): Whether to include full text in the results. Defaults to False.
1538
1608
 
1539
1609
  Returns:
1540
- Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]: Either an AnswerResponse object containing the answer and sources,
1541
- or an iterator that yields either answer chunks or sources when streaming is enabled.
1610
+ Union[AnswerResponse, Iterator[Union[str, List[AnswerResult]]]]:
1611
+ - If stream=False, returns an AnswerResponse object containing the answer and sources.
1612
+ - If stream=True, returns an iterator that yields either answer chunks or sources.
1542
1613
  """
1543
1614
  options = {
1544
1615
  k: v
@@ -1547,10 +1618,10 @@ class Exa:
1547
1618
  }
1548
1619
  options = to_camel_case(options)
1549
1620
  response = self.request("/answer", options)
1550
-
1621
+
1551
1622
  if stream:
1552
1623
  return response
1553
-
1624
+
1554
1625
  return AnswerResponse(
1555
1626
  response["answer"],
1556
1627
  [AnswerResult(**to_snake_case(result)) for result in response["sources"]]
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "exa-py"
3
- version = "1.8.3"
3
+ version = "1.8.5"
4
4
  description = "Python SDK for Exa API."
5
5
  authors = ["Exa AI <hello@exa.ai>"]
6
6
  readme = "README.md"
File without changes
File without changes
File without changes
File without changes