feat(groups): I18 — bid-based task assignment (CNP-lite) - #642
Conversation
The planner cannot know members'' actual fit or load; the Contract Net Protocol''s announce-bid-award loop maps onto the existing wave scheduler. - assignmentMode = ROLE (default) | BID on TaskDefinition (per task) and GroupTaskConfig (group default), compat ctors; pre-I18 configs resolve to ROLE. - PLAN leaves BID-mode tasks unassigned; each execution wave announces them to eligible members in blind, parallel bid turns - the prompt carries the batch and nothing else (no transcript, no peer bids), and replies land as peer-hidden BID transcript entries. - Deterministic award: highest confidence, ties by speaking order then agent id; a task nobody bid on falls back to ROLE; the auction skips itself (logged) when it cannot beat its own overhead (<2 bidders, <2 tasks, or no turn budget). Bid turns count toward the budget. - The winning bid is per-task metadata (awardedBids on the task list), deliberately not a global DecisionRecord.
|
Warning Review limit reached
Next review available in: 11 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdded ROLE/BID assignment configuration, a ChangesBID assignment contracts and storage
Bid engine
Execution auction
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant TaskForceEngine
participant TaskBidEngine
participant MemberTurnExecutor
participant SharedTaskList
TaskForceEngine->>TaskBidEngine: Build blind bid prompt
TaskForceEngine->>MemberTurnExecutor: Request parallel member bids
MemberTurnExecutor-->>TaskForceEngine: Return bid responses
TaskForceEngine->>TaskBidEngine: Parse and award bids
TaskBidEngine-->>TaskForceEngine: Return deterministic awards
TaskForceEngine->>SharedTaskList: Store award metadata
Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
CodeQL flagged 6 log-injection sites in the I18 bid round; every caller-influenced value (groupId, task subject, agentIds, exception messages) now passes through LogSanitizer - 7 sites, the 6 flagged plus the bid-turn-failure log.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/main/java/ai/labs/eddi/engine/internal/groups/TaskForceEngine.java (1)
351-354: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winConsider making the bid round observe the discussion control token.
The wave loop checks
activeTokens.get(gc.getId())at Line 339, then callsrunBidRoundIfNeeded. The bid round creates its ownMemberTurnCancellationand never consults the control token. ACANCEL_IMMEDIATEthat arrives while bidders are in flight is therefore not observed until the parallel batch budget expires at Line 1064. The execute wave avoids this by registering itsallOffuture on the token at Lines 520-525.The delay is bounded, so this is a responsiveness gap and not a hang. Passing the token into
runBidRoundIfNeededand callingcancellation.cancel()when it is cancelled would align the bid round with the execute wave.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/main/java/ai/labs/eddi/engine/internal/groups/TaskForceEngine.java` around lines 351 - 354, Update runBidRoundIfNeeded and its caller in the wave loop to accept the discussion control token from activeTokens, register a cancellation callback or equivalent that invokes the bid round’s MemberTurnCancellation when the token is cancelled, and ensure the registration is cleaned up appropriately. Preserve the existing bid-round behavior while allowing CANCEL_IMMEDIATE to interrupt in-flight bidders promptly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/changelog.md`:
- Line 29: Correct the test-count summary in the changelog entry to state 13 new
tests, with 8 TaskBidEngineTest tests and 5 TaskForceEngineTest tests; leave the
listed test coverage and remaining counts unchanged.
In `@docs/group-conversations.md`:
- Around line 158-189: Move the entire “### Bid-based assignment (I18,
CNP-lite)” subsection, including its example and bullets, to immediately after
the paragraph beginning “Both caps are enforced independently” in the
agent-filed tasks content. Preserve the subsection’s text unchanged so “Both
caps” continues to refer to maxPerTurn and maxAgentAddedTasksPerDiscussion.
---
Nitpick comments:
In `@src/main/java/ai/labs/eddi/engine/internal/groups/TaskForceEngine.java`:
- Around line 351-354: Update runBidRoundIfNeeded and its caller in the wave
loop to accept the discussion control token from activeTokens, register a
cancellation callback or equivalent that invokes the bid round’s
MemberTurnCancellation when the token is cancelled, and ensure the registration
is cleaned up appropriately. Preserve the existing bid-round behavior while
allowing CANCEL_IMMEDIATE to interrupt in-flight bidders promptly.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 935121b9-feba-4e29-a0e3-4679c0803327
📒 Files selected for processing (8)
docs/changelog.mddocs/group-conversations.mdsrc/main/java/ai/labs/eddi/configs/groups/model/AgentGroupConfiguration.javasrc/main/java/ai/labs/eddi/configs/groups/model/SharedTaskList.javasrc/main/java/ai/labs/eddi/engine/internal/groups/TaskBidEngine.javasrc/main/java/ai/labs/eddi/engine/internal/groups/TaskForceEngine.javasrc/test/java/ai/labs/eddi/engine/internal/groups/TaskBidEngineTest.javasrc/test/java/ai/labs/eddi/engine/internal/groups/TaskForceEngineTest.java
The changelog's test tally is 13 (8 TaskBidEngineTest + 5 TaskForceEngineTest), and the bid-assignment subsection now follows the agent-task caps paragraph so 'Both caps' keeps its referent.
Summary
Implements I18 — Bid-based task assignment (CNP-lite) from
planning/group-collaboration-improvements-plan.md(Wave 3, adopted from the research review and scoped down — the turn-auction extension stays rejected: an extra LLM call per member per turn to decide who talks doubles cost to save cost). The planner cannot know members' actual fit or load; the Contract Net Protocol's announce-bid-award loop maps cleanly onto the existing wave scheduler.Design (per the plan)
assignmentMode = ROLE (default) | BIDonTaskDefinition(per task) andGroupTaskConfig(group default), both with backward-compatible constructors.TaskBidEngine.effectiveModeresolves task → group → ROLE, so every pre-I18 config behaves exactly as before.TaskForceEngine.runBidRoundIfNeeded, before each wave's grouping so awards join the same wave): eligible members (non-moderator AGENTs) each get one blind, parallel bid turn. The prompt carries the announced batch and nothing else — no transcript, no peer bids; blindness is what makes the self-assessed confidences comparable — and states the honesty rule to the model ("an inflated confidence wins you work you will fail at, on the record"). Replies land asBIDtranscript entries — F4's blind-bid visibility rule (peer-hidden while the phase runs) has its first producer.{"bids": [{"subject", "confidence": 0..1, "estimatedComplexity": "XS|S|M|L", "rationale"}]}; three-tier parse mirroringVoteTallyEngine(FAIL_ON_TRAILING_TOKENS); prose casts no bids; bids on unannounced tasks are dropped; confidence clamped; first-bid-per-task within one reply.SharedTaskList.awardedBids[taskId] = AwardedBid{agentId, confidence, estimatedComplexity, rationale}— deliberately not a globalDecisionRecord: an award is a scheduling fact about one task, not the discussion's conclusion.Tests (12 new; 1694 green across
engine.internal+configs.groups; checkstyle clean)TaskBidEngineTest(pure): parse tiers + clamping ([0,1] both ends) + unknown-subject drop + case-insensitive canonical match; award to highest confidence with rationale carried; tie-break determinism (speaking order, then agent id for unordered members); no-bids absence; effective-mode chain; worthwhile-auction caps; blind prompt content.TaskForceEngineTest(engine, mocked member turns): award to highest confidence with recordedawardedBid, turn accounting, and BID entries on the transcript; blindness asserted on the captured prompts (no peer rationale or confidence leaks); no-bids ROLE fallback assigns every task (never stalls the wave) without fabricating awards; skip-conditions (1 bidder / 1 task) make zero LLM calls yet still assign; ROLE-mode tasks are never auctioned.Summary by CodeRabbit
New Features
Documentation
Tests