Interface ActivityStore
- All Known Implementing Classes:
InMemoryActivityStore
write an event as it happens, and read a filtered slice back when the assistant needs context.
What this interface is for
The capture layer pushes a UserActivityEvent here every time the user does something
meaningful; the context layer pulls a recent slice back to render into a prompt. Keeping these
two operations behind an interface means the policy of where activity lives — in memory,
in a database, in nothing at all — is a swappable decision that the rest of the feature never has
to know about.
Familiar analogy: the standard power socket in a wall. Appliances (the capture and
context layers) plug into the same socket shape; behind the wall the electricity might come from
the grid, a battery, or a generator. ActivityStore is that socket — one stable shape, many
possible sources behind it.
Implementations
InMemoryActivityStore— the default. A bounded, per-session ring-buffer that keeps only a recent window and evaporates when the process stops. This is the right choice for v1: the ambient primitive only ever reads a recent slice, so durable storage isn't needed, and a memory-only store is also the most privacy-friendly default.- Durable backends (a JPA-backed or SQLite-backed store) are deliberately deferred to a later
version. They become useful only once you want activity to survive restarts or be queried
historically — at which point you provide your own
@Alternativeimplementing this same SPI, and nothing else changes.
Contract for implementations
- Be thread-safe.
record(dyntabs.ai.activity.UserActivityEvent)is called from request threads as users act;query(dyntabs.ai.activity.ActivityQuery)may run on another thread when the assistant is invoked. query(dyntabs.ai.activity.ActivityQuery)returns a snapshot in chronological order (oldest first), so a renderer can read it straight through as a timeline. The returned list is the caller's to keep; mutating it must not affect the store.- Never throw from
record(dyntabs.ai.activity.UserActivityEvent). Capturing activity is a side-channel; a storage hiccup must never break the user's actual action.
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptionquery(ActivityQuery query) Return the events matching the given query, oldest first, capped by the query's limit.default List<UserActivityEvent> Convenience shortcut for the overwhelmingly common read: "the lastlimitevents in this session and tab".voidrecord(UserActivityEvent event) Append one event to the timeline.
-
Method Details
-
record
Append one event to the timeline.Implementations should treat this as best-effort and non-throwing: it runs on the user's request thread, and recording is never more important than the action being recorded.
- Parameters:
event- the event to store; must not benull
-
query
Return the events matching the given query, oldest first, capped by the query's limit.- Parameters:
query- the filter describing which slice to return; must not benull- Returns:
- a chronological, caller-owned snapshot list; never
null(empty if nothing matches)
-
recent
Convenience shortcut for the overwhelmingly common read: "the lastlimitevents in this session and tab".Analogy: a "show recent" button that pre-fills the search form for you. It simply builds an
ActivityQuerywith the session, tab and limit set and delegates toquery(ActivityQuery).- Parameters:
sessionId- the session to scope to (ornullfor any)tabId- the tab to scope to (ornullfor any)limit- the maximum number of most-recent events (<= 0means no limit)- Returns:
- a chronological, caller-owned snapshot list; never
null
-