webcrawlerapi 2.1.0__tar.gz → 2.1.2__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webcrawlerapi
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: Python SDK for WebCrawler API
5
5
  Home-page: https://github.com/webcrawlerapi/webcrawlerapi-python-sdk
6
6
  Author: Andrew
@@ -2,7 +2,7 @@ from setuptools import find_packages, setup
2
2
 
3
3
  setup(
4
4
  name="webcrawlerapi",
5
- version="2.1.0",
5
+ version="2.1.2",
6
6
  packages=find_packages(),
7
7
  install_requires=[
8
8
  "requests>=2.25.0",
@@ -25,6 +25,7 @@ Basic usage:
25
25
  from .client import WebCrawlerAPI
26
26
  from .models import (
27
27
  Action,
28
+ AgentRun,
28
29
  CrawlResponse,
29
30
  Job,
30
31
  JobItem,
@@ -49,4 +50,5 @@ __all__ = [
49
50
  "ScrapeResponseError",
50
51
  "Action",
51
52
  "UploadS3Action",
53
+ "AgentRun",
52
54
  ]
@@ -6,6 +6,7 @@ import requests
6
6
 
7
7
  from .models import (
8
8
  Action,
9
+ AgentRun,
9
10
  CrawlResponse,
10
11
  Job,
11
12
  JobMarkdownResponse,
@@ -17,6 +18,7 @@ from .models import (
17
18
 
18
19
  CRAWLER_VERSION = "v1"
19
20
  SCRAPER_VERSION = "v2"
21
+ AGENT_TERMINAL_STATUSES = {"done", "error", "canceled"}
20
22
 
21
23
 
22
24
  class WebCrawlerAPI:
@@ -355,6 +357,130 @@ class WebCrawlerAPI:
355
357
 
356
358
  return self.get_job_markdown_content(job.id)
357
359
 
360
+ def run_agent_async(
361
+ self,
362
+ prompt: str,
363
+ max_spend_usd: float,
364
+ urls: Optional[List[str]] = None,
365
+ seed_urls_only: Optional[bool] = None,
366
+ output_schema: Optional[Dict[str, Any]] = None,
367
+ model: Optional[str] = None,
368
+ ) -> AgentRun:
369
+ """
370
+ Start a new agent run asynchronously.
371
+
372
+ Args:
373
+ prompt (str): Natural-language task for the agent to complete
374
+ max_spend_usd (float): Maximum spend for this run in USD
375
+ urls (list, optional): Optional seed URLs the agent can use while running the task
376
+ seed_urls_only (bool, optional): If True, the agent only uses the provided seed URLs
377
+ output_schema (dict, optional): Optional JSON schema for structured agent output
378
+ model (str, optional): Model to use for the run. Omit to use the API default.
379
+
380
+ Returns:
381
+ AgentRun: The created agent run
382
+
383
+ Raises:
384
+ WebCrawlerApiError: If the API returns an error response
385
+ requests.exceptions.RequestException: If the HTTP request fails
386
+ """
387
+ payload: Dict[str, Any] = {"prompt": prompt, "max_spend_usd": max_spend_usd}
388
+
389
+ if urls is not None:
390
+ payload["urls"] = urls
391
+ if seed_urls_only is not None:
392
+ payload["seed_urls_only"] = seed_urls_only
393
+ if output_schema is not None:
394
+ payload["output_schema"] = output_schema
395
+ if model is not None:
396
+ payload["model"] = model
397
+
398
+ response = self.session.post(
399
+ urljoin(self.base_url, f"/{CRAWLER_VERSION}/agent"), json=payload
400
+ )
401
+ if not response.ok:
402
+ self._raise_for_error(response)
403
+ return AgentRun(response.json())
404
+
405
+ def get_agent_job(self, job_id: str) -> AgentRun:
406
+ """
407
+ Get the status and result of a specific agent run.
408
+
409
+ Args:
410
+ job_id (str): The unique identifier of the agent run
411
+
412
+ Returns:
413
+ AgentRun: The agent run status and result
414
+
415
+ Raises:
416
+ WebCrawlerApiError: If the API returns an error response
417
+ requests.exceptions.RequestException: If the HTTP request fails
418
+ """
419
+ response = self.session.get(
420
+ urljoin(self.base_url, f"/{CRAWLER_VERSION}/agent/job/{job_id}"),
421
+ headers={"Cache-Control": "no-cache, no-store, must-revalidate"},
422
+ )
423
+ if not response.ok:
424
+ self._raise_for_error(response)
425
+ return AgentRun(response.json())
426
+
427
+ def run_agent(
428
+ self,
429
+ prompt: str,
430
+ max_spend_usd: float,
431
+ urls: Optional[List[str]] = None,
432
+ seed_urls_only: Optional[bool] = None,
433
+ output_schema: Optional[Dict[str, Any]] = None,
434
+ model: Optional[str] = None,
435
+ max_polls: int = 100,
436
+ ) -> AgentRun:
437
+ """
438
+ Start a new agent run and wait for its completion.
439
+
440
+ Args:
441
+ prompt (str): Natural-language task for the agent to complete
442
+ max_spend_usd (float): Maximum spend for this run in USD
443
+ urls (list, optional): Optional seed URLs the agent can use while running the task
444
+ seed_urls_only (bool, optional): If True, the agent only uses the provided seed URLs
445
+ output_schema (dict, optional): Optional JSON schema for structured agent output
446
+ model (str, optional): Model to use for the run. Omit to use the API default.
447
+ max_polls (int): Maximum number of status checks before raising a timeout (default: 100)
448
+
449
+ Returns:
450
+ AgentRun: The final agent run state after completion
451
+
452
+ Raises:
453
+ WebCrawlerApiError: If the API returns an error response or the run times out
454
+ requests.exceptions.RequestException: If any API request fails
455
+ """
456
+ run = self.run_agent_async(
457
+ prompt=prompt,
458
+ max_spend_usd=max_spend_usd,
459
+ urls=urls,
460
+ seed_urls_only=seed_urls_only,
461
+ output_schema=output_schema,
462
+ model=model,
463
+ )
464
+
465
+ if not run.id:
466
+ raise WebCrawlerApiError(
467
+ "invalid_response", "Failed to fetch agent job status"
468
+ )
469
+
470
+ if run.status in AGENT_TERMINAL_STATUSES:
471
+ return run
472
+
473
+ for _ in range(max_polls):
474
+ time.sleep(2)
475
+ agent_job = self.get_agent_job(run.id)
476
+ if agent_job.status in AGENT_TERMINAL_STATUSES:
477
+ return agent_job
478
+
479
+ raise WebCrawlerApiError(
480
+ "timeout",
481
+ "Agent run took too long, please retry or increase the number of polling retries",
482
+ )
483
+
358
484
  def scrape_async(
359
485
  self,
360
486
  url: str,
@@ -94,6 +94,31 @@ class ScrapeResponseError:
94
94
  status: Optional[str] = None
95
95
 
96
96
 
97
+ class AgentRun:
98
+ """Represents an agent run job."""
99
+
100
+ TERMINAL_STATUSES = {"done", "error", "canceled"}
101
+
102
+ def __init__(self, data: Dict[str, Any]):
103
+ self.id: str = data["id"]
104
+ self.status: str = data["status"]
105
+ self.prompt: str = data["prompt"]
106
+ self.model: str = data["model"]
107
+ self.data: Optional[Any] = data.get("data")
108
+ self.error_reason: Optional[str] = data.get("error_reason")
109
+ self.balance_used_usd: float = data.get("balance_used_usd", 0)
110
+ self.max_spend_usd: Optional[float] = data.get("max_spend_usd")
111
+ self.urls: Optional[List[str]] = data.get("urls")
112
+ self.created_at: datetime = parse_datetime(data["created_at"])
113
+ self.updated_at: datetime = parse_datetime(data["updated_at"])
114
+ self.success: bool = data.get("success", False)
115
+
116
+ @property
117
+ def is_terminal(self) -> bool:
118
+ """Check if the agent run is in a terminal state (done, error, or canceled)."""
119
+ return self.status in self.TERMINAL_STATUSES
120
+
121
+
97
122
  @dataclass
98
123
  class Action:
99
124
  """Base class for actions that can be performed during crawling."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: webcrawlerapi
3
- Version: 2.1.0
3
+ Version: 2.1.2
4
4
  Summary: Python SDK for WebCrawler API
5
5
  Home-page: https://github.com/webcrawlerapi/webcrawlerapi-python-sdk
6
6
  Author: Andrew
File without changes
File without changes