@promptev/client 0.2.0 → 1.1.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.
@@ -1,104 +1,549 @@
1
+ /**
2
+ * @promptev/client — the official JavaScript/TypeScript client for Promptev.
3
+ *
4
+ * 1.0 talks to Promptev's `/api/v1` surface, authenticated with a workspace
5
+ * API key (`fk_…`) sent as a Bearer token. The key is bound to ONE project and
6
+ * carries its own retrieval identity, so what a caller may read is part of the
7
+ * credential rather than a parameter on the call.
8
+ *
9
+ * Two methods:
10
+ * - `chat()` — stream a turn from an agent (SSE).
11
+ * - `uploadDocument()` — put files into the key's project corpus.
12
+ */
13
+ /**
14
+ * The default host. NOT `api.promptev.ai` — that host still serves the
15
+ * previous product and would answer 404 for every `/api/v1` path here.
16
+ * FLIP THIS the day `api.promptev.ai` is repointed at the console backend.
17
+ */
18
+ /**
19
+ * Where the client talks by default.
20
+ *
21
+ * `api.promptev.ai` is the API's permanent home. At the time 1.0 was written
22
+ * that host still served the PREVIOUS product, and it is being repointed at
23
+ * the new backend — so this default is correct for where things are going and
24
+ * must not ship to npm before the DNS moves. Point `baseUrl` at
25
+ * `https://console.promptev.ai` in the meantime, or at your own host if you
26
+ * run Promptev yourself.
27
+ */
28
+ export declare const DEFAULT_BASE_URL = "https://api.promptev.ai";
29
+ /** The server's own ceiling on one message (`ApiChatBody.message`). */
30
+ export declare const MAX_MESSAGE_CHARS = 20000;
31
+ /** `uploads.MAX_FILES_PER_REQUEST` — files in ONE upload request. */
32
+ export declare const MAX_FILES_PER_REQUEST = 20;
33
+ /** `file_types.MAX_UPLOAD_BYTES` — 25 MB per file. */
34
+ export declare const MAX_UPLOAD_BYTES: number;
35
+ /** Files ONE orchestration run may carry — the same ceiling a chat turn has.
36
+ * Server-side: `run_inputs.MAX_FILE_PARTS`. */
37
+ export declare const MAX_FILES_PER_RUN = 5;
1
38
  export interface PromptevClientConfig {
2
- projectKey: string;
39
+ /**
40
+ * Your Promptev API key — `fk_…`, minted in Settings → API keys of the
41
+ * project it may reach. It is sent as `Authorization: Bearer <key>`, never
42
+ * in a URL, and it carries the retrieval identity the agent answers under.
43
+ */
44
+ apiKey: string;
45
+ /** Override for self-hosted / staging. Defaults to {@link DEFAULT_BASE_URL}. */
3
46
  baseUrl?: string;
47
+ /** Extra HTTP headers on every request. */
4
48
  headers?: Record<string, string>;
49
+ /**
50
+ * Milliseconds to wait for the response HEADERS. A `chat()` stream is not
51
+ * bounded by it — once the response arrives the timer is cleared, because a
52
+ * turn that runs tools (or waits for an approval) legitimately outlives any
53
+ * request timeout.
54
+ */
5
55
  timeout?: number;
56
+ /** Retries for transient server errors (502/503/504) on non-streaming calls. */
6
57
  maxRetries?: number;
7
58
  }
