@illalabs/sdk 0.4.0-canary.361ed2fa → 0.4.0-canary.3f75ecce
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 +53 -0
- package/dist/src/chat/Chat.d.ts +31 -2
- package/dist/src/chat/Chat.d.ts.map +1 -1
- package/dist/src/chat/Chat.js +81 -3
- package/dist/src/chat/Chat.js.map +1 -1
- package/dist/src/context/ContextManager.js +1 -1
- package/dist/src/context/ContextManager.js.map +1 -1
- package/dist/src/interfaces/chat.interface.d.ts +52 -1
- package/dist/src/interfaces/chat.interface.d.ts.map +1 -1
- package/dist/src/interfaces/coreApiProvider.interface.d.ts +13 -1
- package/dist/src/interfaces/coreApiProvider.interface.d.ts.map +1 -1
- package/dist/src/interfaces/index.d.ts +1 -1
- package/dist/src/interfaces/index.d.ts.map +1 -1
- package/dist/src/internal.d.ts +1 -0
- package/dist/src/internal.d.ts.map +1 -1
- package/dist/src/internal.js +1 -0
- package/dist/src/internal.js.map +1 -1
- package/dist/src/prompt/index.d.ts +1 -1
- package/dist/src/prompt/index.d.ts.map +1 -1
- package/dist/src/providers/coreApiProvider/CoreApiProvider.d.ts +40 -1
- package/dist/src/providers/coreApiProvider/CoreApiProvider.d.ts.map +1 -1
- package/dist/src/providers/coreApiProvider/CoreApiProvider.js +124 -2
- package/dist/src/providers/coreApiProvider/CoreApiProvider.js.map +1 -1
- package/dist/src/providers/coreApiProvider/index.d.ts +1 -1
- package/dist/src/providers/coreApiProvider/index.d.ts.map +1 -1
- package/dist/src/providers/coreApiProvider/types.d.ts +44 -0
- package/dist/src/providers/coreApiProvider/types.d.ts.map +1 -1
- package/dist/src/sdk.d.ts +65 -4
- package/dist/src/sdk.d.ts.map +1 -1
- package/dist/src/sdk.js +58 -4
- package/dist/src/sdk.js.map +1 -1
- package/dist/src/streaming/errors/SSEParse.d.ts +15 -0
- package/dist/src/streaming/errors/SSEParse.d.ts.map +1 -0
- package/dist/src/streaming/errors/SSEParse.js +23 -0
- package/dist/src/streaming/errors/SSEParse.js.map +1 -0
- package/dist/src/streaming/errors/StreamingHttpError.d.ts +18 -0
- package/dist/src/streaming/errors/StreamingHttpError.d.ts.map +1 -0
- package/dist/src/streaming/errors/StreamingHttpError.js +27 -0
- package/dist/src/streaming/errors/StreamingHttpError.js.map +1 -0
- package/dist/src/streaming/errors/StreamingResponseBodyNull.d.ts +13 -0
- package/dist/src/streaming/errors/StreamingResponseBodyNull.d.ts.map +1 -0
- package/dist/src/streaming/errors/StreamingResponseBodyNull.js +21 -0
- package/dist/src/streaming/errors/StreamingResponseBodyNull.js.map +1 -0
- package/dist/src/streaming/errors/StreamingServerError.d.ts +23 -0
- package/dist/src/streaming/errors/StreamingServerError.d.ts.map +1 -0
- package/dist/src/streaming/errors/StreamingServerError.js +33 -0
- package/dist/src/streaming/errors/StreamingServerError.js.map +1 -0
- package/dist/src/streaming/errors/index.d.ts +5 -0
- package/dist/src/streaming/errors/index.d.ts.map +1 -0
- package/dist/src/streaming/errors/index.js +5 -0
- package/dist/src/streaming/errors/index.js.map +1 -0
- package/dist/src/streaming/index.d.ts +4 -0
- package/dist/src/streaming/index.d.ts.map +1 -0
- package/dist/src/streaming/index.js +3 -0
- package/dist/src/streaming/index.js.map +1 -0
- package/dist/src/streaming/parseSSE.d.ts +23 -0
- package/dist/src/streaming/parseSSE.d.ts.map +1 -0
- package/dist/src/streaming/parseSSE.js +152 -0
- package/dist/src/streaming/parseSSE.js.map +1 -0
- package/dist/src/streaming/types.d.ts +6 -0
- package/dist/src/streaming/types.d.ts.map +1 -0
- package/dist/src/streaming/types.js +6 -0
- package/dist/src/streaming/types.js.map +1 -0
- package/dist/src/telemetry/TelemetryClient.d.ts +140 -0
- package/dist/src/telemetry/TelemetryClient.d.ts.map +1 -0
- package/dist/src/telemetry/TelemetryClient.js +225 -0
- package/dist/src/telemetry/TelemetryClient.js.map +1 -0
- package/dist/src/telemetry/index.d.ts +2 -0
- package/dist/src/telemetry/index.d.ts.map +1 -0
- package/dist/src/telemetry/index.js +2 -0
- package/dist/src/telemetry/index.js.map +1 -0
- package/package.json +3 -5
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when the streaming response body is null.
|
|
3
|
+
*
|
|
4
|
+
* This typically indicates the server did not return a streaming response
|
|
5
|
+
* when one was expected.
|
|
6
|
+
*/
|
|
7
|
+
export class StreamingResponseBodyNull extends Error {
|
|
8
|
+
/**
|
|
9
|
+
* Creates a new StreamingResponseBodyNull error.
|
|
10
|
+
*/
|
|
11
|
+
constructor() {
|
|
12
|
+
super("Response body is null - streaming not available");
|
|
13
|
+
this.name = "StreamingResponseBodyNull";
|
|
14
|
+
// Restore the prototype chain for proper Error subclassing in TypeScript
|
|
15
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
16
|
+
if (Error.captureStackTrace) {
|
|
17
|
+
Error.captureStackTrace(this, StreamingResponseBodyNull);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=StreamingResponseBodyNull.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamingResponseBodyNull.js","sourceRoot":"","sources":["../../../../src/streaming/errors/StreamingResponseBodyNull.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,OAAO,yBAA0B,SAAQ,KAAK;IAChD;;OAEG;IACH;QACI,KAAK,CAAC,iDAAiD,CAAC,CAAC;QACzD,IAAI,CAAC,IAAI,GAAG,2BAA2B,CAAC;QAExC,yEAAyE;QACzE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC1B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,yBAAyB,CAAC,CAAC;QAC7D,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when the server sends an error event through the SSE stream.
|
|
3
|
+
*
|
|
4
|
+
* This error captures the error code and message from the stream error event.
|
|
5
|
+
*/
|
|
6
|
+
export declare class StreamingServerError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* The request ID associated with the failed stream.
|
|
9
|
+
*/
|
|
10
|
+
readonly requestId: string;
|
|
11
|
+
/**
|
|
12
|
+
* Optional error code from the server.
|
|
13
|
+
*/
|
|
14
|
+
readonly code?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new StreamingServerError.
|
|
17
|
+
* @param requestId - The request ID from the error event
|
|
18
|
+
* @param message - The error message from the server
|
|
19
|
+
* @param code - Optional error code from the server
|
|
20
|
+
*/
|
|
21
|
+
constructor(requestId: string, message: string, code?: string);
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=StreamingServerError.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamingServerError.d.ts","sourceRoot":"","sources":["../../../../src/streaming/errors/StreamingServerError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,oBAAqB,SAAQ,KAAK;IAC3C;;OAEG;IACH,SAAgB,SAAS,EAAE,MAAM,CAAC;IAElC;;OAEG;IACH,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAE9B;;;;;OAKG;gBACS,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM;CAahE"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when the server sends an error event through the SSE stream.
|
|
3
|
+
*
|
|
4
|
+
* This error captures the error code and message from the stream error event.
|
|
5
|
+
*/
|
|
6
|
+
export class StreamingServerError extends Error {
|
|
7
|
+
/**
|
|
8
|
+
* The request ID associated with the failed stream.
|
|
9
|
+
*/
|
|
10
|
+
requestId;
|
|
11
|
+
/**
|
|
12
|
+
* Optional error code from the server.
|
|
13
|
+
*/
|
|
14
|
+
code;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new StreamingServerError.
|
|
17
|
+
* @param requestId - The request ID from the error event
|
|
18
|
+
* @param message - The error message from the server
|
|
19
|
+
* @param code - Optional error code from the server
|
|
20
|
+
*/
|
|
21
|
+
constructor(requestId, message, code) {
|
|
22
|
+
super(message);
|
|
23
|
+
this.name = "StreamingServerError";
|
|
24
|
+
this.requestId = requestId;
|
|
25
|
+
this.code = code;
|
|
26
|
+
// Restore the prototype chain for proper Error subclassing in TypeScript
|
|
27
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
28
|
+
if (Error.captureStackTrace) {
|
|
29
|
+
Error.captureStackTrace(this, StreamingServerError);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=StreamingServerError.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StreamingServerError.js","sourceRoot":"","sources":["../../../../src/streaming/errors/StreamingServerError.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,oBAAqB,SAAQ,KAAK;IAC3C;;OAEG;IACa,SAAS,CAAS;IAElC;;OAEG;IACa,IAAI,CAAU;IAE9B;;;;;OAKG;IACH,YAAY,SAAiB,EAAE,OAAe,EAAE,IAAa;QACzD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,sBAAsB,CAAC;QACnC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;QAC3B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QAEjB,yEAAyE;QACzE,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QAElD,IAAI,KAAK,CAAC,iBAAiB,EAAE,CAAC;YAC1B,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;QACxD,CAAC;IACL,CAAC;CACJ"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SSEParse } from "./SSEParse.js";
|
|
2
|
+
export { StreamingHttpError } from "./StreamingHttpError.js";
|
|
3
|
+
export { StreamingResponseBodyNull } from "./StreamingResponseBodyNull.js";
|
|
4
|
+
export { StreamingServerError } from "./StreamingServerError.js";
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/streaming/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { SSEParse } from "./SSEParse.js";
|
|
2
|
+
export { StreamingHttpError } from "./StreamingHttpError.js";
|
|
3
|
+
export { StreamingResponseBodyNull } from "./StreamingResponseBodyNull.js";
|
|
4
|
+
export { StreamingServerError } from "./StreamingServerError.js";
|
|
5
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/streaming/errors/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,yBAAyB,EAAE,MAAM,gCAAgC,CAAC;AAC3E,OAAO,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { SSEParse, StreamingHttpError, StreamingResponseBodyNull, StreamingServerError, } from "./errors/index.js";
|
|
2
|
+
export { parseSSEStream } from "./parseSSE.js";
|
|
3
|
+
export type { ErrorEventData, ErrorStreamEvent, ResultStreamEvent, SSEStreamEndEvent, SSEStreamEndEventData, SSEStreamEvent, StreamEventType, TelemetryStreamEvent, } from "./types.js";
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/streaming/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,oBAAoB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,YAAY,EACR,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,oBAAoB,GACvB,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/streaming/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,QAAQ,EACR,kBAAkB,EAClB,yBAAyB,EACzB,oBAAoB,GACvB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SSEStreamEvent } from "@illalabs/interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Async generator that parses SSE events from a ReadableStream.
|
|
4
|
+
*
|
|
5
|
+
* @param stream - The ReadableStream from a fetch response body
|
|
6
|
+
* @param signal - Optional AbortSignal to allow mid-stream cancellation
|
|
7
|
+
* @yields SSEStreamEvent objects as they are parsed from the stream
|
|
8
|
+
* @throws SSEParse if event data cannot be parsed
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* const controller = new AbortController();
|
|
13
|
+
* for await (const event of parseSSEStream(response.body!, controller.signal)) {
|
|
14
|
+
* if (event.type === 'telemetry') {
|
|
15
|
+
* console.log('Telemetry:', event.data.type);
|
|
16
|
+
* } else if (event.type === 'result') {
|
|
17
|
+
* console.log('Result:', event.data.text);
|
|
18
|
+
* }
|
|
19
|
+
* }
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function parseSSEStream(stream: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<SSEStreamEvent>;
|
|
23
|
+
//# sourceMappingURL=parseSSE.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseSSE.d.ts","sourceRoot":"","sources":["../../../src/streaming/parseSSE.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAgH3D;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAuB,cAAc,CACjC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,CAAC,EAAE,WAAW,GACrB,cAAc,CAAC,cAAc,CAAC,CAsChC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { errorEventDataSchema, resultEventDataSchema, streamEndEventDataSchema, telemetryEventSchema, } from "@illalabs/interfaces";
|
|
2
|
+
import { ZodError } from "zod";
|
|
3
|
+
import { SSEParse } from "./errors/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* Parses a single SSE message into its event type and data.
|
|
6
|
+
*/
|
|
7
|
+
function parseSSEMessage(message) {
|
|
8
|
+
const lines = message.split("\n");
|
|
9
|
+
let eventType = "message";
|
|
10
|
+
const dataLines = [];
|
|
11
|
+
for (const line of lines) {
|
|
12
|
+
if (line.startsWith("event:")) {
|
|
13
|
+
eventType = line.slice(6).trim();
|
|
14
|
+
}
|
|
15
|
+
else if (line.startsWith("data:")) {
|
|
16
|
+
const value = line.slice(5);
|
|
17
|
+
dataLines.push(value.startsWith(" ") ? value.slice(1) : value);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
const data = dataLines.join("\n");
|
|
21
|
+
return data ? { event: eventType, data } : null;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Formats a Zod validation error into a human-readable message.
|
|
25
|
+
*/
|
|
26
|
+
function formatZodError(error) {
|
|
27
|
+
return error.issues
|
|
28
|
+
.map((issue) => {
|
|
29
|
+
const path = issue.path.length > 0 ? `${issue.path.join(".")}: ` : "";
|
|
30
|
+
return `${path}:${issue.message}`;
|
|
31
|
+
})
|
|
32
|
+
.join("; ");
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Converts a parsed SSE message into a typed SSEStreamEvent.
|
|
36
|
+
* Validates the parsed data at runtime using Zod schemas.
|
|
37
|
+
*/
|
|
38
|
+
function toStreamEvent(event, data) {
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = JSON.parse(data);
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
throw new SSEParse(`Failed to parse JSON data: ${data}`, error);
|
|
45
|
+
}
|
|
46
|
+
try {
|
|
47
|
+
switch (event) {
|
|
48
|
+
case "telemetry": {
|
|
49
|
+
const validated = telemetryEventSchema.parse(parsed);
|
|
50
|
+
return { type: "telemetry", data: validated };
|
|
51
|
+
}
|
|
52
|
+
case "result": {
|
|
53
|
+
const validated = resultEventDataSchema.parse(parsed);
|
|
54
|
+
return { type: "result", data: validated };
|
|
55
|
+
}
|
|
56
|
+
case "error": {
|
|
57
|
+
const validated = errorEventDataSchema.parse(parsed);
|
|
58
|
+
return { type: "error", data: validated };
|
|
59
|
+
}
|
|
60
|
+
case "stream_end": {
|
|
61
|
+
const validated = streamEndEventDataSchema.parse(parsed);
|
|
62
|
+
return { type: "stream_end", data: validated };
|
|
63
|
+
}
|
|
64
|
+
default: {
|
|
65
|
+
// Try to infer event type from data.type field if present
|
|
66
|
+
if (typeof parsed === "object" && parsed !== null && "type" in parsed) {
|
|
67
|
+
const typedData = parsed;
|
|
68
|
+
switch (typedData.type) {
|
|
69
|
+
case "result": {
|
|
70
|
+
const validated = resultEventDataSchema.parse(parsed);
|
|
71
|
+
return { type: "result", data: validated };
|
|
72
|
+
}
|
|
73
|
+
case "error": {
|
|
74
|
+
const validated = errorEventDataSchema.parse(parsed);
|
|
75
|
+
return { type: "error", data: validated };
|
|
76
|
+
}
|
|
77
|
+
case "stream_end": {
|
|
78
|
+
const validated = streamEndEventDataSchema.parse(parsed);
|
|
79
|
+
return { type: "stream_end", data: validated };
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Default to telemetry for unknown event types
|
|
84
|
+
const validated = telemetryEventSchema.parse(parsed);
|
|
85
|
+
return { type: "telemetry", data: validated };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
if (error instanceof ZodError) {
|
|
91
|
+
throw new SSEParse(`Invalid event data for "${event}": ${formatZodError(error)}`, error);
|
|
92
|
+
}
|
|
93
|
+
throw error;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Async generator that parses SSE events from a ReadableStream.
|
|
98
|
+
*
|
|
99
|
+
* @param stream - The ReadableStream from a fetch response body
|
|
100
|
+
* @param signal - Optional AbortSignal to allow mid-stream cancellation
|
|
101
|
+
* @yields SSEStreamEvent objects as they are parsed from the stream
|
|
102
|
+
* @throws SSEParse if event data cannot be parsed
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* ```typescript
|
|
106
|
+
* const controller = new AbortController();
|
|
107
|
+
* for await (const event of parseSSEStream(response.body!, controller.signal)) {
|
|
108
|
+
* if (event.type === 'telemetry') {
|
|
109
|
+
* console.log('Telemetry:', event.data.type);
|
|
110
|
+
* } else if (event.type === 'result') {
|
|
111
|
+
* console.log('Result:', event.data.text);
|
|
112
|
+
* }
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export async function* parseSSEStream(stream, signal) {
|
|
117
|
+
const reader = stream.getReader();
|
|
118
|
+
const decoder = new TextDecoder();
|
|
119
|
+
let buffer = "";
|
|
120
|
+
try {
|
|
121
|
+
while (true) {
|
|
122
|
+
if (signal?.aborted) {
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
const { done, value } = await reader.read();
|
|
126
|
+
if (done) {
|
|
127
|
+
if (buffer.trim()) {
|
|
128
|
+
const parsed = parseSSEMessage(buffer);
|
|
129
|
+
if (parsed) {
|
|
130
|
+
yield toStreamEvent(parsed.event, parsed.data);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
break;
|
|
134
|
+
}
|
|
135
|
+
buffer += decoder.decode(value, { stream: true });
|
|
136
|
+
const messages = buffer.split("\n\n");
|
|
137
|
+
buffer = messages.pop() ?? "";
|
|
138
|
+
for (const message of messages) {
|
|
139
|
+
if (!message.trim())
|
|
140
|
+
continue;
|
|
141
|
+
const parsed = parseSSEMessage(message);
|
|
142
|
+
if (parsed) {
|
|
143
|
+
yield toStreamEvent(parsed.event, parsed.data);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
finally {
|
|
149
|
+
reader.releaseLock();
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=parseSSE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseSSE.js","sourceRoot":"","sources":["../../../src/streaming/parseSSE.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Streaming types for SSE chat endpoint.
|
|
3
|
+
* Re-exports types from @illalabs/interfaces for SDK consumers.
|
|
4
|
+
*/
|
|
5
|
+
export type { ErrorEventData, ErrorStreamEvent, ResultStreamEvent, SSEStreamEndEvent, SSEStreamEndEventData, SSEStreamEvent, StreamEventType, TelemetryStreamEvent, } from "@illalabs/interfaces";
|
|
6
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/streaming/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,YAAY,EACR,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,eAAe,EACf,oBAAoB,GACvB,MAAM,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/streaming/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { OrchestratorPhase, TelemetryEvent, TelemetryEventType } from "@illalabs/interfaces";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration for the TelemetryClient
|
|
4
|
+
*/
|
|
5
|
+
export type TelemetryClientConfig = {
|
|
6
|
+
/** Base URL of the API (e.g., "https://api.example.com/v1/chat") */
|
|
7
|
+
baseUrl: string;
|
|
8
|
+
/** Called when an event is received from the stream */
|
|
9
|
+
onEvent?: (event: TelemetryEvent) => void;
|
|
10
|
+
/** Called when the stream completes successfully */
|
|
11
|
+
onComplete?: () => void;
|
|
12
|
+
/** Called when an error occurs */
|
|
13
|
+
onError?: (error: Error) => void;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* State of the telemetry stream
|
|
17
|
+
*/
|
|
18
|
+
export type TelemetryStreamState = {
|
|
19
|
+
/** Whether the stream is currently connected */
|
|
20
|
+
isConnected: boolean;
|
|
21
|
+
/** Whether the stream has completed */
|
|
22
|
+
isComplete: boolean;
|
|
23
|
+
/** All events received from the stream */
|
|
24
|
+
events: TelemetryEvent[];
|
|
25
|
+
/** The last event received */
|
|
26
|
+
lastEvent: TelemetryEvent | null;
|
|
27
|
+
/** Any error that occurred */
|
|
28
|
+
error: Error | null;
|
|
29
|
+
/** Current phase of orchestration */
|
|
30
|
+
currentPhase: OrchestratorPhase;
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Error thrown when the telemetry stream fails to connect or encounters an error
|
|
34
|
+
*/
|
|
35
|
+
export declare class TelemetryStreamFailed extends Error {
|
|
36
|
+
/** The request ID that was being streamed */
|
|
37
|
+
readonly requestId?: string;
|
|
38
|
+
/**
|
|
39
|
+
* Creates a new TelemetryStreamFailed error
|
|
40
|
+
* @param message - Description of what went wrong
|
|
41
|
+
* @param requestId - The request ID that was being streamed
|
|
42
|
+
*/
|
|
43
|
+
constructor(message: string, requestId?: string);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Browser-only client for consuming telemetry SSE streams.
|
|
47
|
+
* This client connects to the telemetry endpoint and emits events as they arrive.
|
|
48
|
+
*
|
|
49
|
+
* **Note**: This client requires the native `EventSource` API, which is only available
|
|
50
|
+
* in browser environments. For Node.js usage, you must provide a polyfill such as
|
|
51
|
+
* the `eventsource` package before instantiating this client.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const client = new TelemetryClient({
|
|
56
|
+
* baseUrl: 'https://api.example.com/v1/chat',
|
|
57
|
+
* onEvent: (event) => console.log('Event:', event.type),
|
|
58
|
+
* onComplete: () => console.log('Stream complete'),
|
|
59
|
+
* onError: (error) => console.error('Error:', error),
|
|
60
|
+
* });
|
|
61
|
+
*
|
|
62
|
+
* client.connect('request-uuid');
|
|
63
|
+
*
|
|
64
|
+
* // Later, disconnect
|
|
65
|
+
* client.disconnect();
|
|
66
|
+
* ```
|
|
67
|
+
*
|
|
68
|
+
* @example Node.js usage with polyfill
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Install: pnpm add eventsource
|
|
71
|
+
* // At the top of your entry file:
|
|
72
|
+
* import EventSource from 'eventsource';
|
|
73
|
+
* globalThis.EventSource = EventSource as unknown as typeof globalThis.EventSource;
|
|
74
|
+
*
|
|
75
|
+
* // Then use TelemetryClient normally
|
|
76
|
+
* const client = new TelemetryClient({ ... });
|
|
77
|
+
* ```
|
|
78
|
+
*/
|
|
79
|
+
export declare class TelemetryClient {
|
|
80
|
+
private eventSource;
|
|
81
|
+
private config;
|
|
82
|
+
private currentRequestId;
|
|
83
|
+
private _isConnected;
|
|
84
|
+
private _isComplete;
|
|
85
|
+
/**
|
|
86
|
+
* Creates a new TelemetryClient instance
|
|
87
|
+
* @param config - Configuration including base URL and event callbacks
|
|
88
|
+
*/
|
|
89
|
+
constructor(config: TelemetryClientConfig);
|
|
90
|
+
/**
|
|
91
|
+
* Whether the client is currently connected to a stream
|
|
92
|
+
*/
|
|
93
|
+
get isConnected(): boolean;
|
|
94
|
+
/**
|
|
95
|
+
* Whether the current stream has completed
|
|
96
|
+
*/
|
|
97
|
+
get isComplete(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Connect to a telemetry stream for a specific request
|
|
100
|
+
* @param requestId - The request ID to subscribe to
|
|
101
|
+
* @throws {TelemetryStreamFailed} If EventSource is not available in the environment
|
|
102
|
+
*/
|
|
103
|
+
connect(requestId: string): void;
|
|
104
|
+
/**
|
|
105
|
+
* Disconnect from the current stream
|
|
106
|
+
*/
|
|
107
|
+
disconnect(): void;
|
|
108
|
+
/**
|
|
109
|
+
* Close the EventSource without clearing the requestId
|
|
110
|
+
* (used when stream ends normally)
|
|
111
|
+
*/
|
|
112
|
+
private closeEventSource;
|
|
113
|
+
/**
|
|
114
|
+
* Derive orchestrator phase from a telemetry event.
|
|
115
|
+
* This static method provides a consistent mapping from events to phases.
|
|
116
|
+
*
|
|
117
|
+
* @param event - The telemetry event to derive phase from
|
|
118
|
+
* @returns The current orchestrator phase
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* const phase = TelemetryClient.getPhaseFromEvent(event);
|
|
123
|
+
* console.log('Current phase:', phase); // e.g., "thinking", "executing_tools"
|
|
124
|
+
* ```
|
|
125
|
+
*/
|
|
126
|
+
static getPhaseFromEvent(event: TelemetryEvent | null): OrchestratorPhase;
|
|
127
|
+
/**
|
|
128
|
+
* Get a human-readable label for an orchestrator phase
|
|
129
|
+
* @param phase - The phase to get label for
|
|
130
|
+
* @returns Human-readable label
|
|
131
|
+
*/
|
|
132
|
+
static getPhaseLabel(phase: OrchestratorPhase): string;
|
|
133
|
+
/**
|
|
134
|
+
* Check if an event type indicates the stream should end
|
|
135
|
+
* @param type - The event type to check
|
|
136
|
+
* @returns True if the event indicates stream completion
|
|
137
|
+
*/
|
|
138
|
+
static isTerminalEvent(type: TelemetryEventType): boolean;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=TelemetryClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TelemetryClient.d.ts","sourceRoot":"","sources":["../../../src/telemetry/TelemetryClient.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAElG;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAChC,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC1C,oDAAoD;IACpD,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,kCAAkC;IAClC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,oBAAoB,GAAG;IAC/B,gDAAgD;IAChD,WAAW,EAAE,OAAO,CAAC;IACrB,uCAAuC;IACvC,UAAU,EAAE,OAAO,CAAC;IACpB,0CAA0C;IAC1C,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,8BAA8B;IAC9B,SAAS,EAAE,cAAc,GAAG,IAAI,CAAC;IACjC,8BAA8B;IAC9B,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IACpB,qCAAqC;IACrC,YAAY,EAAE,iBAAiB,CAAC;CACnC,CAAC;AAEF;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC5C,6CAA6C;IAC7C,SAAgB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnC;;;;OAIG;gBACS,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;CAKlD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,qBAAa,eAAe;IACxB,OAAO,CAAC,WAAW,CAA4B;IAC/C,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,gBAAgB,CAAuB;IAC/C,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,WAAW,CAAS;IAE5B;;;OAGG;gBACS,MAAM,EAAE,qBAAqB;IAIzC;;OAEG;IACH,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED;;OAEG;IACH,IAAI,UAAU,IAAI,OAAO,CAExB;IAED;;;;OAIG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;IAiEhC;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAQxB;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,iBAAiB,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI,GAAG,iBAAiB;IA0BzE;;;;OAIG;IACH,MAAM,CAAC,aAAa,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM;IAuBtD;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,IAAI,EAAE,kBAAkB,GAAG,OAAO;CAG5D"}
|