asyncio.create_task() is only weakly referenced by the event loop. If the
caller discards the returned Task object the GC can destroy it before the
coroutine finishes, silently dropping any messages that were queued for
storage.
The Cartesia SDK in this same repo already uses the correct pattern
(_background_tasks set + add_done_callback(discard)). Apply the same fix
to SupermemoryPipecatService:
* Add `_background_tasks: set` in __init__
* Save every storage task in the set; remove it via done-callback once
complete
* Clear the set in reset_memory_tracking()
Adds tests/test_background_task_tracking.py with five test cases:
- presence of _background_tasks attribute
- task is held in the set while running
- task is removed from the set after completion
- a forced GC cycle cannot collect a tracked task mid-execution
- reset_memory_tracking clears the set