8
- export interface AgentSession {
9
- sessionToken: string;
10
- agentId: string;
59
+ /**
60
+ * Assert, on this one call, WHICH end user your backend is acting for.
61
+ *
62
+ * The key's grant is a ceiling and this only ever narrows within it: the
63
+ * groups you assert are intersected with the key's `grp:` grants, and the
64
+ * key's `user:` grants drop entirely the moment an assertion is present. A
65
+ * compromised caller therefore cannot read beyond what the key was granted.
66
+ * `subject` is recorded as the conversation's actor for the audit trail; it is
67
+ * not verified by the server, so it never widens anything.
68
+ */
69
+ export interface OnBehalfOf {
70
+ /** Who you are acting for — an email or a stable user id (1–320 chars). */
71
+ subject: string;
72
+ /** The end user's groups, as your system knows them. Omit for the key's full grant. */
73
+ groups?: string[];
74
+ }
75
+ /** A model of a provider the workspace has connected, by the ids its model list shows. */
76
+ export interface ModelChoice {
77
+ provider: string;
78
+ model: string;
79
+ }
80
+ /**
81
+ * What one call overrides on one of the agent's tools, by where each value
82
+ * goes. Only what the tool already has in that place can be overridden; any
83
+ * other name answers 400, and nothing is stored: the next call runs the agent
84
+ * as it was published.
85
+ *
86
+ * - An HTTP tool has `headers`, `query`, `body` and `path` (a `{{name}}` in
87
+ * its URL). A GET or DELETE has no body: all its parameters are `query`.
88
+ * - An MCP server has `headers` (sent to the server) and `arguments` (of its
89
+ * functions; a value reaches every function that takes that argument).
90
+ *
91
+ * A value the model would have filled is fixed for the call: the model neither
92
+ * sees nor changes it, and it shows wherever tool arguments show (the
93
+ * `tool_call` event, approvals). A header, or a value the tool was saved with,
94
+ * never appears in the stream. Put secrets in `headers`.
95
+ */
96
+ export interface ToolInput {
97
+ headers?: Record<string, string>;
98
+ query?: Record<string, unknown>;
99
+ body?: Record<string, unknown>;
100
+ path?: Record<string, unknown>;
101
+ arguments?: Record<string, unknown>;
102
+ }
103
+ export interface ChatOptions {
104
+ /**
105
+ * Continue an existing thread. Read it off the first `conversation` event
106
+ * and pass it back on the next turn. Omit to start a new conversation.
107
+ *
108
+ * Worth passing: with a tool's "Ask once" approval mode the agent asks on
109
+ * the FIRST call in a conversation and not again for the rest of it, so a
110
+ * continued thread sees far fewer `approval_required` events.
111
+ *
112
+ * A thread belongs to the agent, to this API surface, AND to the
113
+ * `onBehalfOf.subject` it was opened under — so keep the subject the same
114
+ * across the turns of one conversation, and never pass an id from the app,
115
+ * the portal or an embed. Any mismatch answers 404, not a new thread.
116
+ */
117
+ conversationId?: string;
118
+ /** Act for one of your end users — see {@link OnBehalfOf}. */
119
+ onBehalfOf?: OnBehalfOf;
120
+ /**
121
+ * Run this one call on another model. The workspace's own provider key is
122
+ * used; a model it cannot call answers 400 before the turn starts.
123
+ */
124
+ model?: ModelChoice;
125
+ /**
126
+ * Override what the agent's tools are configured with, for this one call,
127
+ * keyed by tool id (shown on the tool's page) — see {@link ToolInput}.
128
+ */
129
+ toolInputs?: Record<string, ToolInput>;
130
+ /** Abort the turn from your own signal (in addition to the client timeout). */
131
+ signal?: AbortSignal;
132
+ }
133
+ export interface UploadOptions {
134
+ /**
135
+ * How the document is indexed. `"hybrid"` (the default) or `"graph"`.
136
+ * `"graph"` needs a graph database and an extraction model configured for
137
+ * the workspace, or the server answers 422.
138
+ */
139
+ mode?: "hybrid" | "graph";
140
+ /** Abort the upload from your own signal. */
141
+ signal?: AbortSignal;
142
+ }
143
+ /**
144
+ * A file to upload. Either a web `File`/`Blob`, or a plain object naming its
145
+ * bytes — which is what you want in Node, where `File` is awkward:
146
+ *
147
+ * ```ts
148
+ * await client.uploadDocument({ name: "handbook.pdf", content: await readFile(path) });
149
+ * ```
150
+ */
151
+ export type UploadInput = Blob | {
152
+ /** The filename the corpus stores it under — the extension picks the parser. */
153
+ name: string;
154
+ content: Blob | ArrayBuffer | ArrayBufferView | string;
155
+ /** Optional MIME type; the server decides from the name either way. */
156
+ type?: string;
157
+ };
158
+ /** One file's outcome — a batch reports every file, failures included. */
159
+ export interface UploadResult {
160
+ filename: string;
161
+ /** What the engine made of it — `"indexed"`, `"failed"`, … */
162
+ status: string;
163
+ /** The corpus id, or `null` when the file did not land. */
164
+ document_id: string | null;
165
+ chunks: number;
166
+ units: number;
167
+ /** Why this file failed, or `null`. */
168
+ error: string | null;
169
+ }
170
+ export interface UploadResponse {
171
+ results: UploadResult[];
172
+ }
173
+ /** First frame of every stream: the id that continues this thread. */
174
+ export interface ConversationEvent {
175
+ type: "conversation";
176
+ /** Pass as `conversationId` on the next `chat()` call. */
177
+ id: string;
178
+ }
179
+ /**
180
+ * One delta of the model's REASONING — not the answer. Never concatenate it
181
+ * into the reply; render it separately, or ignore it.
182
+ *
183
+ * Emitted only by models that actually stream thinking (Anthropic with a
184
+ * thinking budget, Gemini, the OpenAI Responses API) — many turns carry none.
185
+ */
186
+ export interface ThinkingEvent {
187
+ type: "thinking";
188
+ content: string;
189
+ }
190
+ /**
191
+ * ONE delta of the answer. Concatenating every `token.content` in order gives
192
+ * the agent's complete reply.
193
+ */
194
+ export interface TokenEvent {
195
+ type: "token";
196
+ content: string;
197
+ }
198
+ /** A stage of the turn — reading attachments, retrieving, waiting on an emailed approval. */
199
+ export interface StepEvent {
200
+ type: "step";
201
+ name: string;
202
+ status: "started" | "completed" | "failed";
203
+ detail?: string;
204
+ /** Set on the "waiting for approval — <tool>" step an EMAIL approval opens. */
205
+ tool_name?: string;
206
+ channel?: string;
207
+ }
208
+ /** Where the answer is grounded — one entry per retrieved document. */
209
+ export interface SourcesEvent {
210
+ type: "sources";
211
+ items: {
212
+ name: string;
213
+ document_id: string;
214
+ }[];
215
+ }
216
+ /** The agent decided to run a tool. `id` correlates with its `tool_result`. */
217
+ export interface ToolCallEvent {
218
+ type: "tool_call";
219
+ id: string;
220
+ name: string;
221
+ args?: Record<string, unknown>;
222
+ }
223
+ /** That tool answered. `ok: false` is a failure the agent will go on to explain. */
224
+ export interface ToolResultEvent {
225
+ type: "tool_result";
226
+ id: string;
227
+ name: string;
228
+ ok: boolean;
229
+ /** A one-line summary of the result — never the full payload. */
230
+ summary?: string;
231
+ /** How an approval ended, when the tool was gated: rejected / timeout / expired. */
232
+ approval?: string;
233
+ }
234
+ /**
235
+ * THE TURN IS PAUSED, WAITING FOR A HUMAN.
236
+ *
237
+ * A tool the agent wants to run is gated on approval. The stream stays OPEN: a
238
+ * person approves it in the Promptev app, by email, or in Slack, and the turn
239
+ * then continues on this same connection — you never re-send the message. If
240
+ * nobody decides in time the approval expires and the turn reports it as a
241
+ * failed `tool_result` (`approval: "expired"`).
242
+ *
243
+ * Handle this event. An integration that ignores it looks hung to its user for
244
+ * as long as the approval window lasts, which is the single most common
245
+ * support ticket this API generates. At minimum, tell your user what is being
246
+ * asked and who has to decide it.
247
+ *
248
+ * NOT every gated tool sends this event. `channel` is only ever `"inline"` or
249
+ * `"slack"` — somewhere a human is already looking. A tool whose approval is
250
+ * routed to an APPROVER BY EMAIL sends no card at all: it streams a
251
+ * {@link StepEvent} named `waiting for approval — <tool>` instead, which
252
+ * closes when the decision lands. Code that waits only for
253
+ * `approval_required` would wait forever on those.
254
+ *
255
+ * Passing `conversationId` on follow-up turns materially reduces how often you
256
+ * see it: a tool set to "Ask once" asks on the first call in a conversation and
257
+ * not again for the rest of it.
258
+ */
259
+ export interface ApprovalRequiredEvent {
260
+ type: "approval_required";
261
+ /** The pending approval's id — the same one the approver decides in Promptev. */
262
+ approval_id: string;
263
+ /** The tool waiting to run. */
264
+ tool_name: string;
265
+ /** The arguments it would run with — show these to whoever has to decide. */
266
+ args?: Record<string, unknown>;
267
+ /** Why approval is being asked for, in the operator's own words. */
268
+ reason?: string;
269
+ /**
270
+ * Where a human can decide it — `"inline"` (in the Promptev app) or
271
+ * `"slack"`. Never `"email"`: see this event's note above.
272
+ */
273
+ channel?: "inline" | "slack";
274
+ /** ISO-8601 deadline, after which the approval expires and the tool fails. */
275
+ expires_at?: string;
276
+ }
277
+ /**
278
+ * A file the agent produced this turn (`generate_file`). This surface carries
279
+ * no download link — open the conversation in Promptev to fetch the file, or
280
+ * have the agent put what you need in its answer.
281
+ */
282
+ export interface ArtifactEvent {
283
+ type: "artifact";
284
+ id: string;
285
+ kind: string;
11
286
  name: string;
12
- memoryEnabled: boolean;
13
- messages: Record<string, any>[];
287
+ mime: string;
288
+ size: number;
289
+ exports?: unknown[];
290
+ /** Only on surfaces that mint signed links; absent on `/api/v1`. */
291
+ url?: string;
292
+ }
293
+ /** 2–3 follow-ups the same person would plausibly ask next. Only when the agent has suggestions on. */
294
+ export interface SuggestionsEvent {
295
+ type: "suggestions";
296
+ questions: string[];
297
+ }
298
+ /** What the turn cost, emitted just before `done`. */
299
+ export interface UsageEvent {
300
+ type: "usage";
301
+ /** Credit units: one for the turn plus one per executed tool call. */
302
+ units: number;
303
+ /** Provider token counts, when the provider reported them. */
304
+ tokens?: Record<string, unknown>;
305
+ tool_calls?: number;
14
306
  }
15
- export interface TriggerResult {
16
- response: string;
17
- sessionId: string;
307
+ /** The stream finished cleanly. Nothing follows it. */
308
+ export interface DoneEvent {
309
+ type: "done";
18
310
  }
19
- export interface AgentEvent {
311
+ /** The turn failed mid-stream. Nothing follows it. */
312
+ export interface ErrorEvent {
313
+ type: "error";
314
+ message: string;
315
+ }
316
+ /**
317
+ * A frame from a NEWER server than this client knows about.
318
+ *
319
+ * Unknown types are yielded, never thrown on: a server that adds an event must
320
+ * not break an integration that had nothing to do with the deploy. Such a
321
+ * frame arrives typed as {@link AgentEvent} — its `type` simply matches none of
322
+ * the cases you handle. Cast it if you want its fields:
323
+ *
324
+ * ```ts
325
+ * default: console.log("new event:", (ev as UnknownEvent).type);
326
+ * ```
327
+ */
328
+ export interface UnknownEvent {
20
329
  type: string;
21
- output: string;
22
- raw: Record<string, any>;
330
+ [key: string]: unknown;
23
331
  }
332
+ /**
333
+ * Every frame `chat()` can yield. Narrow on `type`.
334
+ *
335
+ * The union names what today's server emits, so narrowing gives you real field
336
+ * types. A frame from a newer server still reaches you at runtime — see
337
+ * {@link UnknownEvent}.
338
+ */
339
+ export type AgentEvent = ConversationEvent | ThinkingEvent | TokenEvent | StepEvent | SourcesEvent | ToolCallEvent | ToolResultEvent | ApprovalRequiredEvent | ArtifactEvent | SuggestionsEvent | UsageEvent | DoneEvent | ErrorEvent;
340
+ /** The named event types — the vocabulary, for switch tables and filters. */
341
+ export type AgentEventType = "conversation" | "thinking" | "token" | "step" | "sources" | "tool_call" | "tool_result" | "approval_required" | "artifact" | "suggestions" | "usage" | "done" | "error";
24
342
  export declare class PromptevError extends Error {
25
343
  statusCode?: number;
26
344
  responseText?: string;
27
- constructor(message: string, statusCode?: number, responseText?: string);
345
+ /** Which request field the server objected to, when it named one. */
346
+ field?: string;
347
+ constructor(message: string, statusCode?: number, responseText?: string, field?: string);
28
348
  }
349
+ /** 400/422 — the request itself was wrong. `field` says which part. */
29
350
  export declare class ValidationError extends PromptevError {
30
- constructor(message: string, statusCode?: number, responseText?: string);
351
+ name: string;
31
352
  }
353
+ /** 401/403 — the key is missing, malformed, revoked or expired. */
32
354
  export declare class AuthenticationError extends PromptevError {
33
- constructor(message: string, statusCode?: number, responseText?: string);
355
+ name: string;
34
356
  }
357
+ /**
358
+ * 404 — no such agent, OR an agent your key cannot reach, OR one that has
359
+ * never been published. All three answer identically on purpose: a key holder
360
+ * learns nothing about projects it was not given.
361
+ */
35
362
  export declare class NotFoundError extends PromptevError {
36
- constructor(message: string, statusCode?: number, responseText?: string);
363
+ name: string;
37
364
  }
365
+ /** 429 — too many requests. `retryAfter` is the server's own answer, in seconds. */
38
366
  export declare class RateLimitError extends PromptevError {
39
- constructor(message: string, statusCode?: number, responseText?: string);
367
+ name: string;
368
+ /** Seconds to wait, from the `Retry-After` header, when the server sent one. */
369
+ retryAfter?: number;
370
+ constructor(message: string, statusCode?: number, responseText?: string, field?: string, retryAfter?: number);
371
+ }
372
+ /**
373
+ * 402 — the workspace is out of credits. Not a rate limit: waiting does not
374
+ * fix it, a top-up does.
375
+ */
376
+ export declare class InsufficientCreditsError extends PromptevError {
377
+ name: string;
40
378
  }
379
+ /** 5xx — the server failed, after the client's retries were exhausted. */
41
380
  export declare class ServerError extends PromptevError {
42
- constructor(message: string, statusCode?: number, responseText?: string);
381
+ name: string;
43
382
  }
383
+ /** The request never got an answer: DNS, connection, abort, or the client timeout. */
44
384
  export declare class NetworkError extends PromptevError {
45
- constructor(message: string, statusCode?: number, responseText?: string);
385
+ name: string;
386
+ }
387
+ /** What an orchestration takes: its own declared input keys. Values are plain
388
+ * scalars or flat lists of them — the shape the server bounds (50 keys, 64-char
389
+ * names, lists of 100, 64 KB). Files do NOT go in here; they are their own
390
+ * parts, keyed by the input they fill. */
391
+ export type RunInputs = Record<string, unknown>;
392
+ export interface RunOptions {
393
+ /** Files for inputs declared `File(s)`, keyed by the input's key — the part
394
+ * is NAMED after the input it fills, which is what lets one call fill two
395
+ * different file inputs. */
396
+ files?: Record<string, UploadInput | UploadInput[]>;
397
+ /** Send one and a retry returns the run you already started instead of
398
+ * running the team twice. */
399
+ idempotencyKey?: string;
400
+ signal?: AbortSignal;
401
+ }
402
+ export interface StartedRun {
403
+ /** Pass this to {@link PromptevClient.getRun}. */
404
+ run_id: string;
405
+ status: "accepted";
406
+ }
407
+ export interface RunStatus {
408
+ run_id: string;
409
+ /** The orchestration's slug. */
410
+ orchestration: string;
411
+ /** `running` · `awaiting_review` · `revising` · `delivered` · `failed`. */
412
+ status: string;
413
+ created_at: string | null;
414
+ /** Present only once there IS one — a half-written answer read mid-run is
415
+ * worse than none, because a caller would act on a draft. */
416
+ output?: string;
417
+ error?: string;
46
418
  }
47
419
  export declare class PromptevClient {
48
- private projectKey;
420
+ private apiKey;
49
421
  private baseUrl;
50
422
  private headers;
51
423
  private timeout;
52
424
  private maxRetries;
53
425
  constructor(config: PromptevClientConfig);
426
+ /**
427
+ * Every refusal on `/api/v1` is `{"error": {"message", "field"?}}`. The
428
+ * older `{"detail": …}` shape is still read as a fallback, so a proxy or an
429
+ * un-migrated route can never produce an empty message.
430
+ */
54
431
  private static raiseForStatus;
432
+ private authHeaders;
55
433
  private fetchWithRetry;
434
+ /**
435
+ * One `fetch`, with the client timeout applied to the RESPONSE only.
436
+ *
437
+ * The timer is cleared the moment the response resolves, which is what lets
438
+ * a `chat()` stream run for minutes — a tool call, or a human deciding an
439
+ * approval, is not a stalled request.
440
+ */
441
+ private fetchOnce;
56
442
  private parseSSE;
57
443
  /**
58
- * Trigger an agent in a single blocking call — the primary way to use the SDK.
444
+ * Send a message to one of your project's agents and stream the answer.
445
+ *
446
+ * This is the whole conversational surface: it starts a thread or continues
447
+ * one, streams every event the turn produces, and ends with `done` (or
448
+ * `error`). There is no separate "start" call and no session token — the API
449
+ * key IS the credential, and `conversationId` is the thread.
450
+ *
451
+ * @param agentSlug The agent's slug, as shown on its page in Promptev. Only
452
+ * PUBLISHED agents in the key's own project can be reached; anything else
453
+ * answers 404 ({@link NotFoundError}).
454
+ * @param message What to say. Required, non-empty after trimming, at most
455
+ * {@link MAX_MESSAGE_CHARS} characters.
456
+ *
457
+ * @example Stream the answer
458
+ * ```ts
459
+ * let conversationId: string | undefined;
460
+ * for await (const ev of client.chat("support-agent", "What is the refund policy?")) {
461
+ * switch (ev.type) {
462
+ * case "conversation": conversationId = ev.id; break;
463
+ * case "token": process.stdout.write(ev.content); break;
464
+ * case "approval_required":
465
+ * console.log(`\n${ev.tool_name} needs approval — ${ev.reason ?? "policy"}`);
466
+ * break;
467
+ * case "error": throw new Error(ev.message);
468
+ * }
469
+ * }
470
+ * // Continue the thread — and see far fewer approval prompts:
471
+ * for await (const ev of client.chat("support-agent", "And for digital goods?", { conversationId })) {
472
+ * if (ev.type === "token") process.stdout.write(ev.content);
473
+ * }
474
+ * ```
475
+ */
476
+ chat(agentSlug: string, message: string, options?: ChatOptions): AsyncGenerator<AgentEvent>;
477
+ /**
478
+ * Put one or more documents into the project's corpus — the same "Uploads"
479
+ * source the app writes to, so what you upload here is what the agents in
480
+ * that project retrieve.
59
481
  *
60
- * Creates (or resumes) a session AND runs the agent, returning the final
61
- * response as JSON. Any tools the agent has attached run server-side.
482
+ * The key names the project, so nothing about the destination is in the
483
+ * request: a key cannot upload into a project it does not reach.
62
484
  *
63
- * @param agentId - Your agent's id (from the Deploy tab).
64
- * @param message - The user message to send to the agent.
65
- * @param opts.sessionId - Pass the `sessionId` from a previous call to keep
66
- * conversation memory. Omit it for a fresh, stateless run.
67
- * @param opts.variables - Object filling the agent's `{{...}}` prompt variables.
68
- * @returns `{ response, sessionId }` — pass `sessionId` back on the next call
69
- * to continue the same conversation.
485
+ * Limits, checked here and again on the server: at most
486
+ * {@link MAX_FILES_PER_REQUEST} files per call, at most
487
+ * {@link MAX_UPLOAD_BYTES} (25 MB) per file — a larger set belongs in a
488
+ * connector source. Ingestion is content-addressed: re-uploading identical
489
+ * bytes updates the existing document instead of duplicating it.
490
+ *
491
+ * Ingestion is slow, and the request does not return until every file is
492
+ * indexed — raise `timeout` well above its 30 s default for real documents.
70
493
  *
71
494
  * @example
72
- * const { response, sessionId } = await client.triggerAgent(
73
- * "your-agent-id",
74
- * "What is the refund policy?",
75
- * { variables: { company: "Acme Corp" } }
495
+ * ```ts
496
+ * import { readFile } from "node:fs/promises";
497
+ *
498
+ * const { results } = await client.uploadDocument(
499
+ * { name: "handbook.pdf", content: await readFile("handbook.pdf") },
500
+ * { mode: "hybrid" }
76
501
  * );
77
- * // Follow-up keeps memory:
78
- * await client.triggerAgent("your-agent-id", "And for digital goods?", { sessionId });
502
+ * for (const r of results) console.log(r.filename, r.status, r.error ?? "");
503
+ * ```
79
504
  */
80
- triggerAgent(agentId: string, message: string, opts?: {
81
- sessionId?: string;
82
- variables?: Record<string, any>;
83
- visitor?: string;
84
- }): Promise<TriggerResult>;
505
+ uploadDocument(files: UploadInput | UploadInput[], options?: UploadOptions): Promise<UploadResponse>;
85
506
  /**
86
- * Start a new agent chat session (streaming flow).
507
+ * Start a run of a published orchestration. Answers as soon as the run is
508
+ * recorded — **not** when it finishes.
87
509
  *
88
- * @param agentId - Your agent's id (from the Deploy tab).
510
+ * An orchestration is a team of agents; it runs in a worker for as long as it
511
+ * takes, so this returns a `run_id` and {@link getRun} tells you what became
512
+ * of it. That is the difference from {@link chat}, which streams one agent's
513
+ * answer inline.
514
+ *
515
+ * ```ts
516
+ * const { run_id } = await client.runOrchestration("month-end-close", {
517
+ * period: "2026-03",
518
+ * entity: "Acme GmbH",
519
+ * });
520
+ * ```
521
+ *
522
+ * With files — the part is named after the input it fills:
523
+ *
524
+ * ```ts
525
+ * const { run_id } = await client.runOrchestration(
526
+ * "contract-review",
527
+ * { matter: "Acme renewal" },
528
+ * { files: { contract: { name: "lease.pdf", content: bytes } } },
529
+ * );
530
+ * ```
89
531
  */
90
- startAgent(agentId: string, options?: {
91
- visitor?: string;
92
- platform?: string;
93
- }): Promise<AgentSession>;
532
+ runOrchestration(slug: string, inputs?: RunInputs, options?: RunOptions): Promise<StartedRun>;
94
533
  /**
95
- * Stream an agent response as SSE events.
534
+ * What became of a run — poll this after {@link runOrchestration}.
96
535
  *
97
- * @param agentId - Your agent's id (from the Deploy tab).
536
+ * ```ts
537
+ * let run = await client.getRun(run_id);
538
+ * while (run.status === "running" || run.status === "revising") {
539
+ * await new Promise((r) => setTimeout(r, 2000));
540
+ * run = await client.getRun(run_id);
541
+ * }
542
+ * console.log(run.output);
543
+ * ```
98
544
  */
99
- streamAgent(agentId: string, options: {
100
- sessionToken: string;
101
- query: string;
102
- }): AsyncGenerator<AgentEvent>;
545
+ getRun(runId: string, options?: {
546
+ signal?: AbortSignal;
547
+ }): Promise<RunStatus>;
103
548
  }
104
549
  export default PromptevClient;