Skip to content

refactor(worker): use event segmenter instead of queue#67

Draft
kwaa wants to merge 29 commits intomainfrom
refactor/es-worker
Draft

refactor(worker): use event segmenter instead of queue#67
kwaa wants to merge 29 commits intomainfrom
refactor/es-worker

Conversation

@kwaa
Copy link
Copy Markdown
Member

@kwaa kwaa commented Apr 24, 2026

Before

plast-mem

Overall

split F1 NemoriF1 LLM n
overall 47.18% 49.68% 67.00% 150

Samples

sample F1 NemoriF1 LLM n
conv-47 47.18% 49.68% 67.00% 150

Categories

id category F1 NemoriF1 LLM n
c1 multi-hop 24.91% 41.74% 62.50% 20
c2 temporal 19.52% 18.72% 38.24% 34
c3 open-domain 7.10% 5.99% 42.31% 13
c4 single-hop 70.15% 71.12% 83.73% 83

full-context

Overall

split F1 NemoriF1 LLM n
overall 47.60% 49.05% 71.33% 150

Samples

sample F1 NemoriF1 LLM n
conv-47 47.60% 49.05% 71.33% 150

Categories

id category F1 NemoriF1 LLM n
c1 multi-hop 19.01% 32.88% 62.50% 20
c2 temporal 25.41% 26.08% 47.06% 34
c3 open-domain 15.36% 15.23% 50.00% 13
c4 single-hop 68.63% 67.66% 86.75% 83

delta

Overall Delta

metric delta
F1 -0.42%
NemoriF1 +0.63%
LLM -4.33%

Category Delta

id category F1 NemoriF1 LLM
c1 multi-hop +5.90% +8.86% +0.00%
c2 temporal -5.90% -7.36% -8.82%
c3 open-domain -8.26% -9.24% -7.69%
c4 single-hop +1.53% +3.47% -3.01%

After

plast-mem

Overall

split F1 NemoriF1 LLM n
overall 48.87% 49.83% 73.00% 150

Samples

sample F1 NemoriF1 LLM n
conv-47 48.87% 49.83% 73.00% 150

Categories

id category F1 NemoriF1 LLM n
c1 multi-hop 20.84% 37.40% 57.50% 20
c2 temporal 22.88% 17.19% 50.00% 34
c3 open-domain 17.36% 16.88% 50.00% 13
c4 single-hop 71.22% 71.36% 89.76% 83

full-context

Overall

split F1 NemoriF1 LLM n
overall 47.60% 49.05% 71.33% 150

Samples

sample F1 NemoriF1 LLM n
conv-47 47.60% 49.05% 71.33% 150

Categories

id category F1 NemoriF1 LLM n
c1 multi-hop 19.01% 32.88% 62.50% 20
c2 temporal 25.41% 26.08% 47.06% 34
c3 open-domain 15.36% 15.23% 50.00% 13
c4 single-hop 68.63% 67.66% 86.75% 83

delta

Overall Delta

metric delta
F1 +1.28%
NemoriF1 +0.78%
LLM +1.67%

Category Delta

id category F1 NemoriF1 LLM
c1 multi-hop +1.83% +4.52% -5.00%
c2 temporal -2.53% -8.89% +2.94%
c3 open-domain +2.00% +1.65% +0.00%
c4 single-hop +2.59% +3.71% +3.01%

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant refactor of the message processing and event segmentation pipeline. It consolidates message queuing, pending review management, and episode creation into a new MessageQueue and a revised EventSegmentationJob worker, removing the older, more granular job types. The changes update API endpoints and worker configurations to align with the new architecture. Key feedback includes a high-severity concern about potential data loss for pending reviews if enqueuing fails, and medium-severity issues regarding the loss or underutilization of prev_episode_content during segmentation, which could impact context continuity. A compatibility warning was also noted for a PostgreSQL 14-specific jsonpath syntax.

"Segmentation claim has no messages"
)));
}
enqueue_pending_reviews(conversation_id, batch_messages, db, &review_storage).await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

enqueue_pending_reviews calls take_pending_reviews, which clears reviews from the database in its own transaction. If the subsequent review_storage.push fails, these reviews are lost from the database and never enqueued in Apalis. Consider clearing the reviews from the database only after successful enqueuing, or ideally, within the same transaction as the episode persistence.

actual = current_messages.len(),
"Stale event segmentation job; clearing fence"
);
MessageQueue::finalize_job(conversation_id, None, db).await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using finalize_job with None here will overwrite any existing prev_episode_content in the database. Since this is a stale job recovery case where no new content was generated, it's better to use clear_fence to preserve the existing context.

Suggested change
MessageQueue::finalize_job(conversation_id, None, db).await?;
MessageQueue::clear_fence(conversation_id, db).await?;

queue_len = current_messages.len(),
"Force processing as single episode"
);
(&segments[..], None)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When forcing a single segment, new_prev_content is set to None, which causes the context for the next segmentation batch to be lost. It should be set to the content of the segment just processed to maintain continuity.

Suggested change
(&segments[..], None)
(&segments[..], segments.last().map(|s| s.content.clone()))

keep_tail_segment = job.keep_tail_segment,
"Event segmentation complete"
);
(&segments[..], None)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

When draining all segments, new_prev_content is set to None. This wipes the context for the next batch of messages. It should be set to the content of the last segment processed.

Suggested change
(&segments[..], None)
(&segments[..], segments.last().map(|s| s.content.clone()))


async fn batch_segment(messages: &[Message]) -> Result<Vec<BatchSegment>, AppError> {
let events = messages.iter().map(message_to_event).collect::<Vec<_>>();
let event_segments = EventSegmenter::segment(&events).await?;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The prev_episode_content context is stored in the message queue but is never fetched or passed to the EventSegmenter. Providing this context would likely improve boundary detection and topic continuity between batches.

C: ConnectionTrait,
{
let sql = format!(
"UPDATE message_queue SET messages = jsonb_path_query_array(messages, '$[{count} to last]'::jsonpath) WHERE id = $1"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The $[count to last] syntax in jsonpath was introduced in PostgreSQL 14. If the deployment environment uses an older version (e.g., Postgres 12 or 13), this query will fail. Ensure the target environment meets this requirement or use a more compatible array slicing method.

Base automatically changed from refactor/event-segmentation to main April 25, 2026 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant