fix(knowledge-fs): allow replay evidence detail query

This commit is contained in:
Jyong 2026-08-21 03:10:14 -04:00
parent 0864965d2c
commit 2ef7719b02
5 changed files with 43 additions and 3 deletions

View File

@ -4,6 +4,6 @@
"openapiSha256": "2cf348c68bbe65dd51bbde9a0a4f91398beeebd79e89e9288c9386b26ae09796",
"capabilityV2AuthManifestSha256": "fc0a47e23cce12544882f0298522b4933002e892b84ce1815df7e81d36a7a0c7",
"capabilityV2AuthTestVectorSha256": "ae0de37b1ff05c40f905cf17a7b410d8971acacf64db07d5ee3d6fecfa559ce3",
"productOperationManifestSha256": "11f801a41805b250f17766935ee9cc7fc93c3ef6489503ba6297673b73362b7d",
"productOperationManifestSha256": "32f305d86525f31eb07a6aef1f72d286d53991f1f8ed1f9d6e52d37cf4561116",
"productOperationGapManifestSha256": "332c80165bd5cf8e79bc511374dde771a8175510404db603a8067f1a22d36df8"
}

View File

@ -98,7 +98,7 @@
{"productOperationId":"updateQualityBadCase","kfsOperationId":"updateQualityBadCase","method":"PATCH","path":"/knowledge-spaces/{id}/quality/bad-cases/{badCaseId}","action":"quality.write","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":65536,"productMaxResponseBytes":524288,"kfsMaxResponseBytes":1048576}},
{"productOperationId":"createQualityReplay","kfsOperationId":"createQualityReplay","method":"POST","path":"/knowledge-spaces/{id}/quality/replay-runs","action":"quality.write","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":65536,"productMaxResponseBytes":4194304,"kfsMaxResponseBytes":4194304}},
{"productOperationId":"listQualityReplays","kfsOperationId":"listQualityReplays","method":"GET","path":"/knowledge-spaces/{id}/quality/replay-runs","action":"quality.read","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":16384,"productMaxResponseBytes":4194304,"kfsMaxResponseBytes":4194304}},
{"productOperationId":"getQualityReplay","kfsOperationId":"getQualityReplay","method":"GET","path":"/knowledge-spaces/{id}/quality/replay-runs/{runId}","action":"quality.read","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":0,"productMaxResponseBytes":4194304,"kfsMaxResponseBytes":4194304}},
{"productOperationId":"getQualityReplay","kfsOperationId":"getQualityReplay","method":"GET","path":"/knowledge-spaces/{id}/quality/replay-runs/{runId}","action":"quality.read","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":16384,"productMaxResponseBytes":4194304,"kfsMaxResponseBytes":4194304}},
{"productOperationId":"getQualityBadCaseTraceReference","kfsOperationId":"getQualityBadCaseTraceReference","method":"GET","path":"/knowledge-spaces/{id}/quality/bad-cases/{badCaseId}/trace-reference","action":"quality.read","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":0,"productMaxResponseBytes":65536,"kfsMaxResponseBytes":1048576}},
{"productOperationId":"listTraces","kfsOperationId":"listKnowledgeSpaceQualityTraces","method":"GET","path":"/knowledge-spaces/{id}/quality/traces","action":"quality.traces.list","resource":"knowledge_space","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":16384,"productMaxResponseBytes":4194304,"kfsMaxResponseBytes":1048576}},
{"productOperationId":"getTrace","kfsOperationId":"getAnswerTrace","method":"GET","path":"/queries/{traceId}","action":"queries.read","resource":"query","transport":"json","stream":{"productKind":"json","kfsResponseKind":"buffered"},"limits":{"productMaxRequestBytes":16384,"productMaxResponseBytes":2097152,"kfsMaxResponseBytes":1048576}},

View File

@ -1152,7 +1152,9 @@ KNOWLEDGE_FS_PRODUCT_OPERATIONS: Final[MappingProxyType[str, KnowledgeFSProductO
"/knowledge-spaces/{id}/quality/replay-runs/{runId}",
"json",
resource_resolver="knowledge_space",
max_request_bytes=0,
# The optional evidenceItemId detail selector is transported as a query string.
# Keep the same bounded query allowance as the replay list operation.
max_request_bytes=16 * 1024,
max_response_bytes=4 * 1024 * 1024,
stream_kind="json",
),

View File

@ -154,6 +154,7 @@ def test_ready_product_operations_exactly_match_capability_method_path_and_actio
assert product_operation.max_response_bytes > 0
assert KNOWLEDGE_FS_PRODUCT_OPERATIONS["createDocument"].max_request_bytes == 15 * 1024 * 1024
assert KNOWLEDGE_FS_PRODUCT_OPERATIONS["getQualityReplay"].max_request_bytes == 16 * 1024
assert KNOWLEDGE_FS_PRODUCT_OPERATIONS["importSourceWorkflow"].max_request_bytes == 4 * 1024 * 1024
assert KNOWLEDGE_FS_PRODUCT_OPERATIONS["uploadSmallFile"].max_request_bytes == 8 * 1024 * 1024

View File

@ -60,6 +60,43 @@ def test_remote_client_builds_capability_only_headers(monkeypatch: pytest.Monkey
assert captured["follow_redirects"] is False
def test_remote_client_allows_quality_replay_evidence_detail_query(
monkeypatch: pytest.MonkeyPatch,
) -> None:
captured: dict[str, object] = {}
response = httpx.Response(
200,
json={"id": "run-1", "items": []},
headers={"Content-Type": "application/json"},
)
def fake_make_request(**kwargs):
captured.update(kwargs)
return response
monkeypatch.setattr(ssrf_proxy, "make_request", fake_make_request)
monkeypatch.setattr(ssrf_proxy, "buffer_response", lambda response, **_: response)
client = HTTPKnowledgeFSProductRemoteClient(base_url="https://knowledge-fs.test", timeout_seconds=3)
evidence_item_id = "771a6d87-6421-458d-bd44-5127f016370d"
result = client.execute_json(
KnowledgeFSRemoteJSONRequest(
operation_id="getQualityReplay",
method="GET",
path="/knowledge-spaces/space-1/quality/replay-runs/run-1",
namespace_id="tenant-1",
knowledge_space_id="space-1",
capability_token="capability-token",
trace_id="trace-1",
payload=None,
query=(("evidenceItemId", evidence_item_id),),
)
)
assert result == {"id": "run-1", "items": []}
assert captured["params"] == (("evidenceItemId", evidence_item_id),)
def test_remote_client_streams_sse_through_internal_capability_transport(
monkeypatch: pytest.MonkeyPatch,
) -> None: