Files
wehub-resource-sync bcbd1bdb22
Test (Python) / test-python-gate (push) Blocked by required conditions
Test (TypeScript) / test-typescript-gate (push) Blocked by required conditions
CLI exit codes / cli-gate (push) Blocked by required conditions
Test (Install) / test-install-gate (push) Blocked by required conditions
Integ / integ-gate (push) Blocked by required conditions
CLI exit codes / Python CLI (push) Waiting to run
Integ / changes (push) Has been skipped
Test (Install) / python-minimal (3.11) (push) Waiting to run
Test (Install) / python-minimal (3.12) (push) Waiting to run
Test (Install) / python-extra (chroma, mirage.resource.chroma) (push) Waiting to run
Integ / integ-ts (push) Waiting to run
Integ / integ (push) Waiting to run
Test (Install) / python-extra (deepagents, mirage.agents.langchain) (push) Waiting to run
Integ / integ-database (push) Waiting to run
Test (Install) / python-extra (email, mirage.resource.email) (push) Waiting to run
Test (Install) / python-extra (hdf5, mirage.core.filetype.hdf5) (push) Waiting to run
Integ / integ-ssh (push) Waiting to run
Pre-commit / pre-commit (push) Failing after 1s
CLI exit codes / changes (push) Has been skipped
Test (Install) / changes (push) Has been skipped
CLI exit codes / TypeScript CLI (push) Waiting to run
CLI exit codes / Cross-language snapshot interop (push) Waiting to run
Test (Install) / python-extra (agno, mirage.agents.agno) (push) Waiting to run
Test (Install) / python-extra (databricks, mirage.resource.databricks_volume) (push) Waiting to run
Test (Python) / changes (push) Has been skipped
Integ / integ-database-ts (push) Waiting to run
Test (Install) / python-extra (fuse, mirage.fuse.mount) (push) Waiting to run
Integ / integ-data (push) Waiting to run
Test (Install) / python-extra (lancedb, mirage.resource.lancedb) (push) Waiting to run
Test (Python) / test (push) Waiting to run
Integ / integ-fuse (push) Waiting to run
Test (Install) / python-extra (langfuse, mirage.resource.langfuse) (push) Waiting to run
Test (Python) / import-isolation (deepagents, openai, mirage.agents.openai_agents) (push) Waiting to run
Test (Python) / audit (push) Waiting to run
Test (Install) / python-extra (hf, mirage.resource.hf_buckets) (push) Waiting to run
Integ / integ-ssh-ts (push) Waiting to run
Test (Install) / python-extra (mongodb, mirage.resource.mongodb) (push) Waiting to run
Test (Python) / import-isolation (deepagents, pydantic-ai, mirage.agents.pydantic_ai) (push) Waiting to run
Test (TypeScript) / changes (push) Has been skipped
Test (Install) / python-extra (nextcloud, mirage.resource.nextcloud) (push) Waiting to run
Test (Install) / python-extra (openai, mirage.agents.openai_agents) (push) Waiting to run
Test (Install) / python-extra (openhands, mirage.agents.openhands, 3.12) (push) Waiting to run
Test (Install) / python-extra (parquet, mirage.core.filetype.parquet) (push) Waiting to run
Test (TypeScript) / test (push) Waiting to run
Test (Install) / python-extra (pdf, mirage.core.filetype.pdf) (push) Waiting to run
Test (TypeScript) / python-fs-shim (push) Waiting to run
Test (Install) / python-extra (postgres, mirage.resource.postgres) (push) Waiting to run
Test (Install) / python-extra (pydantic-ai, mirage.agents.pydantic_ai) (push) Waiting to run
Test (Install) / python-extra (qdrant, mirage.resource.qdrant) (push) Waiting to run
Test (Install) / python-extra (redis, mirage.resource.redis) (push) Waiting to run
Test (Install) / python-extra (s3, mirage.resource.s3) (push) Waiting to run
Test (Install) / python-extra (ssh, mirage.resource.ssh) (push) Waiting to run
Test (Install) / ts-minimal (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 12:30:44 +08:00

429 lines
13 KiB
Python

from types import SimpleNamespace
import pytest
from mirage.cache.index import RAMIndexCacheStore
from mirage.types import PathSpec
from mirage.utils.key_prefix import mount_key
def document(document_id: str, name: str, slug: str | None = None) -> dict:
metadata = []
if slug is not None:
metadata = [{"name": "slug", "value": slug}]
return {
"id": document_id,
"name": name,
"doc_metadata": metadata,
"enabled": True,
"indexing_status": "completed",
"archived": False,
"tokens": 4,
"data_source_type": "upload_file",
"data_source_detail_dict": {
"upload_file": {
"size": 12
}
},
"created_at": 1716282000,
}
def accessor() -> SimpleNamespace:
return SimpleNamespace(config=SimpleNamespace(dataset_id="dataset-1",
slug_metadata_name="slug"))
def custom_slug_accessor() -> SimpleNamespace:
return SimpleNamespace(config=SimpleNamespace(dataset_id="dataset-1",
slug_metadata_name="path"))
custom_slug_search_bodies: list[dict] = []
async def list_path_metadata_documents(config):
return [{
**document("doc-1", "API"), "doc_metadata": [{
"name": "path",
"value": "guides/api"
}]
}]
async def record_empty_custom_slug_search(config, endpoint, body):
custom_slug_search_bodies.append(body)
return {"records": []}
@pytest.mark.asyncio
async def test_search_segments_scopes_folder_to_all_documents(monkeypatch):
from mirage.core.dify import search, tree
bodies: list[dict] = []
async def list_documents(config):
return [
document("doc-1", "API", "guides/api"),
document("doc-2", "Auth", "guides/auth"),
document("doc-3", "README.md"),
]
async def dify_post(config, endpoint, body):
bodies.append(body)
return {
"records": [{
"segment": {
"content": "api segment",
"document": {
"name": "API",
"doc_metadata": [{
"name": "slug",
"value": "guides/api"
}],
},
},
"score": 0.92,
}, {
"segment": {
"content": "auth segment",
"document": {
"name": "Auth",
"doc_metadata": [{
"name": "slug",
"value": "guides/auth"
}],
},
},
"score": 0.81,
}]
}
monkeypatch.setattr(tree, "list_all_documents", list_documents)
monkeypatch.setattr(search, "dify_post", dify_post)
result = await search.search_segments(
accessor(),
"login docs",
[
PathSpec(resource_path=mount_key("/knowledge/guides",
"/knowledge"),
virtual="/knowledge/guides",
directory="/knowledge/guides")
],
RAMIndexCacheStore(),
method="hybrid",
top_k=2,
threshold=0.4,
)
assert result == (b"/knowledge/guides/api:0.92\napi segment\n"
b"/knowledge/guides/auth:0.81\nauth segment\n")
retrieval = bodies[0]["retrieval_model"]
assert retrieval["search_method"] == "hybrid_search"
assert retrieval["top_k"] == 2
assert retrieval["score_threshold_enabled"] is True
assert retrieval["score_threshold"] == 0.4
assert retrieval["metadata_filtering_conditions"] == {
"logical_operator":
"or",
"conditions": [{
"name": "slug",
"comparison_operator": "in",
"value": ["guides/api", "guides/auth"],
}],
}
@pytest.mark.asyncio
async def test_search_segments_unions_slug_and_name_based_paths(monkeypatch):
from mirage.core.dify import search, tree
bodies: list[dict] = []
async def list_documents(config):
return [
document("doc-1", "API", "guides/api"),
document("doc-2", "README.md"),
]
async def dify_post(config, endpoint, body):
bodies.append(body)
return {"records": []}
monkeypatch.setattr(tree, "list_all_documents", list_documents)
monkeypatch.setattr(search, "dify_post", dify_post)
result = await search.search_segments(
accessor(),
"setup",
[
PathSpec(resource_path=mount_key("/knowledge/guides/api",
"/knowledge"),
virtual="/knowledge/guides/api",
directory="/knowledge/guides/api"),
PathSpec(resource_path=mount_key("/knowledge/README.md",
"/knowledge"),
virtual="/knowledge/README.md",
directory="/knowledge/README.md"),
],
RAMIndexCacheStore(),
)
assert result == b""
assert bodies[0]["retrieval_model"]["metadata_filtering_conditions"] == {
"logical_operator":
"or",
"conditions": [{
"name": "slug",
"comparison_operator": "in",
"value": ["guides/api"],
}, {
"name": "document_name",
"comparison_operator": "in",
"value": ["README.md"],
}],
}
@pytest.mark.asyncio
async def test_search_segments_uses_configured_slug_metadata_name(monkeypatch):
from mirage.core.dify import search, tree
custom_slug_search_bodies.clear()
monkeypatch.setattr(tree, "list_all_documents",
list_path_metadata_documents)
monkeypatch.setattr(search, "dify_post", record_empty_custom_slug_search)
await search.search_segments(
custom_slug_accessor(),
"setup",
[
PathSpec(resource_path=mount_key("/knowledge/guides/api",
"/knowledge"),
virtual="/knowledge/guides/api",
directory="/knowledge/guides/api")
],
RAMIndexCacheStore(),
)
assert custom_slug_search_bodies[0]["retrieval_model"][
"metadata_filtering_conditions"] == {
"logical_operator":
"or",
"conditions": [{
"name": "path",
"comparison_operator": "in",
"value": ["guides/api"],
}],
}
@pytest.mark.asyncio
async def test_search_segments_empty_paths_searches_whole_dataset(monkeypatch):
from mirage.core.dify import search
bodies: list[dict] = []
async def dify_post(config, endpoint, body):
bodies.append(body)
return {
"records": [{
"segment": {
"content": "dataset match",
"document": {
"name": "README.md",
"doc_metadata": None,
},
},
"score": 0.77,
}]
}
monkeypatch.setattr(search, "dify_post", dify_post)
result = await search.search_segments(accessor(),
"anything", [],
RAMIndexCacheStore(),
mount_prefix="/knowledge/")
assert result == b"/knowledge/README.md:0.77\ndataset match\n"
assert "metadata_filtering_conditions" not in bodies[0]["retrieval_model"]
def test_records_to_bytes_formats_absolute_paths_and_scores():
from mirage.core.dify.search import records_to_bytes
result = records_to_bytes(
[{
"segment": {
"content": "api segment",
"document": {
"name": "API",
"doc_metadata": [{
"name": "slug",
"value": "guides/api"
}],
},
},
"score": 0.92,
}, {
"segment": {
"content": "auth segment",
"document": {
"name": "README.md",
"doc_metadata": None,
},
},
}],
"slug",
"/knowledge/",
)
assert result == (b"/knowledge/guides/api:0.92\napi segment\n"
b"/knowledge/README.md\nauth segment\n")
def test_records_to_bytes_keeps_multiple_chunks_for_same_document():
from mirage.core.dify.search import records_to_bytes
result = records_to_bytes(
[{
"segment": {
"content": "first chunk",
"document": {
"name":
"refunds.md",
"doc_metadata": [{
"name": "slug",
"value": "policies/refunds"
}],
},
},
"score": 0.82,
}, {
"segment": {
"content": "second chunk",
"document": {
"name":
"refunds.md",
"doc_metadata": [{
"name": "slug",
"value": "policies/refunds"
}],
},
},
"score": 0.79,
}],
"slug",
"/knowledge/",
)
assert result == (b"/knowledge/policies/refunds:0.82\nfirst chunk\n"
b"/knowledge/policies/refunds:0.79\nsecond chunk\n")
def test_records_to_bytes_skips_records_with_invalid_slug():
from mirage.core.dify.search import records_to_bytes
result = records_to_bytes(
[{
"segment": {
"content": "bad chunk",
"document": {
"name": "ok.md",
"doc_metadata": [{
"name": "slug",
"value": ""
}],
},
},
"score": 0.82,
}, {
"segment": {
"content": "good chunk",
"document": {
"name":
"refunds.md",
"doc_metadata": [{
"name": "slug",
"value": "policies/refunds"
}],
},
},
"score": 0.79,
}],
"slug",
"/knowledge/",
)
assert result == b"/knowledge/policies/refunds:0.79\ngood chunk\n"
def test_records_to_bytes_omits_score_for_non_numeric_values():
from mirage.core.dify.search import records_to_bytes
result = records_to_bytes(
[{
"segment": {
"content": "chunk",
"document": {
"name":
"refunds.md",
"doc_metadata": [{
"name": "slug",
"value": "policies/refunds"
}],
},
},
"score": True,
}],
"slug",
"/knowledge/",
)
assert result == b"/knowledge/policies/refunds\nchunk\n"
@pytest.mark.asyncio
async def test_search_segments_caps_top_k_at_dify_limit(monkeypatch):
from mirage.core.dify import search
bodies: list[dict] = []
async def dify_post(config, endpoint, body):
bodies.append(body)
return {"records": []}
monkeypatch.setattr(search, "dify_post", dify_post)
await search.search_segments(accessor(),
"anything", [],
RAMIndexCacheStore(),
top_k=150)
assert bodies[0]["retrieval_model"]["top_k"] == 100
@pytest.mark.asyncio
async def test_search_segments_validates_arguments():
from mirage.core.dify.search import search_segments
with pytest.raises(ValueError, match="search: query is required"):
await search_segments(accessor(), "", [], RAMIndexCacheStore())
with pytest.raises(ValueError, match="search: top-k must be positive"):
await search_segments(accessor(),
"x", [],
RAMIndexCacheStore(),
top_k=0)
with pytest.raises(ValueError, match="search: threshold must be in"):
await search_segments(accessor(),
"x", [],
RAMIndexCacheStore(),
threshold=1.2)
with pytest.raises(ValueError, match="search: method must be one of"):
await search_segments(accessor(),
"x", [],
RAMIndexCacheStore(),
method="bad")