--- icon: lucide/messages-square --- # Conversational pipeline You will build a `ThreadAnonymizationPipeline` that keeps a stable token for the same value from one message to the next. A value seen in message 1 keeps its `<>`{ .placeholder } in message 2, instead of restarting from scratch at each call. You assemble the pipeline with an in-RAM memory, send two messages of the same thread, then erase the thread. !!! note "Prerequisites" `piighost` installed, see [Installation](installation.md). This example uses only the core, no extra. ## 1. Assemble the pipeline `ThreadAnonymizationPipeline` takes the same components as `AnonymizationPipeline` (detector, linker, anonymizer), plus a conversation memory. Only the detector is required. The code below passes only the detector, and the other components keep their defaults. The memory accumulates each message's detections, thread by thread. The pipeline can thus assign tokens over the whole thread rather than over one isolated message. The default memory, `InMemoryConversationMemory`, keeps that state in a process dictionary. Nothing survives a restart and nothing is shared across processes. This memory therefore suits development and tests. The detector stays simple here with `ExactMatchDetector`, which spots known values. The result is thus verifiable, with no model. ```python import asyncio from piighost.components.detector import ExactMatchDetector from piighost.pipeline import ThreadAnonymizationPipeline detector = ExactMatchDetector({"Patrick": "PERSON", "Paris": "LOCATION"}) pipeline = ThreadAnonymizationPipeline(detector) ``` ## 2. De-identify two messages of the same thread `anonymize` takes the text and a `thread_id`. The `thread_id` is required. There is no shared default thread, so two callers cannot fall into the same thread and leak each other's confidential data. The code sends two messages on the thread `"thread-42"`. ```python async def main() -> None: first = await pipeline.anonymize("Patrick lives in Paris.", thread_id="thread-42") print(first.text) second = await pipeline.anonymize("Does Patrick love Paris?", thread_id="thread-42") print(second.text) asyncio.run(main()) ``` The output should be: ```text <> lives in <>. Does <> love <>? ``` `Patrick`{ .pii } keeps `<>`{ .placeholder } from the first message to the second, and `Paris`{ .pii } keeps `<>`{ .placeholder }. With a plain `AnonymizationPipeline`, each call would restart at `<>`{ .placeholder } with no link to the previous message. The thread memory is what makes the number stable. ## 3. Restore a value `deanonymize` rebuilds the thread's tokens from its memory. It therefore restores any text carrying these tokens, including a model reply the pipeline never de-identified. ```python async def main() -> None: restored = await pipeline.deanonymize("Hello <>!", thread_id="thread-42") print(restored) asyncio.run(main()) ``` The output should be: ```text Hello Patrick! ``` ## 4. Forget a thread `forget_thread` erases a thread's memory and returns the count of what was dropped. Useful to honor an erasure request or to free RAM at the end of a conversation. ```python async def main() -> None: forgotten = await pipeline.forget_thread(thread_id="thread-42") print(forgotten) asyncio.run(main()) ``` The output should be: ```text Forgotten(messages=2, detections=4) ``` ## How it works `ThreadAnonymizationPipeline` wraps the base pipeline with a per-thread memory. On each message it caches the detections, then assigns tokens over the union of the whole thread's detections, not the current message alone. A value therefore gets one token for the whole thread. Rendering stays per message. Only the current message's positions are replaced, because each message counts its positions from its own start. ## See also - To share the memory across several processes, replace `InMemoryConversationMemory` with a persistent memory. See the [configuration reference](../configuration/toml.md) to declare it in configuration. - To plug this pipeline into a LangGraph agent, see the [LangChain middleware](langchain.md). - To read the business rules a conversation follows, `BR-CONV-01` to `BR-CONV-11`, see [Follow a conversation and restore the reply](../../../openwiki/en/processes/follow-a-conversation.md).