webcrawlerapi-js 2.1.0 → 2.2.0
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.
- package/README.md +25 -0
- package/dist/@types/api.d.ts +5 -1
- package/dist/@types/model.d.ts +32 -0
- package/dist/api.js +49 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -46,6 +46,31 @@ for (const item of job.job_items) {
|
|
|
46
46
|
}
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
+
## Run an agent
|
|
50
|
+
|
|
51
|
+
```javascript
|
|
52
|
+
import webcrawlerapi from "webcrawlerapi-js"
|
|
53
|
+
|
|
54
|
+
const client = new webcrawlerapi.WebcrawlerClient("YOUR_API_KEY")
|
|
55
|
+
|
|
56
|
+
const result = await client.runAgent({
|
|
57
|
+
prompt: "Visit the provided website and return the page title as JSON.",
|
|
58
|
+
urls: ["https://books.toscrape.com/"],
|
|
59
|
+
seed_urls_only: true,
|
|
60
|
+
output_schema: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
title: { type: "string" },
|
|
64
|
+
},
|
|
65
|
+
required: ["title"],
|
|
66
|
+
additionalProperties: false,
|
|
67
|
+
},
|
|
68
|
+
max_spend_usd: 0.02,
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
console.log(result.status, result.data)
|
|
72
|
+
```
|
|
73
|
+
|
|
49
74
|
## Documentation
|
|
50
75
|
|
|
51
76
|
- [Scraping](docs/scraping.md) — single page, async mode, AI extraction, parameters, response fields
|
package/dist/@types/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse, ScrapeResponseError, ScrapeId, Action, JobMarkdownResponse } from "./model";
|
|
1
|
+
import { CrawlRequest, Job, JobId, ScrapeRequest, ScrapeResponse, ScrapeResponseError, ScrapeId, Action, JobMarkdownResponse, AgentRunRequest, AgentRun } from "./model";
|
|
2
2
|
import { JobStatus, ErrorCode } from "./constants";
|
|
3
3
|
import { WebcrawlerApiError } from "./errors";
|
|
4
4
|
export { WebcrawlerApiError, JobStatus, ErrorCode };
|
|
@@ -8,7 +8,11 @@ export declare class WebcrawlerClient {
|
|
|
8
8
|
protected apiKey: string;
|
|
9
9
|
protected basePath: string;
|
|
10
10
|
constructor(apiKey: string, basePath?: string, apiVersion?: string);
|
|
11
|
+
private getDefaultHeaders;
|
|
11
12
|
scrapeAsync(request: ScrapeRequest): Promise<ScrapeId>;
|
|
13
|
+
runAgentAsync(request: AgentRunRequest): Promise<AgentRun>;
|
|
14
|
+
getAgentJob(jobID: string): Promise<AgentRun>;
|
|
15
|
+
runAgent(request: AgentRunRequest, maxPolls?: number): Promise<AgentRun>;
|
|
12
16
|
getScrape(scrapeId: string): Promise<ScrapeResponse | ScrapeResponseError>;
|
|
13
17
|
scrape(request: ScrapeRequest, maxPolls?: number): Promise<ScrapeResponse | ScrapeResponseError>;
|
|
14
18
|
crawl(crawlRequest: CrawlRequest, actions?: Action | Action[]): Promise<Job>;
|
package/dist/@types/model.d.ts
CHANGED
|
@@ -119,3 +119,35 @@ export interface UploadS3Action extends Action {
|
|
|
119
119
|
export interface JobMarkdownResponse {
|
|
120
120
|
content_url: string;
|
|
121
121
|
}
|
|
122
|
+
export interface AgentRunRequest {
|
|
123
|
+
/** Natural-language task for the agent to complete. */
|
|
124
|
+
prompt: string;
|
|
125
|
+
/** Optional seed URLs the agent can use while running the task. */
|
|
126
|
+
urls?: string[];
|
|
127
|
+
/** If true, the agent only uses the provided seed URLs. */
|
|
128
|
+
seed_urls_only?: boolean;
|
|
129
|
+
/** Optional JSON schema for structured agent output. */
|
|
130
|
+
output_schema?: Record<string, any>;
|
|
131
|
+
/** Model to use for the run. Omit to use the API default. */
|
|
132
|
+
model?: string;
|
|
133
|
+
/** Maximum spend for this run in USD. Required by the API. */
|
|
134
|
+
max_spend_usd: number;
|
|
135
|
+
}
|
|
136
|
+
export interface AgentRun {
|
|
137
|
+
id: string;
|
|
138
|
+
status: string;
|
|
139
|
+
prompt: string;
|
|
140
|
+
model: string;
|
|
141
|
+
data?: any;
|
|
142
|
+
error_reason?: string;
|
|
143
|
+
balance_used_usd: number;
|
|
144
|
+
max_spend_usd?: number;
|
|
145
|
+
urls?: string[];
|
|
146
|
+
created_at: string;
|
|
147
|
+
updated_at: string;
|
|
148
|
+
success: boolean;
|
|
149
|
+
}
|
|
150
|
+
export interface AgentRunList {
|
|
151
|
+
items: AgentRun[];
|
|
152
|
+
total: number;
|
|
153
|
+
}
|
package/dist/api.js
CHANGED
|
@@ -24,6 +24,7 @@ const BASE_PATH = "https://api.webcrawlerapi.com";
|
|
|
24
24
|
const initialPullDelayMs = 2000;
|
|
25
25
|
const MaxPullRetries = 100;
|
|
26
26
|
const DEFAULT_POLL_DELAY_SECONDS = 2;
|
|
27
|
+
const AgentTerminalStatuses = ["done", "error", "canceled"];
|
|
27
28
|
__exportStar(require("./model"), exports);
|
|
28
29
|
const SCRAPE_VERSION = "v2";
|
|
29
30
|
function resolveContentUrl(job, item) {
|
|
@@ -94,6 +95,19 @@ class WebcrawlerClient {
|
|
|
94
95
|
this.basePath = basePath;
|
|
95
96
|
this.apiVersion = apiVersion;
|
|
96
97
|
}
|
|
98
|
+
getDefaultHeaders(cacheControl = false) {
|
|
99
|
+
const headers = {
|
|
100
|
+
'Content-Type': 'application/json',
|
|
101
|
+
'Authorization': `Bearer ${this.apiKey}`,
|
|
102
|
+
"User-Agent": "WebcrawlerAPI-NodeJS-Client"
|
|
103
|
+
};
|
|
104
|
+
if (cacheControl) {
|
|
105
|
+
headers['Cache-Control'] = 'no-cache, no-store, must-revalidate';
|
|
106
|
+
headers['Pragma'] = 'no-cache';
|
|
107
|
+
headers['Expires'] = '0';
|
|
108
|
+
}
|
|
109
|
+
return headers;
|
|
110
|
+
}
|
|
97
111
|
async scrapeAsync(request) {
|
|
98
112
|
const apiUrl = `${this.basePath}/${SCRAPE_VERSION}/scrape?async=true`;
|
|
99
113
|
const requestOptions = {
|
|
@@ -108,6 +122,41 @@ class WebcrawlerClient {
|
|
|
108
122
|
const response = await this.sendRequest(apiUrl, requestOptions);
|
|
109
123
|
return { id: response.id };
|
|
110
124
|
}
|
|
125
|
+
async runAgentAsync(request) {
|
|
126
|
+
const url = `${this.basePath}/${this.apiVersion}/agent`;
|
|
127
|
+
const requestOptions = {
|
|
128
|
+
'method': 'POST',
|
|
129
|
+
'headers': this.getDefaultHeaders(),
|
|
130
|
+
'body': JSON.stringify(request),
|
|
131
|
+
};
|
|
132
|
+
return await this.sendRequest(url, requestOptions);
|
|
133
|
+
}
|
|
134
|
+
async getAgentJob(jobID) {
|
|
135
|
+
const url = `${this.basePath}/${this.apiVersion}/agent/job/${jobID}`;
|
|
136
|
+
const requestOptions = {
|
|
137
|
+
'method': 'GET',
|
|
138
|
+
'headers': this.getDefaultHeaders(true)
|
|
139
|
+
};
|
|
140
|
+
return await this.sendRequest(url, requestOptions);
|
|
141
|
+
}
|
|
142
|
+
async runAgent(request, maxPolls = MaxPullRetries) {
|
|
143
|
+
const run = await this.runAgentAsync(request);
|
|
144
|
+
if (!run.id) {
|
|
145
|
+
throw new errors_1.WebcrawlerApiError('invalid_response', 'Failed to fetch agent job status', 0);
|
|
146
|
+
}
|
|
147
|
+
if (AgentTerminalStatuses.includes(run.status)) {
|
|
148
|
+
return run;
|
|
149
|
+
}
|
|
150
|
+
for (let i = 0; i < maxPolls; i++) {
|
|
151
|
+
await new Promise(resolve => setTimeout(resolve, DEFAULT_POLL_DELAY_SECONDS * 1000));
|
|
152
|
+
const timestamp = new Date().getTime();
|
|
153
|
+
const agentJob = await this.getAgentJob(`${run.id}?t=${timestamp}`);
|
|
154
|
+
if (AgentTerminalStatuses.includes(agentJob.status)) {
|
|
155
|
+
return agentJob;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
throw new errors_1.WebcrawlerApiError('timeout', 'Agent run took too long, please retry or increase the number of polling retries', 0);
|
|
159
|
+
}
|
|
111
160
|
async getScrape(scrapeId) {
|
|
112
161
|
const url = `${this.basePath}/${SCRAPE_VERSION}/scrape/${scrapeId}`;
|
|
113
162
|
const requestOptions = {
|