feat(queue): per-(tool, model) concurrency mode for solve queue (closes #1474)#1797
Open
konard wants to merge 9 commits into
Open
feat(queue): per-(tool, model) concurrency mode for solve queue (closes #1474)#1797konard wants to merge 9 commits into
konard wants to merge 9 commits into
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #1474
Lift the free-agent-model classification out of agent.lib.mjs so the solve queue can call it without depending on the runner module. Pair it with normalizeAgentModelKey to give the queue a stable per-(provider, model) gating key. Issue #1474.
Extend QUEUE_CONFIG with a per-tool concurrency map and add the four modes off / global-one-at-a-time / per-free-model-one-at-a-time / per-model-one-at-a-time. Resolution priority is HIVE_MIND_QUEUE_CONFIG (via new (<tool>-concurrency <mode>) lino entries) > HIVE_MIND_<TOOL>_CONCURRENCY env var > built-in default. Defaults: agent = global-one-at-a-time, all others = off. Issue #1474.
Add a pure helper module (telegram-solve-queue.concurrency.lib.mjs) that decides whether the head of a tool queue can start under the configured concurrency mode, and call it from findStartableItems(). The SolveQueueItem now carries a normalized model alias used as the per- model gating key. Extracted to a separate file to keep the main queue module under the 1500-line cap. Issue #1474.
Parse --model / -m / --model= at the queue boundary the same way --tool is parsed and pass it to solveQueue.enqueue() so the queue can gate per- (free-)model concurrency. Mirrors validateModelInArgs() but only needs the literal string value because equality is enough for gating. Issue #1474.
Add 28 tests in tests/solve-queue-concurrency.test.mjs covering: - HIVE_MIND_QUEUE_CONFIG lino parsing of (<tool>-concurrency <mode>) - SolveQueueItem.model plumbing through enqueue (alias normalization) - getProcessingCountByToolAndModel counter - canStartUnderConcurrencyMode under all four modes - findStartableItems gating: R1 (agent default), R2 (per-free-model parallel + same-model block), R5 (claude unchanged), cross-tool isolation Issue #1474.
Document the per-(tool, model) concurrency design, requirements R1-R7, acceptance criteria, and atomic commit plan. Issue #1474.
Keep the debugging scripts in experiments/ for future reproduction: - debug-r1.mjs / debug-concurrency-second-pass.mjs: walk the queue through two enqueue + start cycles to inspect findStartableItems() gating behavior. - reproduce-r2-failing.mjs: minimum reproducible case for the original R2 failure. - verify-finally-bug.mjs: standalone proof that try/finally restores state before an async body resolves, which was the root cause of the earlier test flakiness in withConcurrency(). Issue #1474.
--tool agent please use mode 1 at time for each specific free model.
Contributor
Author
Working session summaryIssue #1474 is solved. PR #1797 is ready for review with all CI green: PR: #1797 What was done
Commits (7 atomic): models helpers → queue-config → queue gating → telegram-bot wire-up → tests → docs/changeset → debug experiments. This summary was automatically extracted from the AI working session output. |
Contributor
Author
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost: $14.707635📊 Context and tokens usage:Claude Opus 4.7: (5 sub-sessions)
Total: (9.4K new + 508.5K cache writes + 17.4M cache reads) input tokens, 111.4K output tokens, $14.707635 cost 🤖 Models used:
📎 Log file uploaded as Gist (9684KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
Contributor
Author
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
This reverts commit 307388c.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1474.
Implements per-tool concurrency gating for the solve queue so the
--tool agentqueue can run one task at a time per free model (e.g. oneminimax-m2.5-freetask at a time, in parallel with onegpt-5-nano-freetask). The agent queue defaults to global one-at-a-time today; operators flip individual queues (claude, agent, codex, qwen, gemini) to a different mode via env vars or the existingHIVE_MIND_QUEUE_CONFIGlinks notation.--tool agentif only Claude limit thresholds are reached #1159) and the threshold-strategy framework (Solve queue enhancements #1253), which were both about when to throttle but not how many in parallel per model.src/telegram-solve-queue.concurrency.lib.mjs) plus a wire-up infindStartableItems().See
docs/case-studies/issue-1474/README.mdfor the full design, R1–R7 requirements, and acceptance criteria.Concurrency modes
offglobal-one-at-a-timeper-free-model-one-at-a-time(tool, model). Non-free models bypass the gate.per-model-one-at-a-time(tool, model)for every model.Configuration surface
HIVE_MIND_AGENT_CONCURRENCY=per-free-model-one-at-a-time(same forCLAUDE,CODEX,QWEN,GEMINI).HIVE_MIND_QUEUE_CONFIG:agent: global-one-at-a-time, all othersoff.Resolution priority:
HIVE_MIND_QUEUE_CONFIG>HIVE_MIND_<TOOL>_CONCURRENCY> built-in default.Requirements traceability
--tool agentdefaults to globally and unconditionally 1-at-a-time. Verified byR1: agent default (global-one-at-a-time) makes only 1 of 2 startable.R2: per-free-model mode lets two different free models start in parallel+R2: per-free-model mode blocks two items with the SAME free model.HIVE_MIND_QUEUE_CONFIG. Verified byparseQueueConfig — *-concurrency lino entries (R3)(4 cases).opencode/...-freeand Kilo Gatewaykilo/...-free) and aliases. Verified byisFreeAgentModelunit cases.R5: claude default (off) does not gate concurrent same-model items+cross-tool isolation: agent gate does NOT block claude/codex.tests/solve-queue-concurrency.test.mjs) and documented indocs/case-studies/issue-1474/README.md.npm testgreen (207/207 test files), lint clean, all line caps respected.Test plan
node tests/solve-queue-concurrency.test.mjs→ 28/28 passnpm test(default suite) → 207/207 test files passnpm run lint→ cleanbash scripts/check-file-line-limits.sh→ all files ≤ 1500 linesReproduction (manual)
Files changed
src/models/index.mjsisFreeAgentModel,normalizeAgentModelKeyhelpers.src/queue-config.lib.mjsCONCURRENCY_MODES,(<tool>-concurrency <mode>)lino parsing,HIVE_MIND_<TOOL>_CONCURRENCYenv var,QUEUE_CONFIG.concurrency,getConcurrencyMode.src/telegram-solve-queue.lib.mjsSolveQueueItem.model+ gate infindStartableItems.src/telegram-solve-queue.concurrency.lib.mjs(new)countProcessingByTool,countProcessingByToolAndModel,canStartUnderConcurrencyMode.src/telegram-bot.mjs--model/-m/--model=at the queue boundary; pass toenqueue.tests/solve-queue-concurrency.test.mjs(new)docs/case-studies/issue-1474/README.md(new).changeset/issue-1474-agent-concurrency.md(new)experiments/{debug-r1,debug-concurrency-second-pass,reproduce-r2-failing,verify-finally-bug}.mjs(new)Atomic commits
feat(models): add isFreeAgentModel and normalizeAgentModelKey helpersfeat(queue): add per-tool concurrency mode to QUEUE_CONFIGfeat(queue): gate findStartableItems on per-(tool, model) concurrencyfeat(telegram-bot): forward --model alias into the solve queuetest(queue): cover per-(tool, model) concurrency gatingdocs(case-studies): add issue-1474 case study + changesetchore(experiments): add debug scripts for issue-1474 investigation