Governed substrate for autonomous agents: scoped identity (passports), audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
38 lines
1.2 KiB
JavaScript
38 lines
1.2 KiB
JavaScript
/**
|
|
* ConversationLockService - ensures agents execute sequentially per conversation
|
|
* Prevents message interleaving when multiple agents respond simultaneously
|
|
*/
|
|
class ConversationLockService {
|
|
constructor() {
|
|
this.locks = new Map(); // conversationId -> Promise chain
|
|
}
|
|
|
|
/**
|
|
* Execute a function with exclusive access to the conversation.
|
|
* Multiple calls queue up and execute in order.
|
|
* @param {number|string} conversationId
|
|
* @param {function} fn - async function to execute under the lock
|
|
* @returns {Promise} resolves with fn's return value
|
|
*/
|
|
async withLock(conversationId, fn) {
|
|
const key = String(conversationId);
|
|
const previous = this.locks.get(key) || Promise.resolve();
|
|
|
|
// Chain this execution after any pending one
|
|
const current = previous.then(
|
|
() => fn(),
|
|
() => fn() // Execute even if previous failed
|
|
);
|
|
|
|
// Store the chain and clean up when it's the last in line
|
|
const cleanup = current.then(
|
|
() => { if (this.locks.get(key) === cleanup) this.locks.delete(key); },
|
|
() => { if (this.locks.get(key) === cleanup) this.locks.delete(key); }
|
|
);
|
|
this.locks.set(key, cleanup);
|
|
|
|
return current;
|
|
}
|
|
}
|
|
|
|
export default new ConversationLockService();
|