fix: restore vectors when segments are re-enabled via API (#43865)

This commit is contained in:
Jasonfish
2026-10-11 15:30:10 +00:00
committed by GitHub
parent 2de5d891cb
commit 4f1fe1127f
2 changed files with 91 additions and 0 deletions
@@ -751,6 +751,11 @@ class SegmentMutationService:
raise SegmentNotFoundError("Segment not found")
if self._indexing_state.is_segment_indexing(segment_id):
raise ValueError("Segment is indexing, please try again later")
if args.enabled is True and not previous.enabled and args.model_fields_set == {"enabled"}:
# Disabled segments have no vectors to update. Reuse the console's load-based enable task.
self._store.save_segment(segment_ref, {"enabled": True, "disabled_at": None, "disabled_by": None})
self._index.change_status(scope.document.ref, [segment_id], "enable")
return
if args.enabled is False and previous.enabled:
self._store.save_segment(
segment_ref, {"enabled": False, "disabled_at": naive_utc_now(), "disabled_by": actor_id}
@@ -602,6 +602,92 @@ def segment_update(
return update
@pytest.mark.parametrize("segment_update", ["service_api"], indirect=True)
@pytest.mark.parametrize("doc_form", list(IndexStructureType))
def test_enable_only_patch_queues_reindexing_without_replacing_content(
segment_update: SegmentUpdateEntry,
indexing_probe: IndexingProbe,
sqlite_session_factory: sessionmaker[Session],
doc_form: IndexStructureType,
) -> None:
_, _, probe = indexing_probe
answer = "answer" if doc_form == IndexStructureType.QA_INDEX else None
word_count = 13 if answer else 7
with sqlite_session_factory.begin() as session:
segment = _segment("segment-1", "workspace-1", "dataset-1", "document-1")
segment.enabled = False
segment.disabled_at = datetime(2026, 1, 1)
segment.disabled_by = "previous-editor"
segment.answer = answer
segment.word_count = word_count
segment.keywords = ["original"]
segment.index_node_id = "index-1"
session.add(segment)
document = session.get(Document, "document-1")
assert document is not None
document.doc_form = doc_form
document.word_count = word_count
# A disabled segment has no vector to update. Only the asynchronous load path is valid.
probe.fail = True
result = segment_update(
RequestContext("request", None, "editor", "workspace-1"),
dataset_id="dataset-1",
document_id="document-1",
segment_id="segment-1",
values={"enabled": True},
)
assert result.data.enabled is True
assert result.data.status == "completed"
assert result.data.disabled_at is None
assert result.data.disabled_by is None
assert result.data.content == "content"
assert result.data.answer == answer
assert result.data.keywords == ("original",)
assert result.data.word_count == word_count
assert probe.tasks == [("enable", (["segment-1"], "dataset-1", "document-1"))]
assert probe.deleted_ids == []
assert probe.writes == 0
with sqlite_session_factory() as session:
document = session.get(Document, "document-1")
assert document is not None
assert document.word_count == word_count
@pytest.mark.parametrize("segment_update", ["service_api"], indirect=True)
@pytest.mark.parametrize("values", [{"content": "changed"}, {"keywords": ["replacement"]}])
def test_reenable_patch_with_edits_keeps_synchronous_index_update(
segment_update: SegmentUpdateEntry,
indexing_probe: IndexingProbe,
sqlite_session_factory: sessionmaker[Session],
values: dict[str, object],
) -> None:
_, _, probe = indexing_probe
with sqlite_session_factory.begin() as session:
segment = _segment("segment-1", "workspace-1", "dataset-1", "document-1")
segment.enabled = False
segment.index_node_id = "index-1"
session.add(segment)
result = segment_update(
RequestContext("request", None, "editor", "workspace-1"),
dataset_id="dataset-1",
document_id="document-1",
segment_id="segment-1",
values={"enabled": True, **values},
)
assert result.data.enabled is True
assert result.data.status == "completed"
assert result.data.content == values.get("content", "content")
if "keywords" in values:
assert result.data.keywords == ("replacement",)
assert probe.tasks == []
assert probe.deleted_ids == ["index-1"]
assert probe.writes == 1
@pytest.mark.parametrize("entry", ["console", "service_api"])
@pytest.mark.parametrize("enabled", [True, False])
def test_delete_segment_with_legacy_scalar_keywords(