@promptev/client 1.1.0 → 1.3.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/dist/cjs/index.cjs +78 -10
- package/dist/esm/index.d.ts +36 -2
- package/dist/esm/index.js +77 -9
- package/package.json +1 -1
- package/readme.md +44 -4
package/dist/cjs/index.cjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* - `uploadDocument()` — put files into the key's project corpus.
|
|
13
13
|
*/
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
-
exports.PromptevClient = exports.NetworkError = exports.ServerError = exports.InsufficientCreditsError = exports.RateLimitError = exports.NotFoundError = exports.AuthenticationError = exports.ValidationError = exports.PromptevError = exports.MAX_FILES_PER_RUN = exports.MAX_UPLOAD_BYTES = exports.MAX_FILES_PER_REQUEST = exports.MAX_MESSAGE_CHARS = exports.DEFAULT_BASE_URL = void 0;
|
|
15
|
+
exports.PromptevClient = exports.NetworkError = exports.ServerError = exports.InsufficientCreditsError = exports.RateLimitError = exports.NotFoundError = exports.AuthenticationError = exports.ValidationError = exports.PromptevError = exports.KNOWLEDGE_ACTIONS = exports.MAX_FILES_PER_RUN = exports.MAX_UPLOAD_BYTES = exports.MAX_FILES_PER_REQUEST = exports.MAX_MESSAGE_CHARS = exports.DEFAULT_BASE_URL = void 0;
|
|
16
16
|
// ── Configuration ───────────────────────────────────────
|
|
17
17
|
/**
|
|
18
18
|
* The default host. NOT `api.promptev.ai` — that host still serves the
|
|
@@ -39,6 +39,13 @@ exports.MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
|
|
|
39
39
|
/** Files ONE orchestration run may carry — the same ceiling a chat turn has.
|
|
40
40
|
* Server-side: `run_inputs.MAX_FILE_PARTS`. */
|
|
41
41
|
exports.MAX_FILES_PER_RUN = 5;
|
|
42
|
+
/** The knowledge base's actions, as the project MCP's `search_knowledge_base`
|
|
43
|
+
* offers them. Informational: the server decides, so an action added there
|
|
44
|
+
* works here without a new SDK. */
|
|
45
|
+
exports.KNOWLEDGE_ACTIONS = [
|
|
46
|
+
"discover", "search", "get_doc", "list", "query_meta", "compute", "get_chunks",
|
|
47
|
+
"get_docs", "map_reduce", "traverse", "find_related", "get_neighbors", "community_summary",
|
|
48
|
+
];
|
|
42
49
|
// ── Errors ──────────────────────────────────────────────
|
|
43
50
|
class PromptevError extends Error {
|
|
44
51
|
constructor(message, statusCode, responseText, field) {
|
|
@@ -305,8 +312,8 @@ class PromptevClient {
|
|
|
305
312
|
* @param agentSlug The agent's slug, as shown on its page in Promptev. Only
|
|
306
313
|
* PUBLISHED agents in the key's own project can be reached; anything else
|
|
307
314
|
* answers 404 ({@link NotFoundError}).
|
|
308
|
-
* @param message What to say.
|
|
309
|
-
* {@link MAX_MESSAGE_CHARS} characters.
|
|
315
|
+
* @param message What to say. Non-empty after trimming unless
|
|
316
|
+
* `options.files` are sent, at most {@link MAX_MESSAGE_CHARS} characters.
|
|
310
317
|
*
|
|
311
318
|
* @example Stream the answer
|
|
312
319
|
* ```ts
|
|
@@ -333,10 +340,11 @@ class PromptevClient {
|
|
|
333
340
|
throw new ValidationError("Name the agent to talk to.", undefined, undefined, "agentSlug");
|
|
334
341
|
}
|
|
335
342
|
const text = String(message ?? "").trim();
|
|
336
|
-
|
|
343
|
+
const files = options?.files ?? [];
|
|
344
|
+
if (!text && files.length === 0) {
|
|
337
345
|
// The server answers 422 for this; refusing here saves the round trip
|
|
338
346
|
// AND the api_call the workspace would still have been metered for.
|
|
339
|
-
throw new ValidationError("Say something to the agent.", undefined, undefined, "message");
|
|
347
|
+
throw new ValidationError("Say something to the agent, or attach a file.", undefined, undefined, "message");
|
|
340
348
|
}
|
|
341
349
|
if (text.length > exports.MAX_MESSAGE_CHARS) {
|
|
342
350
|
throw new ValidationError(`A message can be at most ${exports.MAX_MESSAGE_CHARS} characters.`, undefined, undefined, "message");
|
|
@@ -359,11 +367,7 @@ class PromptevClient {
|
|
|
359
367
|
// POST could run the agent, and its tools, a second time.
|
|
360
368
|
const resp = await this.fetchOnce(url, {
|
|
361
369
|
method: "POST",
|
|
362
|
-
|
|
363
|
-
"Content-Type": "application/json",
|
|
364
|
-
Accept: "text/event-stream",
|
|
365
|
-
}),
|
|
366
|
-
body: JSON.stringify(payload),
|
|
370
|
+
...chatBody(payload, files, (extra) => this.authHeaders(extra)),
|
|
367
371
|
signal: options?.signal,
|
|
368
372
|
});
|
|
369
373
|
if (resp.status >= 400) {
|
|
@@ -462,6 +466,43 @@ class PromptevClient {
|
|
|
462
466
|
* );
|
|
463
467
|
* ```
|
|
464
468
|
*/
|
|
469
|
+
/**
|
|
470
|
+
* Read the key's project knowledge base through the Context Engine: the
|
|
471
|
+
* same tool, with the same actions, as `search_knowledge_base` on the
|
|
472
|
+
* project's MCP server (`POST /api/v1/knowledge`).
|
|
473
|
+
*
|
|
474
|
+
* ```ts
|
|
475
|
+
* const overview = await client.searchKnowledgeBase("discover");
|
|
476
|
+
* const found = await client.searchKnowledgeBase("search", { query: "how many days do customers have to ask for a refund", top_k: 5 });
|
|
477
|
+
* for (const hit of found.hits) console.log(hit.document_name, hit.chunk_text);
|
|
478
|
+
* const doc = await client.searchKnowledgeBase("get_doc", { document_id: found.hits[0].document_id });
|
|
479
|
+
* ```
|
|
480
|
+
*
|
|
481
|
+
* `fields` are that action's fields (`query`, `top_k`, `document_id`,
|
|
482
|
+
* `source_ids`, `mode`, `limit`, `cursor`, ...); undefined and null ones
|
|
483
|
+
* are not sent. Returns the knowledge base's answer as an object.
|
|
484
|
+
*/
|
|
485
|
+
async searchKnowledgeBase(action, fields = {}, options) {
|
|
486
|
+
if (typeof action !== "string" || !action.trim()) {
|
|
487
|
+
throw new ValidationError('Name the action, e.g. "search".', undefined, undefined, "action");
|
|
488
|
+
}
|
|
489
|
+
const body = { action: action.trim() };
|
|
490
|
+
for (const [key, value] of Object.entries(fields ?? {})) {
|
|
491
|
+
if (value !== undefined && value !== null)
|
|
492
|
+
body[key] = value;
|
|
493
|
+
}
|
|
494
|
+
const headers = this.authHeaders();
|
|
495
|
+
headers["Content-Type"] = "application/json";
|
|
496
|
+
const resp = await this.fetchWithRetry(`${this.baseUrl}/api/v1/knowledge`, {
|
|
497
|
+
method: "POST",
|
|
498
|
+
headers,
|
|
499
|
+
body: JSON.stringify(body),
|
|
500
|
+
signal: options?.signal,
|
|
501
|
+
});
|
|
502
|
+
const text = await resp.text();
|
|
503
|
+
PromptevClient.raiseForStatus(resp.status, text, resp.headers);
|
|
504
|
+
return text ? JSON.parse(text) : {};
|
|
505
|
+
}
|
|
465
506
|
async runOrchestration(slug, inputs = {}, options) {
|
|
466
507
|
if (!slug || !slug.trim()) {
|
|
467
508
|
throw new ValidationError("Name the orchestration to run.", undefined, undefined, "slug");
|
|
@@ -536,6 +577,33 @@ class PromptevClient {
|
|
|
536
577
|
}
|
|
537
578
|
}
|
|
538
579
|
exports.PromptevClient = PromptevClient;
|
|
580
|
+
/**
|
|
581
|
+
* The body of a chat call: JSON when there are no files; MULTIPART when there
|
|
582
|
+
* are, the JSON in a `payload` part and each file in a `files` part. Count and
|
|
583
|
+
* size are judged here, before the wire.
|
|
584
|
+
*/
|
|
585
|
+
function chatBody(payload, files, headers) {
|
|
586
|
+
if (files.length === 0) {
|
|
587
|
+
return {
|
|
588
|
+
headers: headers({ "Content-Type": "application/json", Accept: "text/event-stream" }),
|
|
589
|
+
body: JSON.stringify(payload),
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
if (files.length > exports.MAX_FILES_PER_RUN) {
|
|
593
|
+
throw new ValidationError(`At most ${exports.MAX_FILES_PER_RUN} files can be sent with one call.`, undefined, undefined, "files");
|
|
594
|
+
}
|
|
595
|
+
const form = new FormData();
|
|
596
|
+
form.append("payload", JSON.stringify(payload));
|
|
597
|
+
for (const file of files) {
|
|
598
|
+
const [name, blob] = toBlob(file);
|
|
599
|
+
if (blob.size > exports.MAX_UPLOAD_BYTES) {
|
|
600
|
+
throw new ValidationError(`${name}: larger than ${exports.MAX_UPLOAD_BYTES / (1024 * 1024)} MB — add bigger files to the agent's knowledge instead.`, undefined, undefined, "files");
|
|
601
|
+
}
|
|
602
|
+
form.append("files", blob, name);
|
|
603
|
+
}
|
|
604
|
+
// NO Content-Type — fetch sets the multipart boundary itself.
|
|
605
|
+
return { headers: headers({ Accept: "text/event-stream" }), body: form };
|
|
606
|
+
}
|
|
539
607
|
/** One upload input, as a named Blob — the only shape `FormData` accepts. */
|
|
540
608
|
function toBlob(file) {
|
|
541
609
|
if (typeof Blob !== "undefined" && file instanceof Blob) {
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -35,6 +35,11 @@ export declare const MAX_UPLOAD_BYTES: number;
|
|
|
35
35
|
/** Files ONE orchestration run may carry — the same ceiling a chat turn has.
|
|
36
36
|
* Server-side: `run_inputs.MAX_FILE_PARTS`. */
|
|
37
37
|
export declare const MAX_FILES_PER_RUN = 5;
|
|
38
|
+
/** The knowledge base's actions, as the project MCP's `search_knowledge_base`
|
|
39
|
+
* offers them. Informational: the server decides, so an action added there
|
|
40
|
+
* works here without a new SDK. */
|
|
41
|
+
export declare const KNOWLEDGE_ACTIONS: readonly ["discover", "search", "get_doc", "list", "query_meta", "compute", "get_chunks", "get_docs", "map_reduce", "traverse", "find_related", "get_neighbors", "community_summary"];
|
|
42
|
+
export type KnowledgeAction = (typeof KNOWLEDGE_ACTIONS)[number];
|
|
38
43
|
export interface PromptevClientConfig {
|
|
39
44
|
/**
|
|
40
45
|
* Your Promptev API key — `fk_…`, minted in Settings → API keys of the
|
|
@@ -127,6 +132,16 @@ export interface ChatOptions {
|
|
|
127
132
|
* keyed by tool id (shown on the tool's page) — see {@link ToolInput}.
|
|
128
133
|
*/
|
|
129
134
|
toolInputs?: Record<string, ToolInput>;
|
|
135
|
+
/**
|
|
136
|
+
* Files for the agent to read on this turn, sent in the same call: at most
|
|
137
|
+
* {@link MAX_FILES_PER_RUN}, each at most 25 MB. Accepted only when the
|
|
138
|
+
* agent's "Chat attachments" is on (409 otherwise), and only the types the
|
|
139
|
+
* promptev chat takes (415 otherwise). An image is shown to a model that can
|
|
140
|
+
* see, and read into text for one that cannot. A document is read before
|
|
141
|
+
* the answer starts, so a long scan makes a slower first event. With files,
|
|
142
|
+
* `message` may be empty.
|
|
143
|
+
*/
|
|
144
|
+
files?: UploadInput[];
|
|
130
145
|
/** Abort the turn from your own signal (in addition to the client timeout). */
|
|
131
146
|
signal?: AbortSignal;
|
|
132
147
|
}
|
|
@@ -451,8 +466,8 @@ export declare class PromptevClient {
|
|
|
451
466
|
* @param agentSlug The agent's slug, as shown on its page in Promptev. Only
|
|
452
467
|
* PUBLISHED agents in the key's own project can be reached; anything else
|
|
453
468
|
* answers 404 ({@link NotFoundError}).
|
|
454
|
-
* @param message What to say.
|
|
455
|
-
* {@link MAX_MESSAGE_CHARS} characters.
|
|
469
|
+
* @param message What to say. Non-empty after trimming unless
|
|
470
|
+
* `options.files` are sent, at most {@link MAX_MESSAGE_CHARS} characters.
|
|
456
471
|
*
|
|
457
472
|
* @example Stream the answer
|
|
458
473
|
* ```ts
|
|
@@ -529,6 +544,25 @@ export declare class PromptevClient {
|
|
|
529
544
|
* );
|
|
530
545
|
* ```
|
|
531
546
|
*/
|
|
547
|
+
/**
|
|
548
|
+
* Read the key's project knowledge base through the Context Engine: the
|
|
549
|
+
* same tool, with the same actions, as `search_knowledge_base` on the
|
|
550
|
+
* project's MCP server (`POST /api/v1/knowledge`).
|
|
551
|
+
*
|
|
552
|
+
* ```ts
|
|
553
|
+
* const overview = await client.searchKnowledgeBase("discover");
|
|
554
|
+
* const found = await client.searchKnowledgeBase("search", { query: "how many days do customers have to ask for a refund", top_k: 5 });
|
|
555
|
+
* for (const hit of found.hits) console.log(hit.document_name, hit.chunk_text);
|
|
556
|
+
* const doc = await client.searchKnowledgeBase("get_doc", { document_id: found.hits[0].document_id });
|
|
557
|
+
* ```
|
|
558
|
+
*
|
|
559
|
+
* `fields` are that action's fields (`query`, `top_k`, `document_id`,
|
|
560
|
+
* `source_ids`, `mode`, `limit`, `cursor`, ...); undefined and null ones
|
|
561
|
+
* are not sent. Returns the knowledge base's answer as an object.
|
|
562
|
+
*/
|
|
563
|
+
searchKnowledgeBase(action: KnowledgeAction | (string & {}), fields?: Record<string, unknown>, options?: {
|
|
564
|
+
signal?: AbortSignal;
|
|
565
|
+
}): Promise<Record<string, any>>;
|
|
532
566
|
runOrchestration(slug: string, inputs?: RunInputs, options?: RunOptions): Promise<StartedRun>;
|
|
533
567
|
/**
|
|
534
568
|
* What became of a run — poll this after {@link runOrchestration}.
|
package/dist/esm/index.js
CHANGED
|
@@ -36,6 +36,13 @@ export const MAX_UPLOAD_BYTES = 25 * 1024 * 1024;
|
|
|
36
36
|
/** Files ONE orchestration run may carry — the same ceiling a chat turn has.
|
|
37
37
|
* Server-side: `run_inputs.MAX_FILE_PARTS`. */
|
|
38
38
|
export const MAX_FILES_PER_RUN = 5;
|
|
39
|
+
/** The knowledge base's actions, as the project MCP's `search_knowledge_base`
|
|
40
|
+
* offers them. Informational: the server decides, so an action added there
|
|
41
|
+
* works here without a new SDK. */
|
|
42
|
+
export const KNOWLEDGE_ACTIONS = [
|
|
43
|
+
"discover", "search", "get_doc", "list", "query_meta", "compute", "get_chunks",
|
|
44
|
+
"get_docs", "map_reduce", "traverse", "find_related", "get_neighbors", "community_summary",
|
|
45
|
+
];
|
|
39
46
|
// ── Errors ──────────────────────────────────────────────
|
|
40
47
|
export class PromptevError extends Error {
|
|
41
48
|
constructor(message, statusCode, responseText, field) {
|
|
@@ -294,8 +301,8 @@ export class PromptevClient {
|
|
|
294
301
|
* @param agentSlug The agent's slug, as shown on its page in Promptev. Only
|
|
295
302
|
* PUBLISHED agents in the key's own project can be reached; anything else
|
|
296
303
|
* answers 404 ({@link NotFoundError}).
|
|
297
|
-
* @param message What to say.
|
|
298
|
-
* {@link MAX_MESSAGE_CHARS} characters.
|
|
304
|
+
* @param message What to say. Non-empty after trimming unless
|
|
305
|
+
* `options.files` are sent, at most {@link MAX_MESSAGE_CHARS} characters.
|
|
299
306
|
*
|
|
300
307
|
* @example Stream the answer
|
|
301
308
|
* ```ts
|
|
@@ -322,10 +329,11 @@ export class PromptevClient {
|
|
|
322
329
|
throw new ValidationError("Name the agent to talk to.", undefined, undefined, "agentSlug");
|
|
323
330
|
}
|
|
324
331
|
const text = String(message ?? "").trim();
|
|
325
|
-
|
|
332
|
+
const files = options?.files ?? [];
|
|
333
|
+
if (!text && files.length === 0) {
|
|
326
334
|
// The server answers 422 for this; refusing here saves the round trip
|
|
327
335
|
// AND the api_call the workspace would still have been metered for.
|
|
328
|
-
throw new ValidationError("Say something to the agent.", undefined, undefined, "message");
|
|
336
|
+
throw new ValidationError("Say something to the agent, or attach a file.", undefined, undefined, "message");
|
|
329
337
|
}
|
|
330
338
|
if (text.length > MAX_MESSAGE_CHARS) {
|
|
331
339
|
throw new ValidationError(`A message can be at most ${MAX_MESSAGE_CHARS} characters.`, undefined, undefined, "message");
|
|
@@ -348,11 +356,7 @@ export class PromptevClient {
|
|
|
348
356
|
// POST could run the agent, and its tools, a second time.
|
|
349
357
|
const resp = await this.fetchOnce(url, {
|
|
350
358
|
method: "POST",
|
|
351
|
-
|
|
352
|
-
"Content-Type": "application/json",
|
|
353
|
-
Accept: "text/event-stream",
|
|
354
|
-
}),
|
|
355
|
-
body: JSON.stringify(payload),
|
|
359
|
+
...chatBody(payload, files, (extra) => this.authHeaders(extra)),
|
|
356
360
|
signal: options?.signal,
|
|
357
361
|
});
|
|
358
362
|
if (resp.status >= 400) {
|
|
@@ -451,6 +455,43 @@ export class PromptevClient {
|
|
|
451
455
|
* );
|
|
452
456
|
* ```
|
|
453
457
|
*/
|
|
458
|
+
/**
|
|
459
|
+
* Read the key's project knowledge base through the Context Engine: the
|
|
460
|
+
* same tool, with the same actions, as `search_knowledge_base` on the
|
|
461
|
+
* project's MCP server (`POST /api/v1/knowledge`).
|
|
462
|
+
*
|
|
463
|
+
* ```ts
|
|
464
|
+
* const overview = await client.searchKnowledgeBase("discover");
|
|
465
|
+
* const found = await client.searchKnowledgeBase("search", { query: "how many days do customers have to ask for a refund", top_k: 5 });
|
|
466
|
+
* for (const hit of found.hits) console.log(hit.document_name, hit.chunk_text);
|
|
467
|
+
* const doc = await client.searchKnowledgeBase("get_doc", { document_id: found.hits[0].document_id });
|
|
468
|
+
* ```
|
|
469
|
+
*
|
|
470
|
+
* `fields` are that action's fields (`query`, `top_k`, `document_id`,
|
|
471
|
+
* `source_ids`, `mode`, `limit`, `cursor`, ...); undefined and null ones
|
|
472
|
+
* are not sent. Returns the knowledge base's answer as an object.
|
|
473
|
+
*/
|
|
474
|
+
async searchKnowledgeBase(action, fields = {}, options) {
|
|
475
|
+
if (typeof action !== "string" || !action.trim()) {
|
|
476
|
+
throw new ValidationError('Name the action, e.g. "search".', undefined, undefined, "action");
|
|
477
|
+
}
|
|
478
|
+
const body = { action: action.trim() };
|
|
479
|
+
for (const [key, value] of Object.entries(fields ?? {})) {
|
|
480
|
+
if (value !== undefined && value !== null)
|
|
481
|
+
body[key] = value;
|
|
482
|
+
}
|
|
483
|
+
const headers = this.authHeaders();
|
|
484
|
+
headers["Content-Type"] = "application/json";
|
|
485
|
+
const resp = await this.fetchWithRetry(`${this.baseUrl}/api/v1/knowledge`, {
|
|
486
|
+
method: "POST",
|
|
487
|
+
headers,
|
|
488
|
+
body: JSON.stringify(body),
|
|
489
|
+
signal: options?.signal,
|
|
490
|
+
});
|
|
491
|
+
const text = await resp.text();
|
|
492
|
+
PromptevClient.raiseForStatus(resp.status, text, resp.headers);
|
|
493
|
+
return text ? JSON.parse(text) : {};
|
|
494
|
+
}
|
|
454
495
|
async runOrchestration(slug, inputs = {}, options) {
|
|
455
496
|
if (!slug || !slug.trim()) {
|
|
456
497
|
throw new ValidationError("Name the orchestration to run.", undefined, undefined, "slug");
|
|
@@ -524,6 +565,33 @@ export class PromptevClient {
|
|
|
524
565
|
return JSON.parse(text);
|
|
525
566
|
}
|
|
526
567
|
}
|
|
568
|
+
/**
|
|
569
|
+
* The body of a chat call: JSON when there are no files; MULTIPART when there
|
|
570
|
+
* are, the JSON in a `payload` part and each file in a `files` part. Count and
|
|
571
|
+
* size are judged here, before the wire.
|
|
572
|
+
*/
|
|
573
|
+
function chatBody(payload, files, headers) {
|
|
574
|
+
if (files.length === 0) {
|
|
575
|
+
return {
|
|
576
|
+
headers: headers({ "Content-Type": "application/json", Accept: "text/event-stream" }),
|
|
577
|
+
body: JSON.stringify(payload),
|
|
578
|
+
};
|
|
579
|
+
}
|
|
580
|
+
if (files.length > MAX_FILES_PER_RUN) {
|
|
581
|
+
throw new ValidationError(`At most ${MAX_FILES_PER_RUN} files can be sent with one call.`, undefined, undefined, "files");
|
|
582
|
+
}
|
|
583
|
+
const form = new FormData();
|
|
584
|
+
form.append("payload", JSON.stringify(payload));
|
|
585
|
+
for (const file of files) {
|
|
586
|
+
const [name, blob] = toBlob(file);
|
|
587
|
+
if (blob.size > MAX_UPLOAD_BYTES) {
|
|
588
|
+
throw new ValidationError(`${name}: larger than ${MAX_UPLOAD_BYTES / (1024 * 1024)} MB — add bigger files to the agent's knowledge instead.`, undefined, undefined, "files");
|
|
589
|
+
}
|
|
590
|
+
form.append("files", blob, name);
|
|
591
|
+
}
|
|
592
|
+
// NO Content-Type — fetch sets the multipart boundary itself.
|
|
593
|
+
return { headers: headers({ Accept: "text/event-stream" }), body: form };
|
|
594
|
+
}
|
|
527
595
|
/** One upload input, as a named Blob — the only shape `FormData` accepts. */
|
|
528
596
|
function toBlob(file) {
|
|
529
597
|
if (typeof Blob !== "undefined" && file instanceof Blob) {
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Promptev JavaScript client
|
|
2
2
|
|
|
3
|
-
The official JavaScript/TypeScript client for [Promptev](https://promptev.ai) — stream your AI **agents
|
|
3
|
+
The official JavaScript/TypeScript client for [Promptev](https://promptev.ai) — stream your AI **agents**, put documents into the Context Engine and search it, from anywhere that has `fetch`.
|
|
4
4
|
|
|
5
5
|
> In Promptev, an **agent** is your deployed AI assistant: instructions + model + tools (Jira, Slack, GitHub, your own APIs) + the documents it can retrieve, all configured in the app. This client runs those agents. Tools execute server-side, retrieval is governed server-side, and conversation memory is built in.
|
|
6
6
|
|
|
@@ -105,6 +105,28 @@ Passing `conversationId` is worth doing for a second reason: a tool set to **Ask
|
|
|
105
105
|
|
|
106
106
|
A thread belongs to the agent, to this API, **and** to the `onBehalfOf.subject` it was opened under. Keep the subject the same across a conversation's turns, and never reuse an id from the app, the portal or an embed — any mismatch answers `404`, not a fresh thread.
|
|
107
107
|
|
|
108
|
+
## Sending files with a message
|
|
109
|
+
|
|
110
|
+
Pass `files` and the agent reads them on that turn, in the same call. This is the paperclip of the promptev chat: the agent takes files only when **Chat attachments** is switched on in its builder, and only the types that chat takes.
|
|
111
|
+
|
|
112
|
+
```ts
|
|
113
|
+
import { readFile } from "node:fs/promises";
|
|
114
|
+
|
|
115
|
+
for await (const ev of client.chat("support-agent", "What is the total on this receipt?", {
|
|
116
|
+
files: [{ name: "receipt.png", content: await readFile("receipt.png") }], // or a File / Blob
|
|
117
|
+
})) {
|
|
118
|
+
if (ev.type === "token") process.stdout.write(ev.content);
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Up to **five files per call**, 25 MB each. An image is shown to a model that can see, and read into text for one that cannot. A document is read before the answer starts, so a long scan makes a slower first event. A call may carry files and an empty message.
|
|
123
|
+
|
|
124
|
+
| Status | When |
|
|
125
|
+
|---|---|
|
|
126
|
+
| 409 | The agent's Chat attachments is off |
|
|
127
|
+
| 415 | A file type the agent cannot take |
|
|
128
|
+
| 413 | The workspace is out of storage |
|
|
129
|
+
|
|
108
130
|
## Changing the model or a tool's values for one call
|
|
109
131
|
|
|
110
132
|
Both options are optional. Leave them out and the agent runs exactly as it was published. Nothing a call sends is stored: the next call runs the published agent again.
|
|
@@ -252,6 +274,25 @@ A per-file failure is *reported*, not thrown: every file gets a row in `results`
|
|
|
252
274
|
|
|
253
275
|
> Ingestion is slow and the request does not return until every file is indexed. Raise `timeout` well above its 30-second default: `new PromptevClient({ apiKey, timeout: 300_000 })`.
|
|
254
276
|
|
|
277
|
+
## `searchKnowledgeBase` — search the knowledge base
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
client.searchKnowledgeBase(action, fields?, options?): Promise<Record<string, any>>
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Reads your key's project knowledge base through the Context Engine. It is the same tool, with the same actions, as `search_knowledge_base` on the project's MCP server. Start with `discover` to see what is there, then `search` for passages or `get_doc` for one document:
|
|
284
|
+
|
|
285
|
+
```ts
|
|
286
|
+
const overview = await client.searchKnowledgeBase("discover");
|
|
287
|
+
|
|
288
|
+
const found = await client.searchKnowledgeBase("search", { query: "how many days do customers have to ask for a refund", top_k: 5 });
|
|
289
|
+
for (const hit of found.hits) console.log(hit.document_name, hit.score, hit.chunk_text);
|
|
290
|
+
|
|
291
|
+
const doc = await client.searchKnowledgeBase("get_doc", { document_id: found.hits[0].document_id });
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
The actions are exported as `KNOWLEDGE_ACTIONS`: `discover`, `search`, `get_doc`, `list`, `query_meta`, `compute`, `get_chunks`, `get_docs`, `map_reduce`, `traverse`, `find_related`, `get_neighbors` and `community_summary`. `fields` are that action's fields (`query`, `top_k`, `document_id`, `source_ids`, `mode`, `limit`, `cursor`, ...). The key reads only its own project.
|
|
295
|
+
|
|
255
296
|
## `runOrchestration` — run a team of agents
|
|
256
297
|
|
|
257
298
|
An orchestration is a **team of agents** working one job. `chat` streams one agent's answer inline; an orchestration runs in a worker for as long as it takes, so `runOrchestration` hands back a run id straight away and `getRun` says what became of it.
|
|
@@ -372,9 +413,7 @@ All errors extend `PromptevError` and carry:
|
|
|
372
413
|
## What a call costs
|
|
373
414
|
|
|
374
415
|
Promptev is pay as you go and this API is metered. The rates below are the
|
|
375
|
-
|
|
376
|
-
(BYO) is charged a flat **1** per operation instead, because those bills are
|
|
377
|
-
already yours.
|
|
416
|
+
same for every workspace, including one on its own database or models.
|
|
378
417
|
|
|
379
418
|
| what happens | credits |
|
|
380
419
|
|---|---|
|
|
@@ -384,6 +423,7 @@ already yours.
|
|
|
384
423
|
| retrieval | **1** per knowledge base searched |
|
|
385
424
|
| retrieval in graph mode | **5** per knowledge base searched |
|
|
386
425
|
| a document you upload | **1** per page, slide or MB (minimum 1) |
|
|
426
|
+
| `searchKnowledgeBase` | the same as on the MCP server: **1** per call, **+1** for a search (**+5** when the graph is searched); no `api_call` charge |
|
|
387
427
|
|
|
388
428
|
So an ordinary `chat` costs **2** — one for the request, one for the turn — and
|
|
389
429
|
more if the agent calls tools or searches knowledge. The same conversation held
|