### Summary
Multi-type memory prompts were assembled from sets, so their instruction
and output sections could change order across Python processes with
different hash seeds. Because the generated default prompt is persisted
and later compared as a string, a restart could make an untouched
default look custom and prevent it from being regenerated when memory
types change.
## Summary
- require a `valid_at` timestamp in the semantic-memory output schema
- tell the extraction model to use conversation time when a fact has no
date of its own
- add a regression test for the assembled semantic prompt
This addresses the deterministic prompt inconsistency reported in
#18415. The invalid-timestamp fallback is intentionally left unchanged
because selecting its replacement policy requires a separate design
decision.
This PR adds focused unit tests for aggregate_by_field in OceanBase
memory utilities to improve behavior coverage for real-world input
shapes.
- Adds test coverage for list-valued aggregation fields, including
whitespace trimming and skipping invalid list entries.
- Adds test coverage for scalar field values to ensure blank/non-string
values are ignored.
- Confirms aggregation output remains correct and stable for
mixed-quality message payloads.
### Why this helps
It strengthens regression protection for aggregation logic used by
memory retrieval flows, with no production code changes and minimal
review risk.
### What problem does this PR solve?
- Add aggregation_utils.aggregate_by_field for pure aggregation logic
- Wire OBConnection.get_aggregation to use it (unwrap tuple, pass
messages)
- Add unit tests for aggregate_by_field (no DB/heavy deps)
### Type of change
- [x] New Feature (non-breaking change which adds functionality)