@genkit-ai/core
Version:
Genkit AI framework core libraries.
108 lines • 3.23 kB
JavaScript
import { GenkitError } from "./error";
class StreamNotFoundError extends GenkitError {
constructor(message) {
super({ status: "NOT_FOUND", message });
this.name = "StreamNotFoundError";
}
}
class InMemoryStreamManager {
/**
* @param options Configuration options.
* @param options.ttlSeconds Time-to-live for streams in seconds. Defaults to 5 minutes.
*/
constructor(options = {}) {
this.options = options;
}
streams = /* @__PURE__ */ new Map();
_cleanup() {
const ttl = (this.options.ttlSeconds ?? 5 * 60) * 1e3;
const now = Date.now();
for (const [streamId, stream] of this.streams.entries()) {
if (stream.status !== "open" && now - stream.lastTouched > ttl) {
this.streams.delete(streamId);
}
}
}
async open(streamId) {
this._cleanup();
if (this.streams.has(streamId)) {
throw new Error(`Stream with id ${streamId} already exists.`);
}
this.streams.set(streamId, {
status: "open",
chunks: [],
subscribers: [],
lastTouched: Date.now()
});
return {
write: async (chunk) => {
const stream = this.streams.get(streamId);
if (stream?.status === "open") {
stream.chunks.push(chunk);
stream.subscribers.forEach((s) => s.onChunk(chunk));
stream.lastTouched = Date.now();
}
},
done: async (output) => {
const stream = this.streams.get(streamId);
if (stream?.status === "open") {
this.streams.set(streamId, {
status: "done",
chunks: stream.chunks,
output,
lastTouched: Date.now()
});
stream.subscribers.forEach((s) => s.onDone(output));
}
},
error: async (err) => {
const stream = this.streams.get(streamId);
if (stream?.status === "open") {
stream.subscribers.forEach((s) => s.onError(err));
this.streams.set(streamId, {
status: "error",
chunks: stream.chunks,
error: err,
lastTouched: Date.now()
});
}
}
};
}
async subscribe(streamId, subscriber) {
const stream = this.streams.get(streamId);
if (!stream) {
throw new StreamNotFoundError(`Stream with id ${streamId} not found.`);
}
if (stream.status === "done") {
for (const chunk of stream.chunks) {
subscriber.onChunk(chunk);
}
subscriber.onDone(stream.output);
} else if (stream.status === "error") {
for (const chunk of stream.chunks) {
subscriber.onChunk(chunk);
}
subscriber.onError(stream.error);
} else {
stream.chunks.forEach((chunk) => subscriber.onChunk(chunk));
stream.subscribers.push(subscriber);
}
return {
unsubscribe: () => {
const currentStream = this.streams.get(streamId);
if (currentStream?.status === "open") {
const index = currentStream.subscribers.indexOf(subscriber);
if (index > -1) {
currentStream.subscribers.splice(index, 1);
}
}
}
};
}
}
export {
InMemoryStreamManager,
StreamNotFoundError
};
//# sourceMappingURL=streaming.mjs.map