xapi-to 0.1.20 → 0.1.22

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,228 @@
1
+ # Provider service management
2
+
3
+ Read this guide for provider-side service authoring and operations. These
4
+ commands use `XAPI-KEY` directly and never exchange it for a broad JWT session.
5
+ The key must belong to the service owner and carry the scope named by the
6
+ operation.
7
+
8
+ ## Inspect capabilities and scopes
9
+
10
+ ```bash
11
+ npx xapi-to provider --help
12
+ npx xapi-to skill --help
13
+ npx xapi-to skill spec
14
+ ```
15
+
16
+ Use narrowly scoped keys. Common scopes are:
17
+
18
+ - `service:create`, `service:read`, `service:update`
19
+ - `version:create`, `service:publish`, `service:rollback`
20
+ - `observability:read`
21
+ - `skill:read`, `skill:submit`
22
+ - `earnings:read`; `earnings:transfer` only when reinvestment is intended
23
+ - `service:delete` only for deliberate removal workflows
24
+
25
+ Scope permission and ownership are independent. A key with a scope still cannot
26
+ manage another provider's service or Skill.
27
+
28
+ ## Create and describe a service
29
+
30
+ Create uses the backend service DTO as JSON so credentials and endpoint
31
+ contracts do not have to appear in shell history:
32
+
33
+ ```bash
34
+ npx xapi-to provider create --file ./service.json
35
+ npx xapi-to provider list
36
+ npx xapi-to provider get <service-id>
37
+ ```
38
+
39
+ Keep the three service content layers distinct:
40
+
41
+ - `description` is the short marketplace-card summary.
42
+ - `aboutMarkdown` is the long About tab.
43
+ - `website` is a public HTTP(S) link.
44
+
45
+ Prefer files for long text:
46
+
47
+ ```bash
48
+ npx xapi-to provider update <service-id> \
49
+ --description "Short marketplace summary" \
50
+ --about-file ./ABOUT.md \
51
+ --website https://example.com
52
+ ```
53
+
54
+ Use `--clear-about` or `--clear-website` to clear a value. Provider metadata
55
+ updates cannot modify the version contract or upstream credentials; use the
56
+ version command for those fields.
57
+
58
+ ## Configure a service request limit
59
+
60
+ Rate limits are optional service settings. Configure both values together when
61
+ creating a service or updating an existing one:
62
+
63
+ ```bash
64
+ npx xapi-to provider create --file ./service.json \
65
+ --rate-limit-requests 100 \
66
+ --rate-limit-period-seconds 60
67
+
68
+ npx xapi-to provider update <service-id> \
69
+ --rate-limit-requests 100 \
70
+ --rate-limit-period-seconds 60
71
+ ```
72
+
73
+ `requests` accepts 1 through 1,000,000 and `periodSeconds` accepts 1 through
74
+ 86,400. The backend applies one quota to each User x Service pair, so all API keys
75
+ owned by the same user share that service quota. This setting is supported only
76
+ for `PROXY` services; the backend rejects a non-null limit for `DIRECT` services.
77
+
78
+ Disable the limit explicitly with:
79
+
80
+ ```bash
81
+ npx xapi-to provider update <service-id> --clear-rate-limit
82
+ ```
83
+
84
+ This sends `rateLimitConfig: null`. Omitting the rate-limit flags during an
85
+ update leaves the existing setting unchanged. A raw `rateLimitConfig` can also
86
+ be included in `service.json`; explicit CLI rate-limit flags override that field.
87
+
88
+ ## Edit and publish a revision
89
+
90
+ ```bash
91
+ # Inspect current majors and revisions
92
+ npx xapi-to provider versions <service-id>
93
+
94
+ # Either create a new major or pull a working revision from an existing major
95
+ npx xapi-to provider major create <service-id>
96
+ npx xapi-to provider revision start <service-id> <major>
97
+
98
+ # Merge a partial version-contract update; add --replace for full replacement
99
+ npx xapi-to provider version update \
100
+ <service-id> <version-id> --file ./contract.json
101
+
102
+ # Inspect before publishing
103
+ npx xapi-to provider diff <service-id> <major>
104
+
105
+ # Submit through the normal review gate with public release notes
106
+ npx xapi-to provider publish \
107
+ <service-id> <revision-id> --changelog-file ./CHANGELOG.md
108
+
109
+ # Inspect the review result
110
+ npx xapi-to provider review <service-id> <revision-id>
111
+ ```
112
+
113
+ The changelog is provider-authored, public release information associated with
114
+ that revision. It is not a system deployment log. Build, review, and runtime
115
+ events are generated by the platform and should only be read, never uploaded as
116
+ if they were evidence.
117
+
118
+ `publish` can change live service behavior after review. The CLI does not
119
+ automatically retry this write after an ambiguous transport failure. Read the
120
+ version overview and review state before deciding whether to submit again.
121
+
122
+ ## Create, upload, and link the usage Skill
123
+
124
+ Generate a service-specific starting point from the currently serving endpoints:
125
+
126
+ ```bash
127
+ npx xapi-to provider skill scaffold \
128
+ <service-id> --output ./my-service/SKILL.md
129
+ ```
130
+
131
+ The scaffold command refuses to overwrite an existing file unless `--force` is
132
+ explicitly supplied. Complete the instructions and metadata, then submit either
133
+ a local directory or a public GitHub tree:
134
+
135
+ ```bash
136
+ npx xapi-to skill submit --dir ./my-service
137
+
138
+ npx xapi-to skill submit \
139
+ --github https://github.com/org/repo/tree/main/skills/my-service \
140
+ --version 1.0.0
141
+ ```
142
+
143
+ Local submission skips symlinks, `.git`, and `node_modules`; requires a root
144
+ `SKILL.md`; permits at most 100 files; limits each file to 512 KiB and the encoded
145
+ package to 2 MiB. The server still performs manifest validation and secret
146
+ scanning. A successful upload creates or updates the owned Skill version and
147
+ submits it for review; it is not immediately public.
148
+
149
+ Use the returned submission ID:
150
+
151
+ ```bash
152
+ npx xapi-to skill status <submission-id>
153
+ npx xapi-to skill wait <submission-id> --timeout 10m
154
+ ```
155
+
156
+ After the Skill is published, bind it as the service's primary tutorial and
157
+ record the serving-contract fingerprint:
158
+
159
+ ```bash
160
+ npx xapi-to provider skill link <service-id> <skill-id>
161
+ npx xapi-to provider skill fingerprint \
162
+ <service-id> --skill-version-id <skill-version-id>
163
+ npx xapi-to provider skill context <service-id>
164
+ ```
165
+
166
+ Only a Skill owned by the same provider can be linked, and one Skill can be the
167
+ primary Skill of only one service. The backend permits linking a pending Skill,
168
+ but the public marketplace exposes only a published version; wait for publication
169
+ unless intentionally preparing the association early. Use `provider skill unlink`
170
+ to remove the primary association. The context response reports drift when host,
171
+ major version, or serving endpoints no longer match the stored fingerprint; update
172
+ and resubmit the Skill rather than merely overwriting the fingerprint.
173
+
174
+ ## Observe and recover
175
+
176
+ ```bash
177
+ npx xapi-to provider metrics --days 30
178
+ npx xapi-to provider metrics <service-id> --days 7
179
+ npx xapi-to provider events --limit 50
180
+ npx xapi-to provider events --after '<opaque-next-cursor>' --limit 50
181
+ ```
182
+
183
+ Pass event cursors back unchanged. Metrics and events are owner-scoped; usage
184
+ events are also restricted to the current key where applicable.
185
+
186
+ Verify the finalized cost of a canary or provider call with its receipt ID. Use
187
+ the `X-XAPI-Request-Id` response header or the final `xapi.usage` SSE event, and
188
+ wait when asynchronous billing has not finalized yet:
189
+
190
+ ```bash
191
+ npx xapi-to usage <request-id>
192
+ npx xapi-to usage wait <request-id> --timeout 1m
193
+ ```
194
+
195
+ Receipt reads are idempotent. The wait command applies one total deadline,
196
+ retries not-found and transient transport failures within that deadline, and
197
+ fails immediately for permanent authorization or validation errors.
198
+
199
+ Rollback and default-major changes affect live routing:
200
+
201
+ ```bash
202
+ npx xapi-to provider rollback \
203
+ <service-id> <major> --revision <published-revision-id> \
204
+ --reason "Restore the last known-good contract"
205
+ npx xapi-to provider default-major <service-id> <major>
206
+ npx xapi-to provider deprecate <service-id> <major>
207
+ npx xapi-to provider restore <service-id> <major>
208
+ ```
209
+
210
+ Inspect the target revision before rollback. Do not automatically retry an
211
+ ambiguous rollback response. Deletion requires both `service:delete` and an
212
+ explicit service name or ID confirmation:
213
+
214
+ ```bash
215
+ npx xapi-to provider delete <service-id> --confirm <service-name-or-id>
216
+ ```
217
+
218
+ ## Earnings reinvestment
219
+
220
+ ```bash
221
+ npx xapi-to earnings
222
+ npx xapi-to earnings list --status SETTLED
223
+ npx xapi-to earnings transfer 1 --idempotency-key <stable-operation-key>
224
+ ```
225
+
226
+ Transfer is one-way: it converts settled provider earnings into spendable xAPI
227
+ balance. Confirm the amount and available settled balance first. A transfer may
228
+ be retried only with the same idempotency key and the same amount.
@@ -7,32 +7,45 @@ not an ordinary per-call action, so cleanup and audit are part of task success.
7
7
 
