Skip to content

feat(autogen): add AG2-015, mutating tool has no idempotency key - #101

Open
bradAGI wants to merge 1 commit into
trustabl:mainfrom
bradAGI:feat/ag2-015-idempotency
Open

feat(autogen): add AG2-015, mutating tool has no idempotency key#101
bradAGI wants to merge 1 commit into
trustabl:mainfrom
bradAGI:feat/ag2-015-idempotency

Conversation

@bradAGI

@bradAGI bradAGI commented Aug 24, 2026

Copy link
Copy Markdown

Paired with the engine PR on a branch of the same name, so rules-sync resolves this pack. Neither should merge alone.

The gap

Six packs ship an idempotency rule. AutoGen does not:

pack rule pack rule
Claude Agent SDK CSDK-006 / CSDK-016 MCP MCP-007
OpenAI Agents SDK OAI-009 / OAI-019 CrewAI CREW-006
Google ADK ADK-006 Pydantic AI PYD-007
AutoGen — none —

AG2-015 uses the same name_has_prefix + param_name_matches predicate pair as CREW-006, at the same medium / 0.55.

Why it matters specifically here

The generic argument is that retries re-run side effects. AutoGen supplies more ways for the retry to happen than a single-agent loop does, and both come from its conversation model:

  • The tool response is a message in a conversation that is re-sent in full on every later turn. A call whose result read as inconclusive does not scroll away — it stays visible and re-invitable for the rest of the run.
  • In a GroupChat, any speaker the manager selects can re-issue it — including an agent that was not the original caller, and therefore cannot know the side effect already committed.

So the window in which a duplicate refund_payment can fire is the whole run, and the agent that fires it may be one with no memory of the first attempt.

The fix text names the non-fix

Worth flagging, because it is the common way this gets "fixed" wrongly:

Derive the key from the request's own identity, not from a fresh uuid4() per call — a key regenerated on the retry deduplicates nothing.

A parameter named idempotency_key filled with a fresh UUID at each call satisfies the rule while providing no deduplication at all. The rule cannot see this; the text says so.

Verified end to end

AG2-015 [medium] refund_payment tools.py:6

The sample's second tool is the same refund_payment with an idempotency_key parameter threaded through to the backing call; the rule did not fire on it.

Claude, OpenAI, Google ADK, MCP, CrewAI and Pydantic AI all ship an
idempotency rule (CSDK-006/016, OAI-009/019, ADK-006, MCP-007, CREW-006,
PYD-007). AutoGen shipped none.

Same name_has_prefix + param_name_matches predicate pair as CREW-006, at the
same medium / 0.55.

The explanation names the retry paths AutoGen adds over a single-agent loop:
the tool response is a message in a conversation re-sent in full on every later
turn, so an inconclusive call stays visible and re-invitable for the rest of
the run, and in a group chat any speaker the manager selects can re-issue it —
including an agent that was not the original caller and cannot know the side
effect already committed.

The fix text also names the mistake that defeats the fix: deriving the key from
a fresh uuid4() per call deduplicates nothing, because the retry regenerates it.
@jhumel-code

Copy link
Copy Markdown
Collaborator

Thanks @bradAGI, this is a clean addition and it closes a real gap (every other pack with mutating tools already carries an idempotency rule). I verified the pack against the engine on main: name_has_prefix and param_name_matches both exist, autogen_tool is valid at tool scope, AG2-015 is unclaimed on main, and since no new predicate is introduced the manifest correctly stays at schema_version: 14. Severity and confidence (medium, 0.55) line up exactly with CREW-006, which this rule is modeled on, and I appreciate that the explanation was reframed for AutoGen's conversation model (the re-sent transcript, the group chat speaker re-issuing a call) rather than copied from the CrewAI text. The uuid4 caveat in the fix is a genuinely useful sentence. The engine half at trustabl/trustabl#138 mirrors this file byte for byte and carries fire and silent cases, so the sync contract is satisfied.

One coordination item before either half merges: you have a second open pair claiming AG2-015 with essentially the same rule, #63 paired with trustabl/trustabl#142. This pair reads like the refinement, but the call is yours; please close whichever pair is superseded so we have one in-flight claim on the ID.

Separately, the rule needs a rationale doc in trustabl-rulebook before it ships; we can handle that on our side or pair on it, no action needed from you there.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants