ql-agent-sdk 1.0.2 → 1.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 +169 -1
- package/dist/index.cjs +160 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +331 -8
- package/dist/index.d.ts +331 -8
- package/dist/index.js +160 -26
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -74,7 +74,7 @@ Create keys in your Quanton Labs dashboard → **API Keys** page. Each key is sc
|
|
|
74
74
|
|
|
75
75
|
| Scope | Grants access to |
|
|
76
76
|
|-------|-----------------|
|
|
77
|
-
| `workspace` | `ql.workspace.get()` |
|
|
77
|
+
| `workspace` | `ql.workspace.get()`, `ql.workspace.getModels()`, `ql.workspace.update()`, `ql.workspace.updateModels()`, `ql.workspace.listCatalogModels()`, `ql.workspace.verifyOpenRouterKey()`, `ql.workspace.listKeys()` |
|
|
78
78
|
| `agents` | `ql.agents.list()`, `ql.agents.get()` |
|
|
79
79
|
| `capabilities` | `ql.agents.capabilities()`, `ql.agents.runCapability()` |
|
|
80
80
|
| `chat` | `ql.agents.chat()`, `ql.agents.chatStream()` |
|
|
@@ -133,6 +133,53 @@ ws.plan; // "standard" | "premium" | "enterprise" | undefined
|
|
|
133
133
|
ws.createdAt; // string (ISO 8601)
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
#### `ql.workspace.getModels()` → `Promise<WorkspaceModelsResult>`
|
|
137
|
+
|
|
138
|
+
**Scope:** `workspace`
|
|
139
|
+
|
|
140
|
+
Returns the per-role model configuration (director panel): defaults for
|
|
141
|
+
`reasoning`, `instruct`, `response`, `vision`, `image`, `video` plus ordered
|
|
142
|
+
fallback lists. The OpenRouter key is always masked (`keyMasked`).
|
|
143
|
+
|
|
144
|
+
#### `ql.workspace.update(input)` / `ql.workspace.updateModels(input)` → `Promise<Workspace>`
|
|
145
|
+
|
|
146
|
+
**Scope:** `workspace`
|
|
147
|
+
|
|
148
|
+
Partially updates the workspace. `update()` accepts `{ name?, config?: { openrouter? } }`;
|
|
149
|
+
`updateModels()` is a shortcut that only touches `config.openrouter`. Model fields may be
|
|
150
|
+
set to `""` to clear a default; each `fallbacks.<role>` list holds at most 3 model ids.
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
await ql.workspace.update({ name: "Robinson Mfg. Co., Inc." });
|
|
154
|
+
await ql.workspace.updateModels({
|
|
155
|
+
reasoning: "deepseek/deepseek-v4-flash-0731",
|
|
156
|
+
vision: "anthropic/claude-sonnet-5.5",
|
|
157
|
+
fallbacks: { reasoning: ["openai/gpt-oss-20b"] },
|
|
158
|
+
});
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
#### `ql.workspace.listCatalogModels()` → `Promise<CatalogResult>`
|
|
162
|
+
|
|
163
|
+
**Scope:** `workspace`
|
|
164
|
+
|
|
165
|
+
OpenRouter model catalog (`{ id, name, contextLength, promptPrice, completionPrice }[]`),
|
|
166
|
+
cached server-side for 10 minutes. May return `stale: true` when upstream is down.
|
|
167
|
+
|
|
168
|
+
#### `ql.workspace.verifyOpenRouterKey(key, model?, baseUrl?)` → `Promise<VerifyKeyResult>`
|
|
169
|
+
|
|
170
|
+
**Scope:** `workspace`
|
|
171
|
+
|
|
172
|
+
Checks an OpenRouter key with a 1-token completion (default model
|
|
173
|
+
`openai/gpt-oss-20b`). Returns `{ valid: true }` or `{ valid: false, error }`.
|
|
174
|
+
|
|
175
|
+
#### `ql.workspace.listKeys()` → `Promise<KeysResult>`
|
|
176
|
+
|
|
177
|
+
**Scope:** `workspace`
|
|
178
|
+
|
|
179
|
+
Lists the workspace's v1 API keys with rotation metadata. Every key is auto-deleted
|
|
180
|
+
`lifetimeDays` (90) days after creation; `rotatesAt`/`daysLeft` show time remaining.
|
|
181
|
+
Mint replacements from the Quanton Labs site when one expires.
|
|
182
|
+
|
|
136
183
|
---
|
|
137
184
|
|
|
138
185
|
### Agents
|
|
@@ -633,6 +680,127 @@ try {
|
|
|
633
680
|
|
|
634
681
|
---
|
|
635
682
|
|
|
683
|
+
### Videos (Tiered Generation)
|
|
684
|
+
|
|
685
|
+
Async video generation: submit a job, then poll until it completes. Reference images may be base64 data URLs or https URLs; reference (style) videos must be https URLs — upload local files with `ql.files.upload` first.
|
|
686
|
+
|
|
687
|
+
#### `ql.videos.listModels()` → `Promise<VideoModelsResult>`
|
|
688
|
+
|
|
689
|
+
Lists the tiered video models plus runtime engine availability: `{ models: VideoModelInfo[], engine: { available, detail } }`. Each model reports its tier, supported aspect ratios/resolutions, duration range, reference-image/video limits, voiceover support, and pricing.
|
|
690
|
+
|
|
691
|
+
**Example:**
|
|
692
|
+
```ts
|
|
693
|
+
const { models, engine } = await ql.videos.listModels();
|
|
694
|
+
if (!engine.available) console.warn("Video engine unavailable:", engine.detail);
|
|
695
|
+
const recommended = models.find((m) => m.recommended && m.available);
|
|
696
|
+
```
|
|
697
|
+
|
|
698
|
+
#### `ql.videos.generate(agentId, input)` → `Promise<VideoTaskCreated>`
|
|
699
|
+
|
|
700
|
+
Starts a video job (HTTP 202) and returns `{ taskId, status: "queued" }`.
|
|
701
|
+
|
|
702
|
+
| Field | Description |
|
|
703
|
+
|-------|-------------|
|
|
704
|
+
| `prompt` | The creative brief / script for the video |
|
|
705
|
+
| `model`? | Explicit registry model id (wins over `tier`) |
|
|
706
|
+
| `tier`? | Tier to resolve a model from when `model` is omitted |
|
|
707
|
+
| `images_list`? | Product/reference images — base64 data URLs or https URLs (order defines IMG_0..N) |
|
|
708
|
+
| `video_files`? | Reference (style) videos — https URLs only |
|
|
709
|
+
| `aspect_ratio`? | e.g. `"16:9"`, `"9:16"`, `"1:1"` (default `"16:9"`) |
|
|
710
|
+
| `duration`? | Seconds, within the model's `durationRange` |
|
|
711
|
+
| `resolution`? | e.g. `"720p"` / `"1080p"` (default `"720p"`) |
|
|
712
|
+
| `generate_audio`? | Bake a voiceover into the render (requires `narration`) |
|
|
713
|
+
| `narration`? | Voiceover text (max 3000 chars) |
|
|
714
|
+
|
|
715
|
+
**Example:**
|
|
716
|
+
```ts
|
|
717
|
+
const created = await ql.videos.generate("marketing", {
|
|
718
|
+
prompt: "A 10-second product reel for the new sneaker drop, studio lighting.",
|
|
719
|
+
model: "motion/reel",
|
|
720
|
+
images_list: ["data:image/png;base64,..."], // or https URLs
|
|
721
|
+
video_files: ["https://cdn.example.com/style-ref.mp4"],
|
|
722
|
+
aspect_ratio: "9:16",
|
|
723
|
+
duration: 10,
|
|
724
|
+
resolution: "1080p",
|
|
725
|
+
generate_audio: true,
|
|
726
|
+
narration: "Introducing the all-new AirFlex.",
|
|
727
|
+
});
|
|
728
|
+
```
|
|
729
|
+
|
|
730
|
+
#### `ql.videos.getTask(taskId, signal?)` → `Promise<VideoTask>`
|
|
731
|
+
|
|
732
|
+
Fetches the current job snapshot: `{ taskId, status, progress?, outputUrl?, mime?, ext?, durationSec?, error?, model?, tier?, latencyMs?, createdAt, completedAt }`.
|
|
733
|
+
|
|
734
|
+
#### `ql.videos.cancelTask(taskId)` → `Promise<VideoTask>`
|
|
735
|
+
|
|
736
|
+
Cancels a queued/rendering job and returns the updated snapshot. Throws a `QLError` with code `"conflict"` (HTTP 409) if the job is already terminal.
|
|
737
|
+
|
|
738
|
+
#### `ql.videos.handle(taskId)` → `VideoTaskHandle`
|
|
739
|
+
|
|
740
|
+
Same `poll()` / `wait(opts?)` pattern as `TaskHandle`, polling `/api/v1/video-tasks/:taskId`. Terminal statuses: `completed` (check `outputUrl`), `failed` (check `error`), `cancelled`. Wait options and non-terminal exits (`timeout` / `aborted`) are identical to tasks.
|
|
741
|
+
|
|
742
|
+
**Example:**
|
|
743
|
+
```ts
|
|
744
|
+
const done = await ql.videos.handle(created.taskId).wait({
|
|
745
|
+
intervalMs: 2000,
|
|
746
|
+
timeoutMs: 10 * 60_000,
|
|
747
|
+
onTick: (job) => {
|
|
748
|
+
if (job.progress?.message) process.stdout.write(`\r${job.progress.message}`);
|
|
749
|
+
},
|
|
750
|
+
});
|
|
751
|
+
if (done.status === "completed" && done.outputUrl) {
|
|
752
|
+
console.log("Video ready:", `${ql.baseUrl}${done.outputUrl}`);
|
|
753
|
+
}
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### Audio (Text-to-Speech)
|
|
757
|
+
|
|
758
|
+
#### `ql.audio.voices()` → `Promise<VoicesResult>`
|
|
759
|
+
|
|
760
|
+
Lists available TTS voices: `{ voices: { id, name }[], source: "live" | "none", note? }`. `source === "none"` means no provider key is configured server-side.
|
|
761
|
+
|
|
762
|
+
#### `ql.audio.textToSpeech(agentId, input)` → `Promise<TtsResult>`
|
|
763
|
+
|
|
764
|
+
Synchronous synthesis (no polling). Returns `{ url, voiceId, modelId, bytes, latencyMs }` where `url` is a served media path (e.g. `/generated/tts-….mp3`).
|
|
765
|
+
|
|
766
|
+
| Field | Description |
|
|
767
|
+
|-------|-------------|
|
|
768
|
+
| `text` | Text to synthesize (max 3000 chars) |
|
|
769
|
+
| `voiceId`? | Voice id from `ql.audio.voices()` (defaults to the platform voice) |
|
|
770
|
+
| `stability`? | Voice stability 0..1 (default 0.5) |
|
|
771
|
+
| `similarityBoost`? | Similarity boost 0..1 (default 0.75) |
|
|
772
|
+
|
|
773
|
+
**Example:**
|
|
774
|
+
```ts
|
|
775
|
+
const { voices } = await ql.audio.voices();
|
|
776
|
+
const result = await ql.audio.textToSpeech("marketing", {
|
|
777
|
+
text: "Say hello to the all-new AirFlex.",
|
|
778
|
+
voiceId: voices[0]?.id,
|
|
779
|
+
});
|
|
780
|
+
console.log(`${ql.baseUrl}${result.url}`);
|
|
781
|
+
```
|
|
782
|
+
|
|
783
|
+
### Files (Media Upload)
|
|
784
|
+
|
|
785
|
+
#### `ql.files.upload(file, opts?)` → `Promise<UploadedFile>`
|
|
786
|
+
|
|
787
|
+
Uploads a media file as multipart form data (field `"file"`) and returns `{ url, filename, size, contentType }`. The returned `url` is a stable served path (e.g. `/uploads/<workspace>/<file>`) that can be used directly as a media input URL — e.g. in `videos.generate({ video_files: [res.url] })`.
|
|
788
|
+
|
|
789
|
+
| Option | Description |
|
|
790
|
+
|--------|-------------|
|
|
791
|
+
| `filename`? | Override the stored display name (extension is kept from the file) |
|
|
792
|
+
| `onProgress`? | Coarse progress callback — fetch does not expose byte progress, so it reports 0 at start and 100 on completion only |
|
|
793
|
+
|
|
794
|
+
**Example:**
|
|
795
|
+
```ts
|
|
796
|
+
const blob = await file.arrayBuffer(); // or any Blob source
|
|
797
|
+
const uploaded = await ql.files.upload(new Blob([blob], { type: "video/mp4" }), {
|
|
798
|
+
filename: "style-ref.mp4",
|
|
799
|
+
});
|
|
800
|
+
```
|
|
801
|
+
|
|
802
|
+
---
|
|
803
|
+
|
|
636
804
|
## Error Handling
|
|
637
805
|
|
|
638
806
|
All API failures throw a typed **`QLError`**:
|
package/dist/index.cjs
CHANGED
|
@@ -22,12 +22,16 @@ var index_exports = {};
|
|
|
22
22
|
__export(index_exports, {
|
|
23
23
|
API_ERROR_CODES: () => API_ERROR_CODES,
|
|
24
24
|
AgentsApi: () => AgentsApi,
|
|
25
|
+
AudioApi: () => AudioApi,
|
|
25
26
|
DEFAULT_BASE_URL: () => DEFAULT_BASE_URL,
|
|
27
|
+
FilesApi: () => FilesApi,
|
|
26
28
|
ImagesApi: () => ImagesApi,
|
|
27
29
|
QLClient: () => QLClient,
|
|
28
30
|
QLError: () => QLError,
|
|
29
31
|
TaskHandle: () => TaskHandle,
|
|
30
32
|
TasksApi: () => TasksApi,
|
|
33
|
+
VideoTaskHandle: () => VideoTaskHandle,
|
|
34
|
+
VideosApi: () => VideosApi,
|
|
31
35
|
WorkflowsApi: () => WorkflowsApi,
|
|
32
36
|
WorkspaceApi: () => WorkspaceApi,
|
|
33
37
|
isTerminalTaskStatus: () => isTerminalTaskStatus
|
|
@@ -135,6 +139,12 @@ function createTransport(opts) {
|
|
|
135
139
|
if (!res.ok) throw toHttpError(res.status, text, { method, url: res.url });
|
|
136
140
|
return unwrap(text, { method, url: res.url });
|
|
137
141
|
},
|
|
142
|
+
async form(path, reqOpts) {
|
|
143
|
+
const res = await doFormFetch(path, reqOpts);
|
|
144
|
+
const text = await res.text();
|
|
145
|
+
if (!res.ok) throw toHttpError(res.status, text, { method: "POST", url: res.url });
|
|
146
|
+
return unwrap(text, { method: "POST", url: res.url });
|
|
147
|
+
},
|
|
138
148
|
async stream(method, path, reqOpts = {}) {
|
|
139
149
|
const res = await doFetch(method, path, {
|
|
140
150
|
...reqOpts,
|
|
@@ -175,6 +185,22 @@ function createTransport(opts) {
|
|
|
175
185
|
throw toNetworkError(err, { method, url });
|
|
176
186
|
});
|
|
177
187
|
}
|
|
188
|
+
function doFormFetch(path, reqOpts) {
|
|
189
|
+
const url = buildUrl(baseUrl, path);
|
|
190
|
+
const headers = {
|
|
191
|
+
authorization: `Bearer ${apiKey}`,
|
|
192
|
+
accept: "application/json",
|
|
193
|
+
...reqOpts.headers ?? {}
|
|
194
|
+
};
|
|
195
|
+
return fetchImpl(url, {
|
|
196
|
+
method: "POST",
|
|
197
|
+
headers,
|
|
198
|
+
body: reqOpts.form,
|
|
199
|
+
signal: reqOpts.signal
|
|
200
|
+
}).catch((err) => {
|
|
201
|
+
throw toNetworkError(err, { method: "POST", url });
|
|
202
|
+
});
|
|
203
|
+
}
|
|
178
204
|
}
|
|
179
205
|
function unwrap(text, ctx) {
|
|
180
206
|
const parsed = safeParse(text);
|
|
@@ -313,6 +339,27 @@ var TERMINAL_TASK_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "ca
|
|
|
313
339
|
function isTerminalTaskStatus(status) {
|
|
314
340
|
return TERMINAL_TASK_STATUSES.has(status);
|
|
315
341
|
}
|
|
342
|
+
async function pollUntilTerminal(fetchSnapshot, isTerminal, onTick, opts) {
|
|
343
|
+
const intervalMs = opts.intervalMs ?? 2e3;
|
|
344
|
+
const maxIntervalMs = opts.maxIntervalMs ?? 15e3;
|
|
345
|
+
const signal = opts.signal;
|
|
346
|
+
const startedAt = Date.now();
|
|
347
|
+
let delay = intervalMs;
|
|
348
|
+
for (; ; ) {
|
|
349
|
+
if (signal?.aborted) throw abortError();
|
|
350
|
+
if (opts.timeoutMs !== void 0 && Date.now() - startedAt >= opts.timeoutMs) {
|
|
351
|
+
throw timeoutError(opts.timeoutMs);
|
|
352
|
+
}
|
|
353
|
+
const snapshot = await fetchSnapshot(signal);
|
|
354
|
+
onTick?.(snapshot);
|
|
355
|
+
if (isTerminal(snapshot)) return snapshot;
|
|
356
|
+
if (opts.timeoutMs !== void 0 && Date.now() - startedAt >= opts.timeoutMs) {
|
|
357
|
+
throw timeoutError(opts.timeoutMs);
|
|
358
|
+
}
|
|
359
|
+
await sleep(delay, signal);
|
|
360
|
+
delay = Math.min(maxIntervalMs, Math.round(delay * 1.5));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
316
363
|
var TaskHandle = class {
|
|
317
364
|
constructor(transport, taskId) {
|
|
318
365
|
this.transport = transport;
|
|
@@ -326,33 +373,37 @@ var TaskHandle = class {
|
|
|
326
373
|
poll(signal) {
|
|
327
374
|
return this.get(signal);
|
|
328
375
|
}
|
|
329
|
-
/**
|
|
330
|
-
* Poll until the task reaches a terminal status.
|
|
331
|
-
*
|
|
332
|
-
* - Uses exponential-ish backoff from `intervalMs` up to `maxIntervalMs`.
|
|
333
|
-
* - Throws a QLError with code "timeout" if `timeoutMs` elapses first.
|
|
334
|
-
* - Throws a QLError with code "aborted" if `signal` aborts.
|
|
335
|
-
*/
|
|
376
|
+
/** Poll until the task reaches a terminal status (see pollUntilTerminal for semantics). */
|
|
336
377
|
async wait(opts = {}) {
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
378
|
+
return pollUntilTerminal(
|
|
379
|
+
(signal) => this.get(signal),
|
|
380
|
+
(task) => isTerminalTaskStatus(task.status),
|
|
381
|
+
opts.onTick,
|
|
382
|
+
opts
|
|
383
|
+
);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
var VideoTaskHandle = class {
|
|
387
|
+
constructor(transport, taskId) {
|
|
388
|
+
this.transport = transport;
|
|
389
|
+
this.taskId = taskId;
|
|
390
|
+
}
|
|
391
|
+
/** Fetch the current job snapshot (single request). */
|
|
392
|
+
get(signal) {
|
|
393
|
+
return this.transport.json("GET", `/api/v1/video-tasks/${encodeURIComponent(this.taskId)}`, { signal });
|
|
394
|
+
}
|
|
395
|
+
/** Alias of `get()` — perform one poll and return the latest snapshot. */
|
|
396
|
+
poll(signal) {
|
|
397
|
+
return this.get(signal);
|
|
398
|
+
}
|
|
399
|
+
/** Poll until the job reaches a terminal status (completed/failed/cancelled). */
|
|
400
|
+
async wait(opts = {}) {
|
|
401
|
+
return pollUntilTerminal(
|
|
402
|
+
(signal) => this.get(signal),
|
|
403
|
+
(task) => isTerminalTaskStatus(task.status),
|
|
404
|
+
opts.onTick,
|
|
405
|
+
opts
|
|
406
|
+
);
|
|
356
407
|
}
|
|
357
408
|
};
|
|
358
409
|
function sleep(ms, signal) {
|
|
@@ -387,6 +438,30 @@ var WorkspaceApi = class {
|
|
|
387
438
|
get() {
|
|
388
439
|
return this.t.json("GET", "/api/v1/workspace");
|
|
389
440
|
}
|
|
441
|
+
/** GET /api/v1/workspace/models — current model config (OpenRouter key masked). */
|
|
442
|
+
getModels() {
|
|
443
|
+
return this.t.json("GET", "/api/v1/workspace/models");
|
|
444
|
+
}
|
|
445
|
+
/** PATCH /api/v1/workspace — update the workspace name and/or OpenRouter model config (partial). */
|
|
446
|
+
update(input) {
|
|
447
|
+
return this.t.json("PATCH", "/api/v1/workspace", { body: input });
|
|
448
|
+
}
|
|
449
|
+
/** PATCH /api/v1/workspace — convenience wrapper that only touches `config.openrouter`. */
|
|
450
|
+
updateModels(input) {
|
|
451
|
+
return this.t.json("PATCH", "/api/v1/workspace", { body: { config: { openrouter: input } } });
|
|
452
|
+
}
|
|
453
|
+
/** GET /api/v1/workspace/models/catalog — OpenRouter model catalog (server-side cached). */
|
|
454
|
+
listCatalogModels() {
|
|
455
|
+
return this.t.json("GET", "/api/v1/workspace/models/catalog");
|
|
456
|
+
}
|
|
457
|
+
/** POST /api/v1/workspace/models/verify — check an OpenRouter key with a 1-token completion. */
|
|
458
|
+
verifyOpenRouterKey(key, model, baseUrl) {
|
|
459
|
+
return this.t.json("POST", "/api/v1/workspace/models/verify", { body: { key, model, baseUrl } });
|
|
460
|
+
}
|
|
461
|
+
/** GET /api/v1/workspace/keys — API keys with rotation metadata (rotatesAt, daysLeft). */
|
|
462
|
+
listKeys() {
|
|
463
|
+
return this.t.json("GET", "/api/v1/workspace/keys");
|
|
464
|
+
}
|
|
390
465
|
};
|
|
391
466
|
var AgentsApi = class {
|
|
392
467
|
constructor(t) {
|
|
@@ -490,6 +565,62 @@ var ImagesApi = class {
|
|
|
490
565
|
return this.t.json("POST", `/api/v1/agents/${encodeURIComponent(agentId)}/images`, { body: input });
|
|
491
566
|
}
|
|
492
567
|
};
|
|
568
|
+
var VideosApi = class {
|
|
569
|
+
constructor(t) {
|
|
570
|
+
this.t = t;
|
|
571
|
+
}
|
|
572
|
+
/** GET /api/v1/videos/models — list tiered video models + engine availability. */
|
|
573
|
+
listModels() {
|
|
574
|
+
return this.t.json("GET", "/api/v1/videos/models");
|
|
575
|
+
}
|
|
576
|
+
/** POST /api/v1/agents/:agentId/videos — start a video job (returns the queued task, HTTP 202). */
|
|
577
|
+
generate(agentId, input) {
|
|
578
|
+
return this.t.json("POST", `/api/v1/agents/${encodeURIComponent(agentId)}/videos`, { body: input });
|
|
579
|
+
}
|
|
580
|
+
/** GET /api/v1/video-tasks/:taskId — fetch the current job snapshot. */
|
|
581
|
+
getTask(taskId, signal) {
|
|
582
|
+
return this.t.json("GET", `/api/v1/video-tasks/${encodeURIComponent(taskId)}`, { signal });
|
|
583
|
+
}
|
|
584
|
+
/** DELETE /api/v1/video-tasks/:taskId — cancel a queued/rendering job (409 if already terminal). */
|
|
585
|
+
cancelTask(taskId) {
|
|
586
|
+
return this.t.json("DELETE", `/api/v1/video-tasks/${encodeURIComponent(taskId)}`);
|
|
587
|
+
}
|
|
588
|
+
/** Get a handle for polling / waiting on a video job (poll(), wait()). */
|
|
589
|
+
handle(taskId) {
|
|
590
|
+
return new VideoTaskHandle(this.t, taskId);
|
|
591
|
+
}
|
|
592
|
+
};
|
|
593
|
+
var AudioApi = class {
|
|
594
|
+
constructor(t) {
|
|
595
|
+
this.t = t;
|
|
596
|
+
}
|
|
597
|
+
/** GET /api/v1/audio/voices — list available TTS voices. */
|
|
598
|
+
voices() {
|
|
599
|
+
return this.t.json("GET", "/api/v1/audio/voices");
|
|
600
|
+
}
|
|
601
|
+
/** POST /api/v1/agents/:agentId/tts — synthesize speech (synchronous). */
|
|
602
|
+
textToSpeech(agentId, input) {
|
|
603
|
+
return this.t.json("POST", `/api/v1/agents/${encodeURIComponent(agentId)}/tts`, { body: input });
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
var FilesApi = class {
|
|
607
|
+
constructor(t) {
|
|
608
|
+
this.t = t;
|
|
609
|
+
}
|
|
610
|
+
/** POST /api/v1/files — upload a media file (multipart field "file"). */
|
|
611
|
+
async upload(file, opts = {}) {
|
|
612
|
+
const form = new FormData();
|
|
613
|
+
if (opts.filename !== void 0) {
|
|
614
|
+
form.append("file", file, opts.filename);
|
|
615
|
+
} else {
|
|
616
|
+
form.append("file", file);
|
|
617
|
+
}
|
|
618
|
+
opts.onProgress?.(0);
|
|
619
|
+
const result = await this.t.form("/api/v1/files", { form });
|
|
620
|
+
opts.onProgress?.(100);
|
|
621
|
+
return result;
|
|
622
|
+
}
|
|
623
|
+
};
|
|
493
624
|
function readEnvBaseUrl() {
|
|
494
625
|
try {
|
|
495
626
|
if (typeof process !== "undefined" && process?.env) {
|
|
@@ -512,6 +643,9 @@ var QLClient = class {
|
|
|
512
643
|
this.workflows = new WorkflowsApi(this.transport);
|
|
513
644
|
this.tasks = new TasksApi(this.transport);
|
|
514
645
|
this.images = new ImagesApi(this.transport);
|
|
646
|
+
this.videos = new VideosApi(this.transport);
|
|
647
|
+
this.audio = new AudioApi(this.transport);
|
|
648
|
+
this.files = new FilesApi(this.transport);
|
|
515
649
|
}
|
|
516
650
|
/** The normalized base URL in use (not secret). */
|
|
517
651
|
get baseUrl() {
|