@olbrain/js-sdk 1.0.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/index.js ADDED
@@ -0,0 +1,1001 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __commonJS = (cb, mod) => function __require() {
12
+ return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
13
+ };
14
+ var __export = (target, all) => {
15
+ for (var name in all)
16
+ __defProp(target, name, { get: all[name], enumerable: true });
17
+ };
18
+ var __copyProps = (to, from, except, desc) => {
19
+ if (from && typeof from === "object" || typeof from === "function") {
20
+ for (let key of __getOwnPropNames(from))
21
+ if (!__hasOwnProp.call(to, key) && key !== except)
22
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
23
+ }
24
+ return to;
25
+ };
26
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
27
+ // If the importer is in node compatibility mode or this is not an ESM
28
+ // file that has been converted to a CommonJS file using a Babel-
29
+ // compatible transform (i.e. "__esModule" has not been set), then set
30
+ // "default" to the CommonJS "module.exports" for node compatibility.
31
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
32
+ mod
33
+ ));
34
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
35
+
36
+ // node_modules/tsup/assets/cjs_shims.js
37
+ var init_cjs_shims = __esm({
38
+ "node_modules/tsup/assets/cjs_shims.js"() {
39
+ "use strict";
40
+ }
41
+ });
42
+
43
+ // node_modules/eventsource/lib/eventsource.js
44
+ var require_eventsource = __commonJS({
45
+ "node_modules/eventsource/lib/eventsource.js"(exports2, module2) {
46
+ "use strict";
47
+ init_cjs_shims();
48
+ var parse = require("url").parse;
49
+ var events = require("events");
50
+ var https = require("https");
51
+ var http = require("http");
52
+ var util = require("util");
53
+ var httpsOptions = [
54
+ "pfx",
55
+ "key",
56
+ "passphrase",
57
+ "cert",
58
+ "ca",
59
+ "ciphers",
60
+ "rejectUnauthorized",
61
+ "secureProtocol",
62
+ "servername",
63
+ "checkServerIdentity"
64
+ ];
65
+ var bom = [239, 187, 191];
66
+ var colon = 58;
67
+ var space = 32;
68
+ var lineFeed = 10;
69
+ var carriageReturn = 13;
70
+ var maxBufferAheadAllocation = 1024 * 256;
71
+ var reUnsafeHeader = /^(cookie|authorization)$/i;
72
+ function hasBom(buf) {
73
+ return bom.every(function(charCode, index) {
74
+ return buf[index] === charCode;
75
+ });
76
+ }
77
+ function EventSource2(url, eventSourceInitDict) {
78
+ var readyState = EventSource2.CONNECTING;
79
+ var headers = eventSourceInitDict && eventSourceInitDict.headers;
80
+ var hasNewOrigin = false;
81
+ Object.defineProperty(this, "readyState", {
82
+ get: function() {
83
+ return readyState;
84
+ }
85
+ });
86
+ Object.defineProperty(this, "url", {
87
+ get: function() {
88
+ return url;
89
+ }
90
+ });
91
+ var self = this;
92
+ self.reconnectInterval = 1e3;
93
+ self.connectionInProgress = false;
94
+ function onConnectionClosed(message) {
95
+ if (readyState === EventSource2.CLOSED) return;
96
+ readyState = EventSource2.CONNECTING;
97
+ _emit("error", new Event("error", { message }));
98
+ if (reconnectUrl) {
99
+ url = reconnectUrl;
100
+ reconnectUrl = null;
101
+ hasNewOrigin = false;
102
+ }
103
+ setTimeout(function() {
104
+ if (readyState !== EventSource2.CONNECTING || self.connectionInProgress) {
105
+ return;
106
+ }
107
+ self.connectionInProgress = true;
108
+ connect();
109
+ }, self.reconnectInterval);
110
+ }
111
+ var req;
112
+ var lastEventId = "";
113
+ if (headers && headers["Last-Event-ID"]) {
114
+ lastEventId = headers["Last-Event-ID"];
115
+ delete headers["Last-Event-ID"];
116
+ }
117
+ var discardTrailingNewline = false;
118
+ var data = "";
119
+ var eventName = "";
120
+ var reconnectUrl = null;
121
+ function connect() {
122
+ var options = parse(url);
123
+ var isSecure = options.protocol === "https:";
124
+ options.headers = { "Cache-Control": "no-cache", "Accept": "text/event-stream" };
125
+ if (lastEventId) options.headers["Last-Event-ID"] = lastEventId;
126
+ if (headers) {
127
+ var reqHeaders = hasNewOrigin ? removeUnsafeHeaders(headers) : headers;
128
+ for (var i in reqHeaders) {
129
+ var header = reqHeaders[i];
130
+ if (header) {
131
+ options.headers[i] = header;
132
+ }
133
+ }
134
+ }
135
+ options.rejectUnauthorized = !(eventSourceInitDict && !eventSourceInitDict.rejectUnauthorized);
136
+ if (eventSourceInitDict && eventSourceInitDict.createConnection !== void 0) {
137
+ options.createConnection = eventSourceInitDict.createConnection;
138
+ }
139
+ var useProxy = eventSourceInitDict && eventSourceInitDict.proxy;
140
+ if (useProxy) {
141
+ var proxy = parse(eventSourceInitDict.proxy);
142
+ isSecure = proxy.protocol === "https:";
143
+ options.protocol = isSecure ? "https:" : "http:";
144
+ options.path = url;
145
+ options.headers.Host = options.host;
146
+ options.hostname = proxy.hostname;
147
+ options.host = proxy.host;
148
+ options.port = proxy.port;
149
+ }
150
+ if (eventSourceInitDict && eventSourceInitDict.https) {
151
+ for (var optName in eventSourceInitDict.https) {
152
+ if (httpsOptions.indexOf(optName) === -1) {
153
+ continue;
154
+ }
155
+ var option = eventSourceInitDict.https[optName];
156
+ if (option !== void 0) {
157
+ options[optName] = option;
158
+ }
159
+ }
160
+ }
161
+ if (eventSourceInitDict && eventSourceInitDict.withCredentials !== void 0) {
162
+ options.withCredentials = eventSourceInitDict.withCredentials;
163
+ }
164
+ req = (isSecure ? https : http).request(options, function(res) {
165
+ self.connectionInProgress = false;
166
+ if (res.statusCode === 500 || res.statusCode === 502 || res.statusCode === 503 || res.statusCode === 504) {
167
+ _emit("error", new Event("error", { status: res.statusCode, message: res.statusMessage }));
168
+ onConnectionClosed();
169
+ return;
170
+ }
171
+ if (res.statusCode === 301 || res.statusCode === 302 || res.statusCode === 307) {
172
+ var location = res.headers.location;
173
+ if (!location) {
174
+ _emit("error", new Event("error", { status: res.statusCode, message: res.statusMessage }));
175
+ return;
176
+ }
177
+ var prevOrigin = new URL(url).origin;
178
+ var nextOrigin = new URL(location).origin;
179
+ hasNewOrigin = prevOrigin !== nextOrigin;
180
+ if (res.statusCode === 307) reconnectUrl = url;
181
+ url = location;
182
+ process.nextTick(connect);
183
+ return;
184
+ }
185
+ if (res.statusCode !== 200) {
186
+ _emit("error", new Event("error", { status: res.statusCode, message: res.statusMessage }));
187
+ return self.close();
188
+ }
189
+ readyState = EventSource2.OPEN;
190
+ res.on("close", function() {
191
+ res.removeAllListeners("close");
192
+ res.removeAllListeners("end");
193
+ onConnectionClosed();
194
+ });
195
+ res.on("end", function() {
196
+ res.removeAllListeners("close");
197
+ res.removeAllListeners("end");
198
+ onConnectionClosed();
199
+ });
200
+ _emit("open", new Event("open"));
201
+ var buf;
202
+ var newBuffer;
203
+ var startingPos = 0;
204
+ var startingFieldLength = -1;
205
+ var newBufferSize = 0;
206
+ var bytesUsed = 0;
207
+ res.on("data", function(chunk) {
208
+ if (!buf) {
209
+ buf = chunk;
210
+ if (hasBom(buf)) {
211
+ buf = buf.slice(bom.length);
212
+ }
213
+ bytesUsed = buf.length;
214
+ } else {
215
+ if (chunk.length > buf.length - bytesUsed) {
216
+ newBufferSize = buf.length * 2 + chunk.length;
217
+ if (newBufferSize > maxBufferAheadAllocation) {
218
+ newBufferSize = buf.length + chunk.length + maxBufferAheadAllocation;
219
+ }
220
+ newBuffer = Buffer.alloc(newBufferSize);
221
+ buf.copy(newBuffer, 0, 0, bytesUsed);
222
+ buf = newBuffer;
223
+ }
224
+ chunk.copy(buf, bytesUsed);
225
+ bytesUsed += chunk.length;
226
+ }
227
+ var pos = 0;
228
+ var length = bytesUsed;
229
+ while (pos < length) {
230
+ if (discardTrailingNewline) {
231
+ if (buf[pos] === lineFeed) {
232
+ ++pos;
233
+ }
234
+ discardTrailingNewline = false;
235
+ }
236
+ var lineLength = -1;
237
+ var fieldLength = startingFieldLength;
238
+ var c;
239
+ for (var i2 = startingPos; lineLength < 0 && i2 < length; ++i2) {
240
+ c = buf[i2];
241
+ if (c === colon) {
242
+ if (fieldLength < 0) {
243
+ fieldLength = i2 - pos;
244
+ }
245
+ } else if (c === carriageReturn) {
246
+ discardTrailingNewline = true;
247
+ lineLength = i2 - pos;
248
+ } else if (c === lineFeed) {
249
+ lineLength = i2 - pos;
250
+ }
251
+ }
252
+ if (lineLength < 0) {
253
+ startingPos = length - pos;
254
+ startingFieldLength = fieldLength;
255
+ break;
256
+ } else {
257
+ startingPos = 0;
258
+ startingFieldLength = -1;
259
+ }
260
+ parseEventStreamLine(buf, pos, fieldLength, lineLength);
261
+ pos += lineLength + 1;
262
+ }
263
+ if (pos === length) {
264
+ buf = void 0;
265
+ bytesUsed = 0;
266
+ } else if (pos > 0) {
267
+ buf = buf.slice(pos, bytesUsed);
268
+ bytesUsed = buf.length;
269
+ }
270
+ });
271
+ });
272
+ req.on("error", function(err) {
273
+ self.connectionInProgress = false;
274
+ onConnectionClosed(err.message);
275
+ });
276
+ if (req.setNoDelay) req.setNoDelay(true);
277
+ req.end();
278
+ }
279
+ connect();
280
+ function _emit() {
281
+ if (self.listeners(arguments[0]).length > 0) {
282
+ self.emit.apply(self, arguments);
283
+ }
284
+ }
285
+ this._close = function() {
286
+ if (readyState === EventSource2.CLOSED) return;
287
+ readyState = EventSource2.CLOSED;
288
+ if (req.abort) req.abort();
289
+ if (req.xhr && req.xhr.abort) req.xhr.abort();
290
+ };
291
+ function parseEventStreamLine(buf, pos, fieldLength, lineLength) {
292
+ if (lineLength === 0) {
293
+ if (data.length > 0) {
294
+ var type = eventName || "message";
295
+ _emit(type, new MessageEvent(type, {
296
+ data: data.slice(0, -1),
297
+ // remove trailing newline
298
+ lastEventId,
299
+ origin: new URL(url).origin
300
+ }));
301
+ data = "";
302
+ }
303
+ eventName = void 0;
304
+ } else if (fieldLength > 0) {
305
+ var noValue = fieldLength < 0;
306
+ var step = 0;
307
+ var field = buf.slice(pos, pos + (noValue ? lineLength : fieldLength)).toString();
308
+ if (noValue) {
309
+ step = lineLength;
310
+ } else if (buf[pos + fieldLength + 1] !== space) {
311
+ step = fieldLength + 1;
312
+ } else {
313
+ step = fieldLength + 2;
314
+ }
315
+ pos += step;
316
+ var valueLength = lineLength - step;
317
+ var value = buf.slice(pos, pos + valueLength).toString();
318
+ if (field === "data") {
319
+ data += value + "\n";
320
+ } else if (field === "event") {
321
+ eventName = value;
322
+ } else if (field === "id") {
323
+ lastEventId = value;
324
+ } else if (field === "retry") {
325
+ var retry = parseInt(value, 10);
326
+ if (!Number.isNaN(retry)) {
327
+ self.reconnectInterval = retry;
328
+ }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ module2.exports = EventSource2;
334
+ util.inherits(EventSource2, events.EventEmitter);
335
+ EventSource2.prototype.constructor = EventSource2;
336
+ ["open", "error", "message"].forEach(function(method) {
337
+ Object.defineProperty(EventSource2.prototype, "on" + method, {
338
+ /**
339
+ * Returns the current listener
340
+ *
341
+ * @return {Mixed} the set function or undefined
342
+ * @api private
343
+ */
344
+ get: function get() {
345
+ var listener = this.listeners(method)[0];
346
+ return listener ? listener._listener ? listener._listener : listener : void 0;
347
+ },
348
+ /**
349
+ * Start listening for events
350
+ *
351
+ * @param {Function} listener the listener
352
+ * @return {Mixed} the set function or undefined
353
+ * @api private
354
+ */
355
+ set: function set(listener) {
356
+ this.removeAllListeners(method);
357
+ this.addEventListener(method, listener);
358
+ }
359
+ });
360
+ });
361
+ Object.defineProperty(EventSource2, "CONNECTING", { enumerable: true, value: 0 });
362
+ Object.defineProperty(EventSource2, "OPEN", { enumerable: true, value: 1 });
363
+ Object.defineProperty(EventSource2, "CLOSED", { enumerable: true, value: 2 });
364
+ EventSource2.prototype.CONNECTING = 0;
365
+ EventSource2.prototype.OPEN = 1;
366
+ EventSource2.prototype.CLOSED = 2;
367
+ EventSource2.prototype.close = function() {
368
+ this._close();
369
+ };
370
+ EventSource2.prototype.addEventListener = function addEventListener(type, listener) {
371
+ if (typeof listener === "function") {
372
+ listener._listener = listener;
373
+ this.on(type, listener);
374
+ }
375
+ };
376
+ EventSource2.prototype.dispatchEvent = function dispatchEvent(event) {
377
+ if (!event.type) {
378
+ throw new Error("UNSPECIFIED_EVENT_TYPE_ERR");
379
+ }
380
+ this.emit(event.type, event.detail);
381
+ };
382
+ EventSource2.prototype.removeEventListener = function removeEventListener(type, listener) {
383
+ if (typeof listener === "function") {
384
+ listener._listener = void 0;
385
+ this.removeListener(type, listener);
386
+ }
387
+ };
388
+ function Event(type, optionalProperties) {
389
+ Object.defineProperty(this, "type", { writable: false, value: type, enumerable: true });
390
+ if (optionalProperties) {
391
+ for (var f in optionalProperties) {
392
+ if (optionalProperties.hasOwnProperty(f)) {
393
+ Object.defineProperty(this, f, { writable: false, value: optionalProperties[f], enumerable: true });
394
+ }
395
+ }
396
+ }
397
+ }
398
+ function MessageEvent(type, eventInitDict) {
399
+ Object.defineProperty(this, "type", { writable: false, value: type, enumerable: true });
400
+ for (var f in eventInitDict) {
401
+ if (eventInitDict.hasOwnProperty(f)) {
402
+ Object.defineProperty(this, f, { writable: false, value: eventInitDict[f], enumerable: true });
403
+ }
404
+ }
405
+ }
406
+ function removeUnsafeHeaders(headers) {
407
+ var safe = {};
408
+ for (var key in headers) {
409
+ if (reUnsafeHeader.test(key)) {
410
+ continue;
411
+ }
412
+ safe[key] = headers[key];
413
+ }
414
+ return safe;
415
+ }
416
+ }
417
+ });
418
+
419
+ // src/index.ts
420
+ var index_exports = {};
421
+ __export(index_exports, {
422
+ AgentClient: () => AgentClient,
423
+ AuthenticationError: () => AuthenticationError,
424
+ NetworkError: () => NetworkError,
425
+ OlbrainError: () => OlbrainError,
426
+ RateLimitError: () => RateLimitError,
427
+ SessionNotFoundError: () => SessionNotFoundError,
428
+ StreamingError: () => StreamingError,
429
+ VERSION: () => VERSION,
430
+ ValidationError: () => ValidationError
431
+ });
432
+ module.exports = __toCommonJS(index_exports);
433
+ init_cjs_shims();
434
+
435
+ // src/core/client.ts
436
+ init_cjs_shims();
437
+
438
+ // src/core/exceptions.ts
439
+ init_cjs_shims();
440
+ var OlbrainError = class _OlbrainError extends Error {
441
+ constructor(message) {
442
+ super(message);
443
+ this.name = "OlbrainError";
444
+ Object.setPrototypeOf(this, _OlbrainError.prototype);
445
+ }
446
+ };
447
+ var AuthenticationError = class _AuthenticationError extends OlbrainError {
448
+ constructor(message = "Authentication failed") {
449
+ super(message);
450
+ this.name = "AuthenticationError";
451
+ Object.setPrototypeOf(this, _AuthenticationError.prototype);
452
+ }
453
+ };
454
+ var SessionNotFoundError = class _SessionNotFoundError extends OlbrainError {
455
+ constructor(sessionId) {
456
+ super(`Session not found: ${sessionId}`);
457
+ this.name = "SessionNotFoundError";
458
+ this.sessionId = sessionId;
459
+ Object.setPrototypeOf(this, _SessionNotFoundError.prototype);
460
+ }
461
+ };
462
+ var RateLimitError = class _RateLimitError extends OlbrainError {
463
+ constructor(message = "Rate limit exceeded", retryAfter) {
464
+ super(message);
465
+ this.name = "RateLimitError";
466
+ this.retryAfter = retryAfter;
467
+ Object.setPrototypeOf(this, _RateLimitError.prototype);
468
+ }
469
+ };
470
+ var NetworkError = class _NetworkError extends OlbrainError {
471
+ constructor(message = "Network error", statusCode) {
472
+ super(message);
473
+ this.name = "NetworkError";
474
+ this.statusCode = statusCode;
475
+ Object.setPrototypeOf(this, _NetworkError.prototype);
476
+ }
477
+ };
478
+ var ValidationError = class _ValidationError extends OlbrainError {
479
+ constructor(message = "Validation error") {
480
+ super(message);
481
+ this.name = "ValidationError";
482
+ Object.setPrototypeOf(this, _ValidationError.prototype);
483
+ }
484
+ };
485
+ var StreamingError = class _StreamingError extends OlbrainError {
486
+ constructor(message = "Streaming error") {
487
+ super(message);
488
+ this.name = "StreamingError";
489
+ Object.setPrototypeOf(this, _StreamingError.prototype);
490
+ }
491
+ };
492
+
493
+ // src/core/utils.ts
494
+ init_cjs_shims();
495
+ function validateApiKey(apiKey) {
496
+ if (!apiKey) {
497
+ throw new ValidationError("API key is required");
498
+ }
499
+ const validPrefixes = ["sk_live_", "org_live_", "sk_", "org_"];
500
+ if (!validPrefixes.some((prefix) => apiKey.startsWith(prefix))) {
501
+ throw new ValidationError(
502
+ "Invalid API key format. Must start with sk_, org_, sk_live_, or org_live_"
503
+ );
504
+ }
505
+ }
506
+ function validateAgentId(agentId) {
507
+ if (!agentId) {
508
+ throw new ValidationError("Agent ID is required");
509
+ }
510
+ }
511
+ function formatAuthHeader(apiKey) {
512
+ return `Bearer ${apiKey}`;
513
+ }
514
+ function getExponentialBackoffDelay(attempt, baseDelay = 5e3, maxDelay = 6e4) {
515
+ const delay2 = baseDelay * Math.pow(2, attempt);
516
+ return Math.min(delay2, maxDelay);
517
+ }
518
+ function isBrowser() {
519
+ return typeof window !== "undefined" && typeof document !== "undefined";
520
+ }
521
+ function isNode() {
522
+ return typeof process !== "undefined" && process.versions && process.versions.node;
523
+ }
524
+ async function getEventSourceImpl() {
525
+ if (isBrowser()) {
526
+ return EventSource;
527
+ }
528
+ if (isNode()) {
529
+ try {
530
+ const { EventSource: NodeEventSource } = await Promise.resolve().then(() => __toESM(require_eventsource()));
531
+ return NodeEventSource;
532
+ } catch {
533
+ throw new Error(
534
+ 'EventSource not available in Node.js. Install "eventsource" package: npm install eventsource'
535
+ );
536
+ }
537
+ }
538
+ throw new Error("EventSource not available in this environment");
539
+ }
540
+
541
+ // src/core/streaming.ts
542
+ init_cjs_shims();
543
+ var MessageStream = class {
544
+ constructor(config, onMessage, onError) {
545
+ this.isRunning = false;
546
+ this.reconnectAttempt = 0;
547
+ this.config = config;
548
+ this.onMessage = onMessage;
549
+ this.onError = onError;
550
+ }
551
+ /**
552
+ * Start the streaming connection
553
+ */
554
+ async start() {
555
+ if (this.isRunning) {
556
+ return;
557
+ }
558
+ this.isRunning = true;
559
+ this.reconnectAttempt = 0;
560
+ await this._connect();
561
+ }
562
+ /**
563
+ * Stop the streaming connection
564
+ */
565
+ stop() {
566
+ this.isRunning = false;
567
+ this._cleanup();
568
+ }
569
+ /**
570
+ * Establish SSE connection
571
+ */
572
+ async _connect() {
573
+ try {
574
+ const EventSourceImpl = await getEventSourceImpl();
575
+ const url = `${this.config.baseUrl}/sessions/${this.config.sessionId}/stream`;
576
+ const headers = {
577
+ "Authorization": formatAuthHeader(this.config.apiKey),
578
+ "X-Agent-ID": this.config.agentId
579
+ };
580
+ this.eventSource = new EventSourceImpl(url, { headers });
581
+ this.eventSource.addEventListener("message", (event) => {
582
+ this._handleMessage(event);
583
+ });
584
+ this.eventSource.addEventListener("ping", () => {
585
+ });
586
+ this.eventSource.addEventListener("error", () => {
587
+ this._handleConnectionError();
588
+ });
589
+ this.reconnectAttempt = 0;
590
+ } catch (error) {
591
+ this._handleConnectionError();
592
+ }
593
+ }
594
+ /**
595
+ * Handle incoming message event
596
+ */
597
+ _handleMessage(event) {
598
+ if (!event.data) {
599
+ return;
600
+ }
601
+ try {
602
+ const data = JSON.parse(event.data);
603
+ if (data.type === "ping" || data.type === "keepalive") {
604
+ return;
605
+ }
606
+ if (data.role && data.content) {
607
+ const message = {
608
+ role: data.role,
609
+ content: data.content,
610
+ timestamp: data.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
611
+ metadata: data.metadata
612
+ };
613
+ this.onMessage(message);
614
+ }
615
+ } catch (error) {
616
+ if (this.onError) {
617
+ this.onError(
618
+ new StreamingError(`Failed to parse message: ${error.message}`)
619
+ );
620
+ }
621
+ }
622
+ }
623
+ /**
624
+ * Handle connection errors and attempt reconnection
625
+ */
626
+ _handleConnectionError() {
627
+ if (!this.isRunning) {
628
+ return;
629
+ }
630
+ this._cleanup();
631
+ const delay2 = getExponentialBackoffDelay(this.reconnectAttempt);
632
+ if (this.onError) {
633
+ this.onError(
634
+ new StreamingError(
635
+ `Connection lost. Reconnecting in ${delay2}ms (attempt ${this.reconnectAttempt + 1})`
636
+ )
637
+ );
638
+ }
639
+ this.reconnectAttempt++;
640
+ this.reconnectTimeout = setTimeout(async () => {
641
+ if (this.isRunning) {
642
+ await this._connect();
643
+ }
644
+ }, delay2);
645
+ }
646
+ /**
647
+ * Clean up resources
648
+ */
649
+ _cleanup() {
650
+ if (this.eventSource) {
651
+ this.eventSource.close();
652
+ this.eventSource = void 0;
653
+ }
654
+ if (this.reconnectTimeout) {
655
+ clearTimeout(this.reconnectTimeout);
656
+ this.reconnectTimeout = void 0;
657
+ }
658
+ }
659
+ };
660
+ var StreamManager = class {
661
+ constructor() {
662
+ this.streams = /* @__PURE__ */ new Map();
663
+ }
664
+ /**
665
+ * Start streaming for a session
666
+ */
667
+ async startStream(sessionId, config, onMessage, onError) {
668
+ this.stopStream(sessionId);
669
+ const stream = new MessageStream(config, onMessage, onError);
670
+ this.streams.set(sessionId, stream);
671
+ await stream.start();
672
+ }
673
+ /**
674
+ * Stop streaming for a session
675
+ */
676
+ stopStream(sessionId) {
677
+ const stream = this.streams.get(sessionId);
678
+ if (stream) {
679
+ stream.stop();
680
+ this.streams.delete(sessionId);
681
+ }
682
+ }
683
+ /**
684
+ * Stop all streams
685
+ */
686
+ stopAllStreams() {
687
+ for (const stream of this.streams.values()) {
688
+ stream.stop();
689
+ }
690
+ this.streams.clear();
691
+ }
692
+ /**
693
+ * Check if a stream is running
694
+ */
695
+ isStreamRunning(sessionId) {
696
+ return this.streams.has(sessionId);
697
+ }
698
+ };
699
+
700
+ // src/core/client.ts
701
+ var DEFAULT_BASE_URL = "https://olbrain-agent-cloud-768934887465.us-central1.run.app";
702
+ var DEFAULT_TIMEOUT_MS = 3e4;
703
+ var AgentClient = class {
704
+ constructor(config) {
705
+ validateApiKey(config.apiKey);
706
+ validateAgentId(config.agentId);
707
+ this.config = {
708
+ agentId: config.agentId,
709
+ apiKey: config.apiKey,
710
+ baseUrl: config.baseUrl || DEFAULT_BASE_URL
711
+ };
712
+ this.streamManager = new StreamManager();
713
+ }
714
+ /**
715
+ * Create a new session
716
+ */
717
+ async createSession(options) {
718
+ const payload = {
719
+ message: options?.title || "Chat Session",
720
+ response_mode: "sync",
721
+ mode: "production"
722
+ };
723
+ if (options?.userId) {
724
+ payload.user_id = options.userId;
725
+ }
726
+ if (options?.metadata) {
727
+ payload.metadata = options.metadata;
728
+ }
729
+ const response = await this._request("POST", "/api/agent/webhook", payload);
730
+ if (!response.session_id) {
731
+ throw new OlbrainError("Failed to create session: no session_id returned");
732
+ }
733
+ return response.session_id;
734
+ }
735
+ /**
736
+ * Get session information
737
+ * @note May not be implemented on all backends
738
+ */
739
+ async getSession(sessionId) {
740
+ try {
741
+ const response = await this._request("POST", "/api/agent/webhook", {
742
+ session_id: sessionId,
743
+ action: "get_session_info"
744
+ });
745
+ return this._parseSessionInfo(response);
746
+ } catch (error) {
747
+ console.warn("get_session_info not available, returning basic info");
748
+ return {
749
+ sessionId,
750
+ title: "Session",
751
+ status: "active",
752
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
753
+ messageCount: 0,
754
+ metadata: {}
755
+ };
756
+ }
757
+ }
758
+ /**
759
+ * Update session information
760
+ * @note May not be implemented on all backends
761
+ */
762
+ async updateSession(sessionId, updates) {
763
+ try {
764
+ const payload = {
765
+ session_id: sessionId,
766
+ action: "update_session"
767
+ };
768
+ if (updates.title !== void 0) payload.title = updates.title;
769
+ if (updates.status !== void 0) payload.status = updates.status;
770
+ if (updates.metadata !== void 0) payload.metadata = updates.metadata;
771
+ const response = await this._request("POST", "/api/agent/webhook", payload);
772
+ return this._parseSessionInfo(response);
773
+ } catch (error) {
774
+ console.warn("update_session not available");
775
+ throw error;
776
+ }
777
+ }
778
+ /**
779
+ * Delete a session
780
+ * @note May not be implemented on all backends
781
+ */
782
+ async deleteSession(sessionId) {
783
+ try {
784
+ await this._request("POST", "/api/agent/webhook", {
785
+ session_id: sessionId,
786
+ action: "delete_session"
787
+ });
788
+ } catch (error) {
789
+ console.warn("delete_session not available");
790
+ throw error;
791
+ }
792
+ }
793
+ /**
794
+ * Get messages from a session
795
+ * @note May not be implemented on all backends
796
+ */
797
+ async getMessages(sessionId, limit) {
798
+ try {
799
+ const response = await this._request("POST", "/api/agent/webhook", {
800
+ session_id: sessionId,
801
+ action: "get_messages",
802
+ limit: limit || 100
803
+ });
804
+ return (response.messages || []).map((msg) => ({
805
+ role: msg.role,
806
+ content: msg.content,
807
+ timestamp: msg.timestamp,
808
+ metadata: msg.metadata
809
+ }));
810
+ } catch (error) {
811
+ console.warn("get_messages not available");
812
+ return [];
813
+ }
814
+ }
815
+ /**
816
+ * Get session statistics
817
+ * @note May not be implemented on all backends
818
+ */
819
+ async getSessionStats(sessionId) {
820
+ try {
821
+ const response = await this._request("POST", "/api/agent/webhook", {
822
+ session_id: sessionId,
823
+ action: "get_stats"
824
+ });
825
+ return {
826
+ sessionId: response.session_id,
827
+ messageCount: response.message_count,
828
+ totalTokens: response.total_tokens,
829
+ createdAt: response.created_at,
830
+ lastMessageAt: response.last_message_at
831
+ };
832
+ } catch (error) {
833
+ console.warn("get_stats not available");
834
+ return {
835
+ sessionId,
836
+ messageCount: 0,
837
+ totalTokens: 0,
838
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
839
+ };
840
+ }
841
+ }
842
+ /**
843
+ * Send a message and wait for response
844
+ */
845
+ async sendAndWait(sessionId, message, options) {
846
+ if (!message) {
847
+ throw new ValidationError("Message cannot be empty");
848
+ }
849
+ const payload = {
850
+ session_id: sessionId,
851
+ message: message.trim(),
852
+ response_mode: "sync"
853
+ };
854
+ if (options?.metadata) {
855
+ payload.metadata = options.metadata;
856
+ }
857
+ const timeout = options?.timeout || DEFAULT_TIMEOUT_MS;
858
+ const response = await this._request(
859
+ "POST",
860
+ "/api/agent/webhook",
861
+ payload,
862
+ timeout
863
+ );
864
+ return {
865
+ text: response.response || response.text || "",
866
+ sessionId: response.session_id,
867
+ success: response.success !== false,
868
+ tokenUsage: response.token_usage ? {
869
+ promptTokens: response.token_usage.prompt_tokens,
870
+ completionTokens: response.token_usage.completion_tokens,
871
+ totalTokens: response.token_usage.total_tokens,
872
+ cost: response.token_usage.cost
873
+ } : void 0,
874
+ modelUsed: response.model_used,
875
+ responseTimeMs: response.response_time_ms,
876
+ error: response.error
877
+ };
878
+ }
879
+ /**
880
+ * Send a message (fire and forget)
881
+ */
882
+ async send(sessionId, message) {
883
+ if (!message) {
884
+ throw new ValidationError("Message cannot be empty");
885
+ }
886
+ await this._request("POST", "/api/agent/webhook", {
887
+ session_id: sessionId,
888
+ message: message.trim(),
889
+ response_mode: "sync"
890
+ });
891
+ }
892
+ /**
893
+ * Start listening for messages via SSE streaming
894
+ */
895
+ async listen(sessionId, onMessage, onError) {
896
+ await this.streamManager.startStream(
897
+ sessionId,
898
+ {
899
+ sessionId,
900
+ apiKey: this.config.apiKey,
901
+ agentId: this.config.agentId,
902
+ baseUrl: this.config.baseUrl
903
+ },
904
+ onMessage,
905
+ onError
906
+ );
907
+ }
908
+ /**
909
+ * Stop listening for messages
910
+ */
911
+ stopListening(sessionId) {
912
+ this.streamManager.stopStream(sessionId);
913
+ }
914
+ /**
915
+ * Close client and clean up resources
916
+ */
917
+ close() {
918
+ this.streamManager.stopAllStreams();
919
+ }
920
+ /**
921
+ * Helper method to make HTTP requests
922
+ */
923
+ async _request(method, path, payload, timeout = DEFAULT_TIMEOUT_MS) {
924
+ const url = `${this.config.baseUrl}${path}`;
925
+ const headers = {
926
+ "Content-Type": "application/json",
927
+ "Authorization": formatAuthHeader(this.config.apiKey),
928
+ "X-Agent-ID": this.config.agentId
929
+ };
930
+ const controller = new AbortController();
931
+ const timeoutId = setTimeout(() => controller.abort(), timeout);
932
+ try {
933
+ const response = await fetch(url, {
934
+ method,
935
+ headers,
936
+ body: payload ? JSON.stringify(payload) : void 0,
937
+ signal: controller.signal
938
+ });
939
+ clearTimeout(timeoutId);
940
+ if (!response.ok) {
941
+ const errorData = await response.json().catch(() => ({}));
942
+ const errorMessage = errorData.error || errorData.message || response.statusText;
943
+ if (response.status === 401 || response.status === 403) {
944
+ throw new AuthenticationError(errorMessage);
945
+ } else if (response.status === 404) {
946
+ throw new SessionNotFoundError(payload?.session_id || "unknown");
947
+ } else if (response.status === 429) {
948
+ const retryAfter = response.headers.get("Retry-After");
949
+ throw new RateLimitError(errorMessage, retryAfter ? parseInt(retryAfter) : void 0);
950
+ } else if (response.status >= 500) {
951
+ throw new NetworkError(errorMessage, response.status);
952
+ } else {
953
+ throw new NetworkError(errorMessage, response.status);
954
+ }
955
+ }
956
+ return await response.json();
957
+ } catch (error) {
958
+ clearTimeout(timeoutId);
959
+ if (error instanceof OlbrainError) {
960
+ throw error;
961
+ }
962
+ if (error instanceof TypeError) {
963
+ if (error.message.includes("aborted")) {
964
+ throw new OlbrainError(`Request timeout after ${timeout}ms`);
965
+ }
966
+ throw new NetworkError(error.message);
967
+ }
968
+ throw error;
969
+ }
970
+ }
971
+ /**
972
+ * Helper to parse session info from response
973
+ */
974
+ _parseSessionInfo(data) {
975
+ return {
976
+ sessionId: data.session_id,
977
+ title: data.title,
978
+ status: data.status || "active",
979
+ createdAt: data.created_at,
980
+ messageCount: data.message_count || 0,
981
+ userId: data.user_id,
982
+ metadata: data.metadata || {}
983
+ };
984
+ }
985
+ };
986
+
987
+ // src/index.ts
988
+ var VERSION = "1.0.0";
989
+ // Annotate the CommonJS export names for ESM import in node:
990
+ 0 && (module.exports = {
991
+ AgentClient,
992
+ AuthenticationError,
993
+ NetworkError,
994
+ OlbrainError,
995
+ RateLimitError,
996
+ SessionNotFoundError,
997
+ StreamingError,
998
+ VERSION,
999
+ ValidationError
1000
+ });
1001
+ //# sourceMappingURL=index.js.map