@olbrain/js-sdk 1.1.0 → 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 CHANGED
@@ -91,6 +91,22 @@ const client = new AgentClient({ agentId: '...', apiKey: '...' });
91
91
  const response: ChatResponse = await client.sendAndWait(sessionId, 'Hi!');
92
92
  ```
93
93
 
94
+ ## Workflow runs and approvals
95
+
96
+ ```ts
97
+ import { Olbrain } from '@olbrain/js-sdk';
98
+
99
+ const olbrain = new Olbrain({ apiKey: 'ak_…' }); // servers and scripts
100
+ // const olbrain = new Olbrain({ getIdToken: () => user.getIdToken() }); // a signed-in Olbrain user
101
+
102
+ const { runId } = await olbrain.workflows.run(agentId, { payload: { deck: fileId } });
103
+ const run = await olbrain.runs.get(agentId, runId);
104
+ const pending = await olbrain.approvals.list(agentId, runId);
105
+ await olbrain.approvals.resolve(agentId, runId, { exceptionId: pending[0].exception_id, resolution: 'approved' });
106
+ ```
107
+
108
+ Errors carry the API's code: `BillingError` (the organization can't pay), `NotFoundError`, `AuthenticationError`, `RateLimitError`, and `ApiError` for everything else.
109
+
94
110
  ## 🎯 Core Concepts
95
111
 
96
112
  ### AgentClient
package/dist/index.d.mts CHANGED
@@ -191,6 +191,87 @@ declare class AgentClient {
191
191
  private _parseSessionInfo;
192
192
  }
193
193
 
194
+ interface OlbrainConfig {
195
+ /** An Olbrain access key, ak_… Give this or getIdToken. */
196
+ apiKey?: string;
197
+ /** Returns the signed-in user's Firebase ID token; called before every request. */
198
+ getIdToken?: () => Promise<string>;
199
+ /** Defaults to https://webhook.olbrain.com */
200
+ baseUrl?: string;
201
+ timeoutMs?: number;
202
+ }
203
+ interface RunSummary {
204
+ total_processed: number;
205
+ successful: number;
206
+ failed: number;
207
+ exceptions: number;
208
+ skipped: number;
209
+ }
210
+ interface Run {
211
+ run_id: string;
212
+ status: string;
213
+ progress_percent?: number;
214
+ started_at?: string | null;
215
+ completed_at?: string | null;
216
+ duration_seconds?: number | null;
217
+ error?: string | null;
218
+ summary?: RunSummary | null;
219
+ [key: string]: unknown;
220
+ }
221
+ interface Approval {
222
+ exception_id: string;
223
+ step_id: string;
224
+ item_id?: string | null;
225
+ data?: Record<string, unknown> | null;
226
+ error: string;
227
+ requires_human_review: boolean;
228
+ blocking: boolean;
229
+ }
230
+ interface ResolveInput {
231
+ exceptionId: string;
232
+ resolution: 'approved' | 'rejected' | 'modified';
233
+ /** Only with resolution "modified". */
234
+ modifiedData?: Record<string, unknown>;
235
+ }
236
+ interface ResolveResult {
237
+ exception_id: string;
238
+ resolution: string;
239
+ all_resolved: boolean;
240
+ resumed: boolean;
241
+ }
242
+ declare class Olbrain {
243
+ private readonly config;
244
+ private readonly baseUrl;
245
+ private readonly timeoutMs;
246
+ constructor(config: OlbrainConfig);
247
+ readonly workflows: {
248
+ run: (agentId: string, input?: {
249
+ payload?: unknown;
250
+ variables?: Record<string, unknown>;
251
+ }) => Promise<{
252
+ runId: string;
253
+ status: string;
254
+ }>;
255
+ };
256
+ readonly runs: {
257
+ list: (agentId: string, opts?: {
258
+ status?: string;
259
+ limit?: number;
260
+ }) => Promise<Run[]>;
261
+ get: (agentId: string, runId: string) => Promise<Run>;
262
+ cancel: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
263
+ pause: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
264
+ retry: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
265
+ resume: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
266
+ };
267
+ readonly approvals: {
268
+ list: (agentId: string, runId: string) => Promise<Approval[]>;
269
+ resolve: (agentId: string, runId: string, input: ResolveInput) => Promise<ResolveResult>;
270
+ };
271
+ private control;
272
+ private request;
273
+ }
274
+
194
275
  /**
195
276
  * Error classes for Olbrain SDK
196
277
  */
@@ -239,12 +320,25 @@ declare class ValidationError extends OlbrainError {
239
320
  declare class StreamingError extends OlbrainError {
240
321
  constructor(message?: string);
241
322
  }
323
+ /** An error the API answered with: its HTTP status and machine-readable code. */
324
+ declare class ApiError extends OlbrainError {
325
+ status: number;
326
+ code: string;
327
+ constructor(status: number, code: string, message: string);
328
+ }
329
+ declare class NotFoundError extends ApiError {
330
+ constructor(code?: string, message?: string);
331
+ }
332
+ /** The organization can't pay for this run (balance, credit limit or subscription). */
333
+ declare class BillingError extends ApiError {
334
+ constructor(status: number, code: string, message: string);
335
+ }
242
336
 
243
337
  /**
244
338
  * Olbrain JavaScript SDK
245
339
  * Main entry point for core API exports
246
340
  */
247
341
 
248
- declare const VERSION = "1.0.0";
342
+ declare const VERSION = "1.2.0";
249
343
 
250
- export { AgentClient, type AgentConfig, AuthenticationError, type ChatResponse, type CreateSessionOptions, type ErrorCallback, type Message, type MessageCallback, NetworkError, OlbrainError, RateLimitError, type SendOptions, type SessionInfo, SessionNotFoundError, type SessionStats, type SessionUpdates, type StreamConfig, StreamingError, type TokenUsage, VERSION, ValidationError, type WidgetConfig };
344
+ export { AgentClient, type AgentConfig, ApiError, type Approval, AuthenticationError, BillingError, type ChatResponse, type CreateSessionOptions, type ErrorCallback, type Message, type MessageCallback, NetworkError, NotFoundError, Olbrain, type OlbrainConfig, OlbrainError, RateLimitError, type ResolveInput, type ResolveResult, type Run, type RunSummary, type SendOptions, type SessionInfo, SessionNotFoundError, type SessionStats, type SessionUpdates, type StreamConfig, StreamingError, type TokenUsage, VERSION, ValidationError, type WidgetConfig };
package/dist/index.d.ts CHANGED
@@ -191,6 +191,87 @@ declare class AgentClient {
191
191
  private _parseSessionInfo;
192
192
  }
193
193
 
194
+ interface OlbrainConfig {
195
+ /** An Olbrain access key, ak_… Give this or getIdToken. */
196
+ apiKey?: string;
197
+ /** Returns the signed-in user's Firebase ID token; called before every request. */
198
+ getIdToken?: () => Promise<string>;
199
+ /** Defaults to https://webhook.olbrain.com */
200
+ baseUrl?: string;
201
+ timeoutMs?: number;
202
+ }
203
+ interface RunSummary {
204
+ total_processed: number;
205
+ successful: number;
206
+ failed: number;
207
+ exceptions: number;
208
+ skipped: number;
209
+ }
210
+ interface Run {
211
+ run_id: string;
212
+ status: string;
213
+ progress_percent?: number;
214
+ started_at?: string | null;
215
+ completed_at?: string | null;
216
+ duration_seconds?: number | null;
217
+ error?: string | null;
218
+ summary?: RunSummary | null;
219
+ [key: string]: unknown;
220
+ }
221
+ interface Approval {
222
+ exception_id: string;
223
+ step_id: string;
224
+ item_id?: string | null;
225
+ data?: Record<string, unknown> | null;
226
+ error: string;
227
+ requires_human_review: boolean;
228
+ blocking: boolean;
229
+ }
230
+ interface ResolveInput {
231
+ exceptionId: string;
232
+ resolution: 'approved' | 'rejected' | 'modified';
233
+ /** Only with resolution "modified". */
234
+ modifiedData?: Record<string, unknown>;
235
+ }
236
+ interface ResolveResult {
237
+ exception_id: string;
238
+ resolution: string;
239
+ all_resolved: boolean;
240
+ resumed: boolean;
241
+ }
242
+ declare class Olbrain {
243
+ private readonly config;
244
+ private readonly baseUrl;
245
+ private readonly timeoutMs;
246
+ constructor(config: OlbrainConfig);
247
+ readonly workflows: {
248
+ run: (agentId: string, input?: {
249
+ payload?: unknown;
250
+ variables?: Record<string, unknown>;
251
+ }) => Promise<{
252
+ runId: string;
253
+ status: string;
254
+ }>;
255
+ };
256
+ readonly runs: {
257
+ list: (agentId: string, opts?: {
258
+ status?: string;
259
+ limit?: number;
260
+ }) => Promise<Run[]>;
261
+ get: (agentId: string, runId: string) => Promise<Run>;
262
+ cancel: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
263
+ pause: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
264
+ retry: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
265
+ resume: (agentId: string, runId: string) => Promise<Record<string, unknown>>;
266
+ };
267
+ readonly approvals: {
268
+ list: (agentId: string, runId: string) => Promise<Approval[]>;
269
+ resolve: (agentId: string, runId: string, input: ResolveInput) => Promise<ResolveResult>;
270
+ };
271
+ private control;
272
+ private request;
273
+ }
274
+
194
275
  /**
195
276
  * Error classes for Olbrain SDK
196
277
  */
@@ -239,12 +320,25 @@ declare class ValidationError extends OlbrainError {
239
320
  declare class StreamingError extends OlbrainError {
240
321
  constructor(message?: string);
241
322
  }
323
+ /** An error the API answered with: its HTTP status and machine-readable code. */
324
+ declare class ApiError extends OlbrainError {
325
+ status: number;
326
+ code: string;
327
+ constructor(status: number, code: string, message: string);
328
+ }
329
+ declare class NotFoundError extends ApiError {
330
+ constructor(code?: string, message?: string);
331
+ }
332
+ /** The organization can't pay for this run (balance, credit limit or subscription). */
333
+ declare class BillingError extends ApiError {
334
+ constructor(status: number, code: string, message: string);
335
+ }
242
336
 
243
337
  /**
244
338
  * Olbrain JavaScript SDK
245
339
  * Main entry point for core API exports
246
340
  */
247
341
 
248
- declare const VERSION = "1.0.0";
342
+ declare const VERSION = "1.2.0";
249
343
 
250
- export { AgentClient, type AgentConfig, AuthenticationError, type ChatResponse, type CreateSessionOptions, type ErrorCallback, type Message, type MessageCallback, NetworkError, OlbrainError, RateLimitError, type SendOptions, type SessionInfo, SessionNotFoundError, type SessionStats, type SessionUpdates, type StreamConfig, StreamingError, type TokenUsage, VERSION, ValidationError, type WidgetConfig };
344
+ export { AgentClient, type AgentConfig, ApiError, type Approval, AuthenticationError, BillingError, type ChatResponse, type CreateSessionOptions, type ErrorCallback, type Message, type MessageCallback, NetworkError, NotFoundError, Olbrain, type OlbrainConfig, OlbrainError, RateLimitError, type ResolveInput, type ResolveResult, type Run, type RunSummary, type SendOptions, type SessionInfo, SessionNotFoundError, type SessionStats, type SessionUpdates, type StreamConfig, StreamingError, type TokenUsage, VERSION, ValidationError, type WidgetConfig };
@@ -416,8 +416,12 @@ var Olbrain = (() => {
416
416
  var index_exports = {};
417
417
  __export(index_exports, {
418
418
  AgentClient: () => AgentClient,
419
+ ApiError: () => ApiError,
419
420
  AuthenticationError: () => AuthenticationError,
421
+ BillingError: () => BillingError,
420
422
  NetworkError: () => NetworkError,
423
+ NotFoundError: () => NotFoundError,
424
+ Olbrain: () => Olbrain,
421
425
  OlbrainError: () => OlbrainError,
422
426
  RateLimitError: () => RateLimitError,
423
427
  SessionNotFoundError: () => SessionNotFoundError,
@@ -479,16 +483,39 @@ var Olbrain = (() => {
479
483
  Object.setPrototypeOf(this, _StreamingError.prototype);
480
484
  }
481
485
  };
486
+ var ApiError = class _ApiError extends OlbrainError {
487
+ constructor(status, code, message) {
488
+ super(message);
489
+ this.name = "ApiError";
490
+ this.status = status;
491
+ this.code = code;
492
+ Object.setPrototypeOf(this, _ApiError.prototype);
493
+ }
494
+ };
495
+ var NotFoundError = class _NotFoundError extends ApiError {
496
+ constructor(code = "not_found", message = "Not found") {
497
+ super(404, code, message);
498
+ this.name = "NotFoundError";
499
+ Object.setPrototypeOf(this, _NotFoundError.prototype);
500
+ }
501
+ };
502
+ var BillingError = class _BillingError extends ApiError {
503
+ constructor(status, code, message) {
504
+ super(status, code, message);
505
+ this.name = "BillingError";
506
+ Object.setPrototypeOf(this, _BillingError.prototype);
507
+ }
508
+ };
482
509
 
483
510
  // src/core/utils.ts
484
511
  function validateApiKey(apiKey) {
485
512
  if (!apiKey) {
486
513
  throw new ValidationError("API key is required");
487
514
  }
488
- const validPrefixes = ["sk_live_", "org_live_", "sk_", "org_"];
515
+ const validPrefixes = ["ak_", "sk_live_", "org_live_", "sk_", "org_"];
489
516
  if (!validPrefixes.some((prefix) => apiKey.startsWith(prefix))) {
490
517
  throw new ValidationError(
491
- "Invalid API key format. Must start with sk_, org_, sk_live_, or org_live_"
518
+ "Invalid API key format. Must start with ak_, sk_, org_, sk_live_, or org_live_"
492
519
  );
493
520
  }
494
521
  }
@@ -508,7 +535,7 @@ var Olbrain = (() => {
508
535
  return typeof window !== "undefined" && typeof document !== "undefined";
509
536
  }
510
537
  function isNode() {
511
- return typeof process !== "undefined" && process.versions && process.versions.node;
538
+ return typeof process !== "undefined" && !!process.versions?.node;
512
539
  }
513
540
  async function getEventSourceImpl() {
514
541
  if (isBrowser()) {
@@ -972,8 +999,98 @@ var Olbrain = (() => {
972
999
  }
973
1000
  };
974
1001
 
1002
+ // src/core/olbrain.ts
1003
+ var DEFAULT_BASE_URL2 = "https://webhook.olbrain.com";
1004
+ var BILLING_CODES = /* @__PURE__ */ new Set([
1005
+ "insufficient_funds",
1006
+ "credit_limit_exceeded",
1007
+ "subscription_suspended",
1008
+ "subscription_inactive",
1009
+ "billing_unavailable"
1010
+ ]);
1011
+ var enc = encodeURIComponent;
1012
+ var Olbrain = class {
1013
+ constructor(config) {
1014
+ this.config = config;
1015
+ this.workflows = {
1016
+ run: async (agentId, input = {}) => {
1017
+ const out = await this.request("POST", `/api/workflows/${enc(agentId)}/trigger`, input);
1018
+ return { runId: out.run_id, status: out.status };
1019
+ }
1020
+ };
1021
+ this.runs = {
1022
+ list: (agentId, opts = {}) => {
1023
+ const q = new URLSearchParams();
1024
+ if (opts.limit !== void 0) q.set("limit", String(opts.limit));
1025
+ if (opts.status) q.set("status", opts.status);
1026
+ const qs = q.toString();
1027
+ return this.request("GET", `/api/agents/${enc(agentId)}/runs${qs ? `?${qs}` : ""}`);
1028
+ },
1029
+ get: (agentId, runId) => this.request("GET", `/api/agents/${enc(agentId)}/runs/${enc(runId)}`),
1030
+ cancel: (agentId, runId) => this.control(agentId, runId, "cancel"),
1031
+ pause: (agentId, runId) => this.control(agentId, runId, "pause"),
1032
+ retry: (agentId, runId) => this.control(agentId, runId, "retry"),
1033
+ resume: (agentId, runId) => this.control(agentId, runId, "resume")
1034
+ };
1035
+ this.approvals = {
1036
+ list: (agentId, runId) => this.request("GET", `/api/agents/${enc(agentId)}/runs/${enc(runId)}/approvals`),
1037
+ resolve: (agentId, runId, input) => this.request("POST", `/api/agents/${enc(agentId)}/runs/${enc(runId)}/approvals/resolve`, {
1038
+ exception_id: input.exceptionId,
1039
+ resolution: input.resolution,
1040
+ ...input.modifiedData ? { modified_data: input.modifiedData } : {}
1041
+ })
1042
+ };
1043
+ if (!config || Boolean(config.apiKey) === Boolean(config.getIdToken)) {
1044
+ throw new ValidationError("Give exactly one of apiKey or getIdToken");
1045
+ }
1046
+ if (config.apiKey && !config.apiKey.startsWith("ak_")) {
1047
+ throw new ValidationError("apiKey must be an Olbrain access key (ak_\u2026)");
1048
+ }
1049
+ this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL2).replace(/\/$/, "");
1050
+ this.timeoutMs = config.timeoutMs ?? 3e4;
1051
+ }
1052
+ control(agentId, runId, verb) {
1053
+ return this.request("POST", `/api/agents/${enc(agentId)}/runs/${enc(runId)}/${verb}`);
1054
+ }
1055
+ async request(method, path, body) {
1056
+ const token = this.config.apiKey ?? await this.config.getIdToken();
1057
+ const headers = { Authorization: `Bearer ${token}` };
1058
+ if (body !== void 0) headers["Content-Type"] = "application/json";
1059
+ const controller = new AbortController();
1060
+ const timer = setTimeout(() => controller.abort(), this.timeoutMs);
1061
+ let res;
1062
+ try {
1063
+ res = await fetch(`${this.baseUrl}${path}`, {
1064
+ method,
1065
+ headers,
1066
+ body: body === void 0 ? void 0 : JSON.stringify(body),
1067
+ signal: controller.signal
1068
+ });
1069
+ } catch (err) {
1070
+ const e = err;
1071
+ throw new NetworkError(e?.name === "AbortError" ? `Request timed out after ${this.timeoutMs}ms` : e?.message || "Network error");
1072
+ } finally {
1073
+ clearTimeout(timer);
1074
+ }
1075
+ const data = await res.json().catch(() => void 0);
1076
+ if (res.ok) return data;
1077
+ const detail = data?.detail;
1078
+ const pick = (k) => [data?.error?.[k], typeof detail === "object" && !Array.isArray(detail) ? detail?.[k] : void 0, data?.[k]].find((v) => typeof v === "string" && v);
1079
+ const code = pick("code") ?? "error";
1080
+ const message = data?.error?.message ?? (typeof detail === "string" && detail ? detail : void 0) ?? pick("message") ?? (res.statusText || "Request failed");
1081
+ if (BILLING_CODES.has(code)) throw new BillingError(res.status, code, message);
1082
+ if (res.status === 401) throw new AuthenticationError(message);
1083
+ if (res.status === 404) throw new NotFoundError(code, message);
1084
+ if (res.status === 429) {
1085
+ const retryAfter = Number(res.headers.get("Retry-After"));
1086
+ throw new RateLimitError(message, Number.isFinite(retryAfter) && retryAfter > 0 ? retryAfter : void 0);
1087
+ }
1088
+ throw new ApiError(res.status, code, message);
1089
+ }
1090
+ };
1091
+
975
1092
  // src/index.ts
976
- var VERSION = "1.0.0";
1093
+ var VERSION = "1.2.0";
977
1094
  return __toCommonJS(index_exports);
978
1095
  })();
979
1096
  //# sourceMappingURL=index.global.js.map