Repository navigation
Conversation
Once the lead creates a team, getTaskListId() resolves to the team name and the lead writes its tasks to that list. In-process teammates looked for tasks in a list keyed by the lead's session id (identity.parentSessionId), both in the claim at spawn and in the idle loop, so they never found one and every task stayed unowned. The runner now calls getTaskListId() once, in the lead's process before the teammate context starts, and passes the result to both the claim at spawn and the idle loop. That is the id the lead writes to, including when the task list override is set, and using one value keeps the two paths from disagreeing if the team is deleted in between. Closes GoDiao#163
GoDiao
left a comment
There was a problem hiding this comment.
Thanks @Sagar07Kr, this looks good! Resolving the task list id once and passing it to both paths is exactly what we asked for, and CI passes. We checked that the other readers of the task list (the task tools, task reminders and the stop hook) already use getTaskListId(), so these two calls were the only ones left.
One small thing in the idle-loop test before we merge:
-
inProcessRunner.test.ts:138-141: the poll stops as soon asowneris set, then assertsstatus: 'in_progress'. Claiming writes the owner first (claimTask), andtryClaimNextTasksets the status in a second write. If a poll reads between the two, it sees the owner withstatus: 'pending', and the test fails even though the code is right. Please make the poll wait for both:found => found?.owner === TEAMMATE && found.status === 'in_progress',
The spawn-path test is fine as it is, because it reads the task inside
runAgent, after both writes.
Could you also run the manual repro from the issue? You don't need a paid provider for it: OpenRouter has free models, e.g. nvidia/nemotron-3-ultra-550b-a55b:free, which we used for testing recently. Add OpenRouter in Settings → Providers, fetch models and pick a free one that supports tool calls. Free models are rate-limited per day, so a short run with the issue's three small tasks should be enough. Please post what you see: whether both teammates claim tasks and all three end up completed.
Thanks!
Closes #163
Part of #162
What changed
src/utils/swarm/inProcessRunner.ts:runInProcessTeammatecallsgetTaskListId()once and passes the result to both the claim at spawn (tryClaimNextTask) and the idle loop (waitForNextPromptOrShutdown). Both usedidentity.parentSessionIdbefore. The outdated comment aboutparentSessionIdabove the spawn claim is removed, and no new comments are added.src/utils/swarm/inProcessRunner.test.ts(new): runs the realrunInProcessTeammatewithrunAgentstubbed, a temporary config dir and the lead's team name set. It covers both paths:in_progressby the time the teammate's first turn starts.CHANGELOG.md: entry under[Unreleased]→Fixed.Why
Once the lead creates a team,
getTaskListId()resolves to the team name and the lead writes its tasks to that list. In-process teammates read a list keyed by the lead's session id, so they never found a task and every task stayed unowned. Both calls run in the lead's process before the teammate context starts, sogetTaskListId()there returns the id the lead writes to, including when the task list override is set. Resolving it once keeps the two paths from disagreeing if the team is deleted in between.How I tested
Bun 1.4.2 (the CI version), macOS arm64.
bun test src/utils/swarm/inProcessRunner.test.ts: 2 pass.src/utils/swarm/inProcessRunner.tsrestored frommain, both tests fail on theirtoMatchObjectassertion: the task stayspendingwith no owner.bun test --randomize --seed=1 src/utils/swarm/inProcessRunner.test.ts: 2 pass. The test restores the config dir, the lead's team name and therunAgentspy, and drains the SDK event the runner queues when it stops.bun test(full): 1395 pass, 1 fail. The failure isfilesystem API > falls back to ripgrep search outside git and still respects ignore files. It fails the same way on this machine with the tree reset tomain(the search returns no entries and the test times out), so it is not caused by this change.cd desktop && bun run lint: passes.cd desktop && bun run test -- --run: 124 files, 1278 passed, 4 skipped. My local Node is 26, whose built-inlocalStorageshadows jsdom's, so I ran it withNODE_OPTIONS=--no-experimental-webstorage; without that flag, 16 files fail, mostly becauselocalStorageis undefined. This PR doesn't touchdesktop/.AGENTS.mdprints nothing for the added lines.I have not run the manual repro from the issue (teammates claiming all three tasks in the app), because it needs a model provider.