gemikenwork / runtime-dist /server /sessionStore.js
burtenshaw's picture
burtenshaw HF Staff
Improve realtime WorkAdventure voice responsiveness
b1ca525 verified
Raw History Blame Contribute Delete
2.81 kB
export class SessionStore {
sessions = new Map();
getOrCreate(id) {
let session = this.sessions.get(id);
if (!session) {
session = new AgentSession(id);
this.sessions.set(id, session);
}
session.touch();
return session;
}
list() {
return Array.from(this.sessions.values()).map((session) => session.summary());
}
}
export class AgentSession {
id;
createdAt = new Date();
lastSeenAt = new Date();
actionCursor = 0;
actions = [];
observations = [];
waiters = new Set();
constructor(id) {
this.id = id;
}
touch() {
this.lastSeenAt = new Date();
}
addObservation(observation) {
this.touch();
this.observations.push({
...observation,
observedAt: new Date().toISOString(),
});
if (this.observations.length > 500) {
this.observations.splice(0, this.observations.length - 500);
}
}
enqueue(action) {
this.touch();
const queuedAction = {
...action,
id: ++this.actionCursor,
createdAt: new Date().toISOString(),
};
this.actions.push(queuedAction);
if (this.actions.length > 500) {
this.actions.splice(0, this.actions.length - 500);
}
this.resolveWaiters();
return queuedAction;
}
getActionsAfter(after) {
return this.actions.filter((action) => action.id > after);
}
async waitForActions(after, timeoutMs) {
const ready = this.getActionsAfter(after);
if (ready.length > 0) {
return ready;
}
await new Promise((resolve) => {
const waiter = { after, resolve };
const timeout = setTimeout(() => {
this.waiters.delete(waiter);
resolve();
}, timeoutMs);
waiter.resolve = () => {
clearTimeout(timeout);
this.waiters.delete(waiter);
resolve();
};
this.waiters.add(waiter);
});
return this.getActionsAfter(after);
}
summary() {
return {
id: this.id,
createdAt: this.createdAt.toISOString(),
lastSeenAt: this.lastSeenAt.toISOString(),
observationsCount: this.observations.length,
actionsCount: this.actions.length,
};
}
recentObservations(limit = 20) {
return this.observations.slice(-limit);
}
resolveWaiters() {
for (const waiter of this.waiters) {
if (this.getActionsAfter(waiter.after).length > 0) {
waiter.resolve();
}
}
}
}
//# sourceMappingURL=sessionStore.js.map