8
8
  ## Contents
9
9
 
10
+ - [Product boundary](#product-boundary)
10
11
  - [Choose the shortest safe lifecycle](#choose-the-shortest-safe-lifecycle)
11
12
  - [Authentication and gateway selection](#authentication-and-gateway-selection)
12
13
  - [Inspect offerings and quote first](#inspect-offerings-and-quote-first)
13
14
  - [One-shot execution](#one-shot-execution)
14
- - [Multi-step agent lifecycle](#multi-step-agent-lifecycle)
15
+ - [Multi-step client lifecycle](#multi-step-client-lifecycle)
15
16
  - [Files and artifacts](#files-and-artifacts)
16
17
  - [Web preview and background processes](#web-preview-and-background-processes)
17
18
  - [Suspend and resume](#suspend-and-resume)
18
19
  - [GPU jobs](#gpu-jobs)
19
- - [Parallel agents](#parallel-agents)
20
- - [OpenAI SandboxAgent with xAPI DeepSeek](#openai-sandboxagent-with-xapi-deepseek)
20
+ - [Parallel isolated instances](#parallel-isolated-instances)
21
+ - [OpenAI SandboxAgent integration example](#openai-sandboxagent-integration-example)
21
22
  - [Audit, history, and billing](#audit-history-and-billing)
22
- - [Run the real Playground acceptance suite](#run-the-real-playground-acceptance-suite)
23
+ - [Run the real Playground recipe acceptance suite](#run-the-real-playground-recipe-acceptance-suite)
23
24
  - [Failure and interruption recovery](#failure-and-interruption-recovery)
24
25
  - [AI operating rules](#ai-operating-rules)
25
26
 
27
+ ## Product boundary
28
+
29
+ xAPI is the Sandbox resource and capability provider. The CLI is a thin client
30
+ for discovery, quote, lifecycle, exec, files, ports, provider extensions,
31
+ history, audit, and billing. It does not implement prompts, model loops, memory,
32
+ multi-agent orchestration, job DAGs, queues, or human approval workflows.
33
+
34
+ Agent, CI, browser, and data examples in this guide are client-side recipes that
35
+ compose Sandbox primitives. They are not additional Gateway workflow APIs.
36
+ Provider-native features remain valid Sandbox extensions when the live Offering
37
+ declares their schemas, limits, state effects, and billing behavior.
38
+
26
39
  ## Choose the shortest safe lifecycle
27
40
 
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 |
41
+ | Need | Preferred command | Cleanup behavior |
42
+ | ------------------------------ | ------------------------------ | ------------------------ |
43
+ | Run one command and get stdout | `sandbox run` | Terminates automatically |
44
+ | Several exec/file calls | `create` + primitives | Agent must terminate |
45
+ | Inspect price/capabilities | `offerings`, `quote` | No instance created |
46
+ | Publish a temporary port | `port` after starting a server | Terminate afterward |
47
+ | Pause a reusable workspace | `suspend` | Storage may keep billing |
48
+ | Inspect prior work/cost | `history`, `get`, `audit` | Read-only |
36
49
 
37
50
  Prefer `sandbox run` whenever the task fits one remote shell command. A shorter
38
51
  lifecycle reduces orphan risk and returns one machine-readable JSON result.
@@ -79,6 +92,7 @@ npx xapi-to sandbox quote \
79
92
  --capabilities exec,files \
80
93
  --cpu 2 \
81
94
  --memory 4 \
95
+ --min-runtime 24h \
82
96
  --max-hourly-usd 0.20 \
83
97
  --format pretty
84
98
  ```
@@ -121,9 +135,9 @@ shells and AI runners can detect failure without parsing stdout.
121
135
  `--keep` suppresses automatic termination. Use it only after the user explicitly
122
136
  asks to retain the instance and understands that billing continues.
123
137
 
124
- ## Multi-step agent lifecycle
138
+ ## Multi-step client lifecycle
125
139
 
126
- Use granular commands when an agent must alternate between files and commands.
140
+ Use granular commands when a client must alternate between files and commands.
127
141
  Capture the instance ID without logging credentials:
128
142
 
129
143
  ```bash
@@ -205,15 +219,17 @@ port response contains `headers`, include them in external requests; they can
205
219
  carry a provider preview token. Do not emulate this mode with `nohup ... &` on
206
220
  an Offering that does not declare `backgroundExec`.
207
221
 
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:
222
+ Cloudflare declares the standard background command surface and maps it to its
223
+ native managed process API. Pin `cf-edge` only when the user explicitly wants
224
+ Cloudflare. For a one-day workspace, require `--min-runtime 24h` and explicitly
225
+ enable `cloudflare.set_keep_alive`; the runtime requirement filters offerings,
226
+ while keepAlive prevents the default ten-minute idle reset:
212
227
 
213
228
  ```bash
214
229
  box_json="$(npx xapi-to sandbox create \
215
230
  --provider cf-edge \
216
- --capabilities exec,files,ports \
231
+ --capabilities exec,backgroundExec,files,ports,lifecycle.keep_alive \
232
+ --min-runtime 24h \
217
233
  --wait)"
218
234
  box_id="$(printf '%s' "$box_json" | jq -r '.id')"
219
235
  port=8080
@@ -225,11 +241,11 @@ npx xapi-to sandbox file write "$box_id" index.html \
225
241
  --provider cf-edge \
226
242
  --content '<!doctype html><h1>xAPI preview</h1>'
227
243
 
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"
244
+ npx xapi-to sandbox extension "$box_id" cloudflare.set_keep_alive \
245
+ --provider cf-edge --input '{"keepAlive":true}'
246
+
247
+ npx xapi-to sandbox exec "$box_id" --provider cf-edge --background --command \
248
+ "python3 -m http.server $port --directory /workspace"
233
249
 
234
250
  npx xapi-to sandbox port "$box_id" "$port" --provider cf-edge
235
251
  ```
@@ -242,6 +258,37 @@ terminate instead of leaving the instance billing. The URL stops working after
242
258
  termination. Quick Tunnels are for previews; use a stable, supported named
243
259
  tunnel or application deployment for production traffic.
244
260
 
261
+ Cloudflare extensions also expose managed process logs/readiness, persistent
262
+ shell sessions, stateful Python/JavaScript/TypeScript code contexts, Git
263
+ checkout, file-change cursors, bucket mounts, and R2 backup/restore. Inspect
264
+ `capabilities.extensionIds` before calling them. A default idle reset starts a
265
+ fresh container and does not retain files, processes, sessions, or interpreter
266
+ state. `keepAlive` removes that idle cutoff but does not guarantee that platform
267
+ maintenance can never restart the host. Use R2 backup or external storage for
268
+ state that must survive restarts, disable keepAlive in `finally`, and terminate.
269
+
270
+ If the Offering declares `cloudflare.browser.*`, Cloudflare Browser Run can be
271
+ used through the same generic extension command. Prefer a Quick Action for
272
+ read-only page understanding before paying for a multi-step browser session:
273
+
274
+ ```bash
275
+ npx xapi-to sandbox extension "$box_id" cloudflare.browser.snapshot \
276
+ --provider cf-edge \
277
+ --input '{"url":"https://example.com/","formats":["screenshot","markdown","accessibilityTree"]}'
278
+
279
+ npx xapi-to sandbox extension "$box_id" cloudflare.browser.automate \
280
+ --provider cf-edge \
281
+ --input '{"url":"https://demo.playwright.dev/todomvc/","actions":[{"type":"fill","selector":".new-todo","value":"xAPI task"},{"type":"press","selector":".new-todo","key":"Enter"}],"extract":[{"name":"todos","selector":".todo-list li label","all":true}],"screenshot":{"type":"png","fullPage":true}}'
282
+ ```
283
+
284
+ Browser Run and the Sandbox container do not share a filesystem. Write the
285
+ returned page data into the sandbox through `sandbox file write` if a later
286
+ container command must analyze it. Browser operations have separate operation
287
+ prices; inspect the quote instead of assuming the container hourly cap includes
288
+ them. The current automation extension is one-shot and closes the browser.
289
+ Persistent CDP/Live View/HITL are not supported until xAPI owns and authorizes
290
+ the session and proxies its WebSocket without exposing Cloudflare credentials.
291
+
245
292
  ## Suspend and resume
246
293
 
247
294
  Check offering lifecycle fields first because not every provider supports an
@@ -290,58 +337,65 @@ npx xapi-to sandbox terminate <id> --provider runpod
290
337
  GPU work is usually more expensive. Quote first, set a deliberate ceiling, use
291
338
  a command timeout, and terminate immediately after artifacts are retrieved.
292
339
 
293
- ## Parallel agents
340
+ ## Parallel isolated instances
294
341
 
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.
342
+ Give each concurrent worker or agent a separate instance. Do not share a mutable
343
+ workspace when the goal is isolation. Use unique idempotency keys and record every instance ID.
297
344
  Run cleanup for all IDs even if one agent fails; then verify `sandbox list` has
298
345
  no active instance from the job.
299
346
 
300
347
  Limit concurrency based on budget. Parallel creation multiplies reservation and
301
348
  running cost, even when the individual hourly quote is small.
302
349
 
303
- ## OpenAI SandboxAgent with xAPI DeepSeek
350
+ ## OpenAI SandboxAgent integration example
304
351
 
305
352
  The OpenAI Agents SDK keeps the model provider and sandbox provider separate.
306
353
  Use the SDK's OpenAI-compatible model provider for DeepSeek through
307
354
  `https://ai.xapi.to/v1`, and the xAPI adapter for Sandbox compute:
308
355
 
356
+ The Agents SDK owns the model loop, tool choice, prompt, and conversation state.
357
+ xAPI owns only the Sandbox resource, execution, lifecycle, audit, and billing.
358
+
309
359
  ```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';
360
+ import { OpenAIProvider, Runner } from "@openai/agents";
361
+ import { Manifest, SandboxAgent, shell } from "@openai/agents/sandbox";
362
+ import { XapiAgentsSandboxClient } from "xapi-to/openai-sandbox";
313
363
 
314
364
  const sandboxApiKey = process.env.XAPI_SANDBOX_KEY;
315
365
  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');
366
+ if (!sandboxApiKey) throw new Error("XAPI_SANDBOX_KEY is required");
367
+ if (!aiApiKey) throw new Error("XAPI_AI_KEY is required");
318
368
 
319
369
  const sandbox = new XapiAgentsSandboxClient({
320
370
  apiKey: sandboxApiKey,
321
- sandboxHost: 'sandbox.test.xapi.to',
322
- provider: 'daytona',
323
- model: 'deepseek-v4-pro',
371
+ sandboxHost: "sandbox.test.xapi.to",
372
+ provider: "daytona",
373
+ model: "deepseek-v4-pro",
324
374
  });
325
375
  const modelProvider = new OpenAIProvider({
326
376
  apiKey: aiApiKey,
327
- baseURL: 'https://ai.xapi.to/v1',
377
+ baseURL: "https://ai.xapi.to/v1",
328
378
  useResponses: false,
329
379
  strictFeatureValidation: true,
330
380
  });
331
381
  const runner = new Runner({ modelProvider, tracingDisabled: true });
332
382
  const agent = new SandboxAgent({
333
- name: 'xAPI DeepSeek sandbox agent',
334
- model: 'deepseek-v4-pro',
383
+ name: "xAPI DeepSeek sandbox agent",
384
+ model: "deepseek-v4-pro",
335
385
  defaultManifest: new Manifest({ root: sandbox.workspaceRoot }),
336
386
  capabilities: [shell()],
337
- instructions: 'Use shell to complete and verify the task.',
387
+ instructions: "Use shell to complete and verify the task.",
338
388
  });
339
389
 
340
390
  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
- });
391
+ const result = await runner.run(
392
+ agent,
393
+ "Write SDK_OK=42 to result.txt and read it.",
394
+ {
395
+ maxTurns: 8,
396
+ sandbox: { client: sandbox },
397
+ },
398
+ );
345
399
  console.log(result.finalOutput);
346
400
  } finally {
347
401
  await sandbox.lastSession?.close();
@@ -406,9 +460,9 @@ For acceptance, verify:
406
460
 
407
461
  Use the returned billing data rather than recomputing cost from wall-clock time.
408
462
 
409
- ## Run the real Playground acceptance suite
463
+ ## Run the real Playground recipe acceptance suite
410
464
 
411
- From an xapi-cli development checkout, run the same nine real workflows shown
465
+ From an xapi-cli development checkout, run the same nine client recipes shown
412
466
  in the Web Playground. The suite uses normal CLI configuration, never accepts a
413
467
  key on argv, records audit/billing evidence, terminates every tracked instance
414
468
  in `finally`, and fails if any instance created after its baseline remains
@@ -1,6 +1,6 @@
1
1
  # WebSocket Gateway Guide
2
2
 
3
- Use xAPI's WebSocket Gateway for full-duplex, low-latency sessions such as OpenAI Realtime, streaming speech recognition, bidirectional text-to-speech, simultaneous interpretation, and podcast generation.
3
+ Use xAPI's WebSocket Gateway for full-duplex, low-latency sessions such as GPT Live, OpenAI Realtime, streaming speech recognition, bidirectional text-to-speech, simultaneous interpretation, and podcast generation.
4
4
 
5
5
  The WebSocket Gateway shares the public `ai.xapi.to` host with the HTTP AI Gateway, but it is a separate protocol surface. An HTTP request continues to use the AI Gateway; a valid WebSocket Upgrade request is routed to the WebSocket Gateway.
6
6
 
@@ -9,6 +9,7 @@ The WebSocket Gateway shares the public `ai.xapi.to` host with the HTTP AI Gatew
9
9
  - [Choose the right interface](#choose-the-right-interface)
10
10
  - [Public URLs and routing](#public-urls-and-routing)
11
11
  - [Authentication](#authentication)
12
+ - [GPT Live example](#gpt-live-example)
12
13
  - [OpenAI Realtime example](#openai-realtime-example)
13
14
  - [Browser connections](#browser-connections)
14
15
  - [Native protocol endpoints](#native-protocol-endpoints)
@@ -39,6 +40,7 @@ Current curated production paths include:
39
40
 
40
41
  | Path | Protocol | Typical use |
41
42
  |---|---|---|
43
+ | `/v1/live/sessions` on the GPT Live service host | OpenAI Live Sessions JSON events | GPT-Live 1 voice with Client or managed Responses delegation |
42
44
  | `/v1/realtime` | OpenAI Realtime GA JSON events | Realtime text and voice |
43
45
  | `/v1/asr` | Volcengine ASR binary frames | Streaming speech recognition |
44
46
  | `/v1/tts` | Doubao bidirectional TTS binary frames | Streaming text-to-speech |
@@ -57,6 +59,15 @@ wss://<service-slug>.p.xapi.to/<endpoint-path>
57
59
 
58
60
  This avoids shared-path ambiguity and is required when the desired service uses a provider-native protocol that is not selected by the unified path. Console Try-It and review workflows can also address an endpoint exactly with `?endpoint=<endpoint-id>`.
59
61
 
62
+ GPT Live currently uses the service-specific URL:
63
+
64
+ ```text
65
+ wss://openai-live.p.xapi.to/v1/live/sessions
66
+ ```
67
+
68
+ Do not replace it with `/v1/realtime`. Live Sessions uses `session.start` and
69
+ `session.started`; Realtime uses a different session lifecycle and event model.
70
+
60
71
  ## Authentication
61
72
 
62
73
  Use the same xAPI key as the CLI and HTTP Gateway. Server-side clients should send one of these handshake headers:
@@ -78,6 +89,43 @@ The Gateway also accepts `?token=<XAPI_KEY>` or `?xapi-key=<XAPI_KEY>` for clien
78
89
 
79
90
  Authentication is checked before the WebSocket upgrade. Invalid handshakes therefore return an HTTP status instead of opening and immediately closing a socket.
80
91
 
92
+ ## GPT Live example
93
+
94
+ GPT Live is a provider-native JSON event protocol, not an Action `call` and not
95
+ OpenAI Realtime. The first client frame must be `session.start`. The production
96
+ endpoint locks the Live model to `gpt-live-1`, disables storage, and lets the
97
+ caller choose `client` or `responses` delegation once per connection. In
98
+ `responses` mode, the managed Responses model and its limits remain
99
+ server-controlled.
100
+
101
+ The packaged `examples/openai-gpt-live-text.mjs` demonstrates the smallest
102
+ managed-Responses lifecycle: connect with a server-side xAPI key, send
103
+ `session.start`, wait for `session.started`, create a text item, request a
104
+ response, and finish with `session.close` after the nested response completes.
105
+ It intentionally omits microphone capture so the protocol boundary is clear.
106
+
107
+ ```bash
108
+ # Install the example's WebSocket transport in your application directory.
109
+ npm install ws
110
+
111
+ # Supply XAPI_KEY through the process environment; never put it in source code
112
+ # or pass it as a command-line argument.
113
+ node examples/openai-gpt-live-text.mjs "Answer in one short sentence."
114
+ ```
115
+
116
+ Voice clients use the same session lifecycle, then send base64 PCM chunks as
117
+ `session.input_audio.append` events and consume `session.output_audio.delta`.
118
+ Audio format, voice, interruption behavior, and the complete event schema must
119
+ follow the current Live Sessions contract. Do not copy Realtime
120
+ `conversation.item.create` or `input_audio_buffer.*` events into a Live session.
121
+
122
+ With `client` delegation, the application must handle
123
+ `session.delegation.created`, run its own text-model request, and return the
124
+ result with `session.commentary.append`, then wait for
125
+ `session.commentary.appended`. Selecting `client` does not make xAPI run a
126
+ model on the application's behalf. Use `responses` when the managed backend is
127
+ desired.
128
+
81
129
  ## OpenAI Realtime example
82
130
 
83
131
  The unified `/v1/realtime` route speaks the OpenAI Realtime GA JSON event protocol. It is native passthrough: send the same events you would send to the upstream Realtime API, but authenticate with the xAPI key.
@@ -121,15 +169,26 @@ Do not send the retired `OpenAI-Beta: realtime=v1` header. Session settings, aud
121
169
  The browser `WebSocket` API cannot set arbitrary handshake headers. The Gateway accepts an xAPI key or temporary token through a subprotocol entry:
122
170
 
123
171
  ```javascript
124
- const temporaryToken = await getTemporaryTokenFromYourBackend();
172
+ const credential = await getEndpointBoundCredentialFromYourBackend(endpointId);
173
+ if (Date.now() >= new Date(credential.latestStartAt).getTime()) {
174
+ throw new Error("refresh the credential before opening a full new session");
175
+ }
125
176
  const ws = new WebSocket(
126
- "wss://ai.xapi.to/v1/realtime",
127
- [`xapi-key.${temporaryToken}`],
177
+ "wss://openai-live.p.xapi.to/v1/live/sessions",
178
+ ["xapi-ws-v1", `xapi-key.${credential.token}`],
128
179
  );
129
180
  ```
130
181
 
131
182
  Never embed a long-lived xAPI key in frontend JavaScript. Use the authenticated xAPI Console Try-It flow or your backend to obtain a short-lived token, then pass only that token to the browser. The Console's `POST /api/keys/ws-token` flow mints a temporary token for a WebSocket endpoint; it requires a logged-in entity account and an endpoint ID, and is not authenticated with a normal xAPI key.
132
183
 
184
+ The credential is endpoint-bound and returns `expiresAt`, `latestStartAt`, and
185
+ `maxDurationSec`. It may be reused for reconnects only while the new connection
186
+ starts before `latestStartAt`; after that boundary, mint a fresh credential so
187
+ the full advertised session and final `session.close` exchange fit inside its
188
+ lifetime. If an endpoint declares public subprotocols, retain them and append
189
+ the `xapi-key.*` entry; otherwise use the non-secret `xapi-ws-v1` marker shown
190
+ above. Never log the secret subprotocol value.
191
+
133
192
  If a browser integration must use `?token=`, use only a short-lived token and avoid logging the complete URL.
134
193
 
135
194
  ## Native protocol endpoints
@@ -138,6 +197,7 @@ The Gateway forwards frames without translating the application protocol. The se
138
197
 
139
198
  | Adapter | Client frames | Important client requirement |
140
199
  |---|---|---|
200
+ | `openai-live` | UTF-8 JSON text | First frame is `session.start`; choose Client or managed Responses delegation once. |
141
201
  | `openai-realtime` | UTF-8 JSON text | Use OpenAI Realtime GA events. |
142
202
  | `volcengine-asr` | Binary | Send the Volcengine ASR header/config/audio frame sequence; PCM configuration must match the audio bytes. |
143
203
  | `doubao-realtime` | Binary | Use the Doubao end-to-end realtime dialogue protocol through its service host or exact endpoint. |