xapi-to 0.1.18 → 0.1.20

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.
@@ -0,0 +1,466 @@
1
+ # Managed Sandbox Compute Guide
2
+
3
+ Use xAPI Sandbox when a user or AI agent needs an isolated cloud computer for
4
+ code execution, file processing, CI reproduction, a temporary Web/API preview,
5
+ GPU work, or a resumable multi-step job. It is a billable lifecycle service,
6
+ not an ordinary per-call action, so cleanup and audit are part of task success.
7
+
8
+ ## Contents
9
+
10
+ - [Choose the shortest safe lifecycle](#choose-the-shortest-safe-lifecycle)
11
+ - [Authentication and gateway selection](#authentication-and-gateway-selection)
12
+ - [Inspect offerings and quote first](#inspect-offerings-and-quote-first)
13
+ - [One-shot execution](#one-shot-execution)
14
+ - [Multi-step agent lifecycle](#multi-step-agent-lifecycle)
15
+ - [Files and artifacts](#files-and-artifacts)
16
+ - [Web preview and background processes](#web-preview-and-background-processes)
17
+ - [Suspend and resume](#suspend-and-resume)
18
+ - [GPU jobs](#gpu-jobs)
19
+ - [Parallel agents](#parallel-agents)
20
+ - [OpenAI SandboxAgent with xAPI DeepSeek](#openai-sandboxagent-with-xapi-deepseek)
21
+ - [Audit, history, and billing](#audit-history-and-billing)
22
+ - [Run the real Playground acceptance suite](#run-the-real-playground-acceptance-suite)
23
+ - [Failure and interruption recovery](#failure-and-interruption-recovery)
24
+ - [AI operating rules](#ai-operating-rules)
25
+
26
+ ## Choose the shortest safe lifecycle
27
+
28
+ | Need | Preferred command | Cleanup behavior |
29
+ |---|---|---|
30
+ | Run one command and get stdout | `sandbox run` | Terminates automatically |
31
+ | Several exec/file calls | `create` + primitives | Agent must terminate |
32
+ | Inspect price/capabilities | `offerings`, `quote` | No instance created |
33
+ | Publish a temporary port | `port` after starting a server | Terminate afterward |
34
+ | Pause a reusable workspace | `suspend` | Storage may keep billing |
35
+ | Inspect prior work/cost | `history`, `get`, `audit` | Read-only |
36
+
37
+ Prefer `sandbox run` whenever the task fits one remote shell command. A shorter
38
+ lifecycle reduces orphan risk and returns one machine-readable JSON result.
39
+
40
+ ## Authentication and gateway selection
41
+
42
+ The CLI reads `XAPI_KEY`, then `XAPI_API_KEY`, then `~/.xapi/config.json`.
43
+ Do not print, interpolate into a URL, or pass the key inside the remote command.
44
+ The CLI sends Sandbox credentials only to `*.xapi.to` or localhost.
45
+
46
+ Production uses `sandbox.xapi.to`. The test service is selected explicitly:
47
+
48
+ ```bash
49
+ export XAPI_SANDBOX_HOST=sandbox.test.xapi.to
50
+ ```
51
+
52
+ Omit `--provider` (or use `--provider auto`) for lowest-price compatible
53
+ selection. Pin only when the task or test requires a particular provider:
54
+
55
+ ```bash
56
+ npx xapi-to sandbox offerings --provider cf-edge --format table
57
+ npx xapi-to sandbox quote --provider daytona --capabilities exec,files
58
+ ```
59
+
60
+ Provider pinning derives a controlled hostname such as
61
+ `cf-edge.sandbox.test.xapi.to`; it does not accept arbitrary provider URLs.
62
+ For production, canonical `--provider daytona` and `--provider e2b` are mapped
63
+ to the deployed `daytona-sandbox.sandbox.xapi.to` and
64
+ `e2b-sandbox.sandbox.xapi.to` aliases; their test hosts remain
65
+ `daytona.sandbox.test.xapi.to` and `e2b.sandbox.test.xapi.to`.
66
+ Available providers and capabilities can change, so inspect `offerings` rather
67
+ than assuming a static capability matrix.
68
+
69
+ ## Inspect offerings and quote first
70
+
71
+ `offerings` shows provider-declared resources, capabilities, lifecycle support,
72
+ and hourly estimates. `quote` applies requirements without creating or billing
73
+ an instance:
74
+
75
+ ```bash
76
+ npx xapi-to sandbox offerings --format table
77
+
78
+ npx xapi-to sandbox quote \
79
+ --capabilities exec,files \
80
+ --cpu 2 \
81
+ --memory 4 \
82
+ --max-hourly-usd 0.20 \
83
+ --format pretty
84
+ ```
85
+
86
+ Use `--format table` for a compact comparison and JSON when a complete quote ID
87
+ or nested rate card must be copied. Table truncation is marked with `…`.
88
+
89
+ Use `--requirements '<json>'` for fields that do not have a shortcut. Treat
90
+ `--max-hourly-usd` as a hard guardrail chosen before creation. A quote is
91
+ short-lived; create promptly or quote again.
92
+
93
+ ## One-shot execution
94
+
95
+ `sandbox run` performs quote → create → wait for `RUNNING` → exec → terminate →
96
+ read final cost. Its default price ceiling is `$0.20/hour`:
97
+
98
+ ```bash
99
+ npx xapi-to sandbox run \
100
+ --capabilities exec \
101
+ --command 'python3 -c "print(sum(range(1000)))"' \
102
+ --format pretty
103
+ ```
104
+
105
+ Arguments after a bare `--` are joined into the remote command:
106
+
107
+ ```bash
108
+ npx xapi-to sandbox run -- node --version
109
+ ```
110
+
111
+ Read these output fields first:
112
+
113
+ - `result.exitCode`, `result.stdout`, `result.stderr`: remote result;
114
+ - `cleanup.operationStatus`, `cleanup.state`: teardown result;
115
+ - `finalState`: should be `TERMINATED` (or provider-terminal `FAILED`);
116
+ - `totalCost`: service-calculated cost, not a client estimate.
117
+
118
+ A remote non-zero exit code becomes the local CLI exit code after cleanup, so
119
+ shells and AI runners can detect failure without parsing stdout.
120
+
121
+ `--keep` suppresses automatic termination. Use it only after the user explicitly
122
+ asks to retain the instance and understands that billing continues.
123
+
124
+ ## Multi-step agent lifecycle
125
+
126
+ Use granular commands when an agent must alternate between files and commands.
127
+ Capture the instance ID without logging credentials:
128
+
129
+ ```bash
130
+ box_json="$(npx xapi-to sandbox create \
131
+ --capabilities exec,files \
132
+ --idempotency-key "job-${JOB_ID}" \
133
+ --wait)"
134
+ box_id="$(printf '%s' "$box_json" | jq -r '.id')"
135
+
136
+ npx xapi-to sandbox wait "$box_id" --state RUNNING --wait-timeout 5m
137
+
138
+ cleanup() {
139
+ npx xapi-to sandbox terminate "$box_id" --wait-timeout 5m || true
140
+ }
141
+ trap cleanup EXIT INT TERM
142
+
143
+ npx xapi-to sandbox file write "$box_id" task.md --file ./task.md
144
+ npx xapi-to sandbox exec "$box_id" --command 'npm test' --timeout 120
145
+ npx xapi-to sandbox file read "$box_id" report.json --output ./report.json
146
+ ```
147
+
148
+ Use a stable business `--idempotency-key` when the caller might repeat create
149
+ after a lost response. Do not blindly repeat mutations with a new key: the first
150
+ request may already have created a billable instance.
151
+
152
+ The CLI rejects unknown Sandbox flags before making a request. Exact
153
+ `--offering-id` selection cannot be combined with `--max-hourly-usd`; select by
154
+ requirements under a ceiling or create from a previously checked quote instead.
155
+ Successful create output returns `clientIdempotencyKey`. If `create --wait`
156
+ fails after acceptance, retain the structured `instanceId`, `observedState`,
157
+ `clientIdempotencyKey`, and recovery commands from stderr, then inspect and
158
+ terminate the instance as appropriate.
159
+
160
+ ## Files and artifacts
161
+
162
+ Write inline text or a local file:
163
+
164
+ ```bash
165
+ npx xapi-to sandbox file write <id> instructions.txt --content 'Run tests.'
166
+ npx xapi-to sandbox file write <id> input.csv --file ./input.csv
167
+ ```
168
+
169
+ Read and list artifacts:
170
+
171
+ ```bash
172
+ npx xapi-to sandbox file list <id> --path . --depth 3
173
+ npx xapi-to sandbox file read <id> output.json
174
+ npx xapi-to sandbox file read <id> output.zip --output ./output.zip
175
+ ```
176
+
177
+ Local `--output` uses create-new semantics and refuses to overwrite an existing
178
+ file. The CLI base64-encodes local input bytes so binary files survive transfer.
179
+
180
+ ## Web preview and background processes
181
+
182
+ For providers that declare both `backgroundExec` and `ports`, use the explicit
183
+ provider-managed background command. Daytona needs this mode because deleting a
184
+ foreground command session also kills shell-backgrounded child processes:
185
+
186
+ ```bash
187
+ box_json="$(npx xapi-to sandbox create \
188
+ --provider daytona \
189
+ --capabilities exec,backgroundExec,ports \
190
+ --wait)"
191
+ box_id="$(printf '%s' "$box_json" | jq -r '.id')"
192
+ port=25319
193
+
194
+ cleanup() { npx xapi-to sandbox terminate "$box_id" --provider daytona || true; }
195
+ trap cleanup EXIT INT TERM
196
+
197
+ npx xapi-to sandbox exec "$box_id" --provider daytona --background --command \
198
+ "python3 -m http.server $port --bind 0.0.0.0"
199
+ npx xapi-to sandbox port "$box_id" "$port" --provider daytona
200
+ ```
201
+
202
+ `--background` returning a session/command ID is only launch acknowledgement.
203
+ Poll the public URL with bounded retries and verify an expected marker. If the
204
+ port response contains `headers`, include them in external requests; they can
205
+ carry a provider preview token. Do not emulate this mode with `nohup ... &` on
206
+ an Offering that does not declare `backgroundExec`.
207
+
208
+ Cloudflare currently uses its provider-specific command/preview behavior rather
209
+ than the standard background session capability. Pin `cf-edge` only when the
210
+ user explicitly wants Cloudflare. Port `8080` is the currently verified preview
211
+ path for the deployed bridge:
212
+
213
+ ```bash
214
+ box_json="$(npx xapi-to sandbox create \
215
+ --provider cf-edge \
216
+ --capabilities exec,files,ports \
217
+ --wait)"
218
+ box_id="$(printf '%s' "$box_json" | jq -r '.id')"
219
+ port=8080
220
+
221
+ cleanup() { npx xapi-to sandbox terminate "$box_id" --provider cf-edge || true; }
222
+ trap cleanup EXIT INT TERM
223
+
224
+ npx xapi-to sandbox file write "$box_id" index.html \
225
+ --provider cf-edge \
226
+ --content '<!doctype html><h1>xAPI preview</h1>'
227
+
228
+ npx xapi-to sandbox exec "$box_id" --provider cf-edge --command \
229
+ "nohup python3 -m http.server $port >/tmp/server.log 2>&1 & \
230
+ for i in 1 2 3 4 5 6 7 8 9 10; do \
231
+ curl -sf http://127.0.0.1:$port/ && exit 0; sleep 1; done; \
232
+ cat /tmp/server.log >&2; exit 1"
233
+
234
+ npx xapi-to sandbox port "$box_id" "$port" --provider cf-edge
235
+ ```
236
+
237
+ Validate that the returned public URL serves the expected marker before calling
238
+ the workflow successful. Quick Tunnel DNS/TLS readiness can be intermittent, so
239
+ use bounded retries (for example, one request every two seconds for up to two
240
+ minutes). If it still fails, verify localhost again, record the URL/error, and
241
+ terminate instead of leaving the instance billing. The URL stops working after
242
+ termination. Quick Tunnels are for previews; use a stable, supported named
243
+ tunnel or application deployment for production traffic.
244
+
245
+ ## Suspend and resume
246
+
247
+ Check offering lifecycle fields first because not every provider supports an
248
+ explicit suspend operation:
249
+
250
+ ```bash
251
+ npx xapi-to sandbox offerings --format pretty
252
+ npx xapi-to sandbox suspend <id>
253
+ npx xapi-to sandbox get <id>
254
+ npx xapi-to sandbox resume <id>
255
+ ```
256
+
257
+ The CLI waits for `SUSPENDED` and `RUNNING` by default. Files may persist while
258
+ memory/processes do not; rely on the selected offering's declared lifecycle
259
+ semantics. Suspension can reduce compute cost but storage may still accrue cost.
260
+ If `lifecycle.suspension.supported` is false (as with a current cf-edge
261
+ offering), do not call suspend/resume; terminate and create a new instance.
262
+
263
+ ## GPU jobs
264
+
265
+ Request GPU resources instead of assuming a provider or model. The current
266
+ RunPod offering is a managed GPU resource without standard `exec`/`files`, so
267
+ inspect its declared extension and obtain connection details instead of sending
268
+ an impossible shell command:
269
+
270
+ ```bash
271
+ npx xapi-to sandbox quote \
272
+ --gpu-count 1 \
273
+ --gpu-model L4 \
274
+ --capabilities exec \
275
+ --max-hourly-usd 2.00
276
+
277
+ npx xapi-to sandbox create \
278
+ --provider runpod \
279
+ --gpu-count 1 \
280
+ --max-hourly-usd 2.00 \
281
+ --wait
282
+
283
+ npx xapi-to sandbox extension <id> runpod.connection_info \
284
+ --provider runpod \
285
+ --input '{}'
286
+
287
+ npx xapi-to sandbox terminate <id> --provider runpod
288
+ ```
289
+
290
+ GPU work is usually more expensive. Quote first, set a deliberate ceiling, use
291
+ a command timeout, and terminate immediately after artifacts are retrieved.
292
+
293
+ ## Parallel agents
294
+
295
+ Give each agent a separate instance. Do not share a mutable workspace when the
296
+ goal is isolation. Use unique idempotency keys and record every instance ID.
297
+ Run cleanup for all IDs even if one agent fails; then verify `sandbox list` has
298
+ no active instance from the job.
299
+
300
+ Limit concurrency based on budget. Parallel creation multiplies reservation and
301
+ running cost, even when the individual hourly quote is small.
302
+
303
+ ## OpenAI SandboxAgent with xAPI DeepSeek
304
+
305
+ The OpenAI Agents SDK keeps the model provider and sandbox provider separate.
306
+ Use the SDK's OpenAI-compatible model provider for DeepSeek through
307
+ `https://ai.xapi.to/v1`, and the xAPI adapter for Sandbox compute:
308
+
309
+ ```ts
310
+ import { OpenAIProvider, Runner } from '@openai/agents';
311
+ import { Manifest, SandboxAgent, shell } from '@openai/agents/sandbox';
312
+ import { XapiAgentsSandboxClient } from 'xapi-to/openai-sandbox';
313
+
314
+ const sandboxApiKey = process.env.XAPI_SANDBOX_KEY;
315
+ const aiApiKey = process.env.XAPI_AI_KEY;
316
+ if (!sandboxApiKey) throw new Error('XAPI_SANDBOX_KEY is required');
317
+ if (!aiApiKey) throw new Error('XAPI_AI_KEY is required');
318
+
319
+ const sandbox = new XapiAgentsSandboxClient({
320
+ apiKey: sandboxApiKey,
321
+ sandboxHost: 'sandbox.test.xapi.to',
322
+ provider: 'daytona',
323
+ model: 'deepseek-v4-pro',
324
+ });
325
+ const modelProvider = new OpenAIProvider({
326
+ apiKey: aiApiKey,
327
+ baseURL: 'https://ai.xapi.to/v1',
328
+ useResponses: false,
329
+ strictFeatureValidation: true,
330
+ });
331
+ const runner = new Runner({ modelProvider, tracingDisabled: true });
332
+ const agent = new SandboxAgent({
333
+ name: 'xAPI DeepSeek sandbox agent',
334
+ model: 'deepseek-v4-pro',
335
+ defaultManifest: new Manifest({ root: sandbox.workspaceRoot }),
336
+ capabilities: [shell()],
337
+ instructions: 'Use shell to complete and verify the task.',
338
+ });
339
+
340
+ try {
341
+ const result = await runner.run(agent, 'Write SDK_OK=42 to result.txt and read it.', {
342
+ maxTurns: 8,
343
+ sandbox: { client: sandbox },
344
+ });
345
+ console.log(result.finalOutput);
346
+ } finally {
347
+ await sandbox.lastSession?.close();
348
+ }
349
+ ```
350
+
351
+ Use `useResponses: false` because `ai.xapi.to` currently implements the OpenAI
352
+ Chat Completions-compatible protocol. Disable tracing unless a separate OpenAI
353
+ telemetry credential is configured; do not send an xAPI key to OpenAI tracing.
354
+ Keep `XAPI_AI_KEY` and `XAPI_SANDBOX_KEY` separate for a mixed environment:
355
+ the former is sent only to production `ai.xapi.to`, while the latter is sent
356
+ only to `sandbox.test.xapi.to`. A production key with both permissions may be
357
+ injected into both variables, but a Sandbox test key must not be assumed to
358
+ have production AI Gateway access.
359
+ The current adapter honestly supports an empty Manifest and Shell capability.
360
+ It rejects Manifest file/mount/environment materialization until those mappings
361
+ are implemented and tested.
362
+
363
+ Run the real SDK + DeepSeek + Daytona acceptance test from the CLI repository:
364
+
365
+ ```bash
366
+ XAPI_SANDBOX_KEY='<sandbox-test-key>' \
367
+ XAPI_AI_KEY='<ai-production-key>' \
368
+ npm run test:sandbox:openai -- \
369
+ --host sandbox.test.xapi.to \
370
+ --provider daytona \
371
+ --model deepseek-v4-pro
372
+ ```
373
+
374
+ The script writes a redacted report, audits operations/events/usage/billing,
375
+ terminates its instance, and fails if any active test instance remains.
376
+
377
+ ## Audit, history, and billing
378
+
379
+ Inspect current state and service-calculated total:
380
+
381
+ ```bash
382
+ npx xapi-to sandbox get <id> --format pretty
383
+ ```
384
+
385
+ Read individual audit streams:
386
+
387
+ ```bash
388
+ npx xapi-to sandbox audit <id> --kind operations
389
+ npx xapi-to sandbox audit <id> --kind events
390
+ npx xapi-to sandbox audit <id> --kind usageSegments
391
+ npx xapi-to sandbox audit <id> --kind billingPeriods
392
+ npx xapi-to sandbox history --state HISTORY --page-size 100
393
+ ```
394
+
395
+ `history` is a separate paginated endpoint for prior instances; it is not an
396
+ `audit --kind`. Filter it with `--search`, `--from`, and `--to` when reconciling
397
+ a specific agent run.
398
+
399
+ For acceptance, verify:
400
+
401
+ 1. create/exec/file/port/terminate operations have terminal success statuses;
402
+ 2. state events reach `TERMINATED`;
403
+ 3. no usage segment or billing period remains open;
404
+ 4. `totalCost` agrees with settled billing periods;
405
+ 5. `sandbox list` shows no active instance from the test.
406
+
407
+ Use the returned billing data rather than recomputing cost from wall-clock time.
408
+
409
+ ## Run the real Playground acceptance suite
410
+
411
+ From an xapi-cli development checkout, run the same nine real workflows shown
412
+ in the Web Playground. The suite uses normal CLI configuration, never accepts a
413
+ key on argv, records audit/billing evidence, terminates every tracked instance
414
+ in `finally`, and fails if any instance created after its baseline remains
415
+ ACTIVE (unrelated pre-existing account instances are still reported):
416
+
417
+ ```bash
418
+ npm run test:sandbox:playground -- --host sandbox.test.xapi.to
419
+
420
+ # Focus a rerun or avoid the higher-cost GPU reservation
421
+ npm run test:sandbox:playground -- --host sandbox.test.xapi.to --only 8,9
422
+ npm run test:sandbox:playground -- --host sandbox.test.xapi.to --skip-gpu
423
+ ```
424
+
425
+ The JSON report path is printed at completion. A provider capacity or HTTP 402
426
+ balance error is an external test precondition failure, not proof that the
427
+ scenario works; retain the error and a previous successful provider-specific
428
+ report separately. For Cloudflare, success requires an external HTTP 200 with
429
+ the expected page marker, not merely a returned Quick Tunnel hostname.
430
+
431
+ ## Failure and interruption recovery
432
+
433
+ `sandbox run` handles ordinary exceptions, remote non-zero exits, `SIGINT`, and
434
+ `SIGTERM` by attempting termination before it exits. `SIGKILL`, machine loss, or
435
+ a network partition cannot run local cleanup.
436
+
437
+ After an uncertain interruption:
438
+
439
+ ```bash
440
+ npx xapi-to sandbox list --format table
441
+ npx xapi-to sandbox get <suspected-id>
442
+ npx xapi-to sandbox terminate <suspected-id> --wait-timeout 5m
443
+ ```
444
+
445
+ If terminate returns a state-change conflict, inspect state and retry after the
446
+ in-flight transition finishes. Do not treat an accepted operation response as
447
+ completion; wait for the instance's observed terminal state.
448
+
449
+ ## AI operating rules
450
+
451
+ When exposing Sandbox to an AI agent:
452
+
453
+ 1. Inject the xAPI key in the tool execution layer; never place it in prompts,
454
+ files, environment dumps, remote commands, logs, or model-visible output.
455
+ 2. Start with `offerings`/`quote` when selection or budget is uncertain.
456
+ 3. Prefer `sandbox run` for one-shot work and granular primitives only when the
457
+ task needs persistent state across calls.
458
+ 4. Set capabilities and a price ceiling narrowly enough for the task.
459
+ 5. Use `--background` only when the selected Offering declares
460
+ `backgroundExec`; then verify the listening port independently.
461
+ 6. Treat instance IDs as cleanup obligations and keep them in structured state.
462
+ 7. Put termination in `finally`; on interruption, enumerate and reconcile any
463
+ uncertain instances.
464
+ 8. Report stdout, exit code, final state, cost, and cleanup outcome separately.
465
+ 9. Never claim success from page/API structure alone—execute the relevant path,
466
+ verify its artifact or public URL, then check audit and residual instances.
@@ -0,0 +1,124 @@
1
+ # Serper Guide
2
+
3
+ Use the direct `serper.*` API actions when the task needs provider-native
4
+ Google results, several searches in one mini-batch, or Serper surfaces that the
5
+ built-in `web.search.*` capabilities do not expose. For a simple single search
6
+ with a normalized xAPI response, prefer `web.search.*` and read
7
+ `google_search.md` instead.
8
+
9
+ The current `serper` service exposes 12 v7 actions. They are third-party API
10
+ actions, so parameters go inside `body`:
11
+
12
+ ```bash
13
+ npx xapi-to get serper.search
14
+ npx xapi-to call serper.search --input '{"body":{"q":"OpenAI","gl":"us","hl":"en"}}'
15
+ ```
16
+
17
+ Run `get` before relying on optional parameters or response fields. Serper
18
+ responses are passed through in provider-native form and can gain fields that
19
+ are not declared in the xAPI output schema.
20
+
21
+ ## Mini-batch
22
+
23
+ Eleven actions accept either one request object or an array of request objects
24
+ in `body`. The response is respectively one result object or an array of result
25
+ objects in request order:
26
+
27
+ ```bash
28
+ npx xapi-to call serper.search --input \
29
+ '{"body":[{"q":"OpenAI","gl":"us","hl":"en"},{"q":"Cloudflare","gl":"us","hl":"en"}]}'
30
+ ```
31
+
32
+ Each array member has the same shape as a single request. Do not wrap the
33
+ members in `queries`, and do not confuse this with `xapi-to get-batch`, which
34
+ retrieves several Action schemas without executing them.
35
+
36
+ `serper.reviews` is the only current `serper.*` action that does not support
37
+ mini-batch. Send exactly one object in its `body`.
38
+
39
+ ## Billing
40
+
41
+ All 12 actions use dynamic xAPI billing at **$0.002 per Serper credit**. For a
42
+ single request, the charge is `response.credits * $0.002`; for a mini-batch it
43
+ is `sum(response[*].credits) * $0.002`.
44
+
45
+ The `cost: 0` placeholder shown in discovery output does not mean the call is
46
+ free; dynamic prices are not comparable as a fixed per-call price. Inspect the
47
+ Action's `meta.description` and `meta.pricing`, and keep returned `credits` when
48
+ auditing usage.
49
+
50
+ ## Current Actions
51
+
52
+ | Action | Use it for | Primary input |
53
+ |---|---|---|
54
+ | `serper.search` | General Google web results | `q` |
55
+ | `serper.images` | Google Images; current schema accepts `num` 10 or 100 | `q` |
56
+ | `serper.news` | Google News results | `q` |
57
+ | `serper.videos` | Google video results | `q` |
58
+ | `serper.shopping` | Product and shopping results | `q` |
59
+ | `serper.scholar` | Academic publications and citations | `q` |
60
+ | `serper.patents` | Patent search | `q` |
61
+ | `serper.autocomplete` | Suggestions for a partial query | `q` |
62
+ | `serper.places` | Local businesses and place search | `q` |
63
+ | `serper.maps` | Map search or lookup by Google Place ID/CID | `q`, `placeId`, or `cid` |
64
+ | `serper.lens` | Reverse image search from a public image URL | `url` |
65
+ | `serper.reviews` | Place reviews and cursor pagination | `placeId`, `cid`, or `fid` |
66
+
67
+ The common search-family controls are `gl`, `hl`, `location`, `page`, `num`,
68
+ `tbs`, and `autocorrect`, but not every action exposes every control. Use the
69
+ current `get` schema instead of copying parameters between actions.
70
+
71
+ ## Focused Examples
72
+
73
+ ### News with a Google time filter
74
+
75
+ ```bash
76
+ npx xapi-to call serper.news --input \
77
+ '{"body":{"q":"AI regulation","gl":"us","hl":"en","tbs":"qdr:d"}}'
78
+ ```
79
+
80
+ ### Maps by coordinates
81
+
82
+ ```bash
83
+ npx xapi-to call serper.maps --input \
84
+ '{"body":{"q":"coffee","ll":"@40.7455096,-74.0083012,14z","hl":"en"}}'
85
+ ```
86
+
87
+ Use `placeId` or `cid` instead of `q` when resolving a known Google place.
88
+
89
+ ### Google Lens
90
+
91
+ ```bash
92
+ npx xapi-to call serper.lens --input \
93
+ '{"body":{"url":"https://example.com/public-image.jpg","gl":"us","hl":"en"}}'
94
+ ```
95
+
96
+ The image must be reachable through a public URL; a local filesystem path is
97
+ not a valid Lens input.
98
+
99
+ ### Reviews and pagination
100
+
101
+ ```bash
102
+ # First page; body must be an object, not an array
103
+ npx xapi-to call serper.reviews --input \
104
+ '{"body":{"placeId":"ChIJ...","sortBy":"newest","gl":"us","hl":"en"}}'
105
+
106
+ # Continue with the provider's cursor
107
+ npx xapi-to call serper.reviews --input \
108
+ '{"body":{"placeId":"ChIJ...","nextPageToken":"<token>","sortBy":"newest","gl":"us","hl":"en"}}'
109
+ ```
110
+
111
+ Current `sortBy` values are `mostRelevant`, `newest`, `highestRating`, and
112
+ `lowestRating`.
113
+
114
+ ## Service Boundary
115
+
116
+ Serper's upstream product also advertises webpage extraction, but the current
117
+ xAPI service directory exposes only the 12 `serper.*` actions above. Do not
118
+ invent or call `serper.webpage`. Search the live registry first; if a Webpage
119
+ Action is added later, use its own discovered Action ID and schema because the
120
+ upstream scraper is a separate surface from Google search.
121
+
122
+ For provider details that are not exposed by `xapi-to get`, consult the current
123
+ official Serper documentation at <https://serper.dev/>. xAPI's `body` wrapper,
124
+ Action IDs, and billing metadata remain authoritative for calls through xAPI.