SDK idempotency and task-history deduplication specification
Duplicate definition
A task-history append is considered a duplicate when it matches an existing history entry according to the selected HistoryAppendPolicy:
kNoDedup: no duplicate detection; every request is appended.kDedupByMessageId: duplicate only when bothmessage_idand the message fingerprint match.kDedupByIdOrFingerprint: with amessage_id, same behavior askDedupByMessageId; without amessage_id, duplicate is determined by fingerprint only.
Fingerprint equality is evaluated on task_id, context_id, role, parts_size, and serialized parts content.
Ignored vs appended behavior
- Ignored (dropped): only when duplicate conditions above are met for the active policy.
- Appended:
- always for
kNoDedup; - for
kDedupByMessageIdwhenmessage_idis missing, or when payload differs; - for
kDedupByIdOrFingerprintwhen neither id+fingerprint nor fingerprint-only duplicate match exists.
- always for
History order is strict append order for accepted entries. Retries that are accepted are appended at the end (no backfilling/reordering).
Missing message_id
For idempotent retry behavior across transports, clients should set message_id consistently per logical message.
When message_id is missing:
kDedupByMessageIdcannot dedupe and the request is appended.kDedupByIdOrFingerprintattempts fingerprint-based dedupe.
Structured telemetry for dedupe drops
InMemoryTaskStore maintains counters via GetHistoryTelemetrySnapshot():
dedupe_dropped_totaldedupe_dropped_by_message_id_and_fingerprintdedupe_dropped_by_fingerprint_without_message_id
Operators can also provide InMemoryTaskStore::HistoryTelemetrySink to consume structured HistoryDedupeEvent records (task_id, message_id, policy, reason) for retry debugging.