From 7ead9c86c549dc0f87dac86a9c83d61d00bcf2a0 Mon Sep 17 00:00:00 2001 From: ansible Date: Tue, 7 Apr 2026 13:54:54 +0000 Subject: [PATCH] Fix agents.json race condition on concurrent starts Re-read agents.json immediately before writing in startAgent to avoid one start overwriting another's entry. Also clean stale sockets before starting new agents. Co-Authored-By: Claude Opus 4.6 (1M context) --- agent/agent.py | 1 + src/agent-manager.ts | 10 ++++++++-- src/overseer.ts | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/agent/agent.py b/agent/agent.py index b6f6c54..4d4d08a 100644 --- a/agent/agent.py +++ b/agent/agent.py @@ -344,6 +344,7 @@ def build_messages(question, channel): if AGENT_MEMORY and AGENT_MEMORY != "# Agent Memory": system += f"\n\nIMPORTANT - Your persistent memory (facts you saved previously, use these to answer questions):\n{AGENT_MEMORY}" system += f"\n\nYou are in IRC channel {channel}. Your nick is {NICK}. Keep responses concise — this is IRC." + system += "\nWhen you want to address another agent or user, always start your message with their nick followed by a colon, e.g. 'coder: can you review this?'. This is how IRC mentions work — without the prefix, they won't see your message." messages = [{"role": "system", "content": system}] diff --git a/src/agent-manager.ts b/src/agent-manager.ts index bded8fe..3a097ef 100644 --- a/src/agent-manager.ts +++ b/src/agent-manager.ts @@ -251,6 +251,9 @@ export async function startAgent( mkdirSync(CONFIG.socketDir, { recursive: true }); mkdirSync(CONFIG.runsDir, { recursive: true }); + // Clean stale socket from previous run + try { unlinkSync(socketPath); } catch {} + // Prepare rootfs copyFileSync(AGENT_ROOTFS, rootfsPath); injectAgentConfig( @@ -321,8 +324,11 @@ export async function startAgent( startedAt: new Date().toISOString(), }; - agents[name] = info; - saveAgents(agents); + // Re-read agents.json before writing to avoid race conditions + // (another startAgent may have written since we last read) + const currentAgents = loadAgents(); + currentAgents[name] = info; + saveAgents(currentAgents); log(`Agent "${name}" started: nick=${nick} ip=${ip}`); return info; diff --git a/src/overseer.ts b/src/overseer.ts index dbefca8..82a62c2 100644 --- a/src/overseer.ts +++ b/src/overseer.ts @@ -197,7 +197,7 @@ export async function runOverseer(config: OverseerConfig) { for (const name of knownAgents) { if (!currentNames.has(name)) { log(`Agent "${name}" died, cleaned up.`); - bot.say("#agents", `Agent "${name}" has died and been cleaned up.`); + bot.say(config.channel, `Agent "${name}" has died and been cleaned up.`); } } knownAgents = currentNames;