fix(knowledge_fs): accept direct unpublished profile activation responses and validate settings

This commit is contained in:
FFXN 2026-08-25 16:30:46 +08:00
parent fbc7c85af1
commit 013ddcf034
3 changed files with 104 additions and 3 deletions

View File

@ -48,6 +48,7 @@ from services.knowledge_fs.product_dto import (
KnowledgeFSDocumentRevisionListResponse,
KnowledgeFSDocumentUploadAcceptedResponse,
KnowledgeFSDurableDeletionAcceptedResponse,
KnowledgeFSEmbeddingSettingsResponse,
KnowledgeFSFindQuery,
KnowledgeFSGoldenQuestionBulkImportPayload,
KnowledgeFSGoldenQuestionBulkImportRemotePayload,
@ -93,6 +94,7 @@ from services.knowledge_fs.product_dto import (
KnowledgeFSResearchTaskPlanResponse,
KnowledgeFSResearchTaskResponse,
KnowledgeFSRetrievalProfileUpdatePayload,
KnowledgeFSRetrievalSettingsResponse,
KnowledgeFSSettingsPayload,
KnowledgeFSSettingsResponse,
KnowledgeFSSettingsUpdateResponse,
@ -561,10 +563,21 @@ class KnowledgeFSDataFacade:
)
else:
raise KnowledgeFSProductRequestRejectedError(status_code=422)
return KnowledgeFSSettingsUpdateResponse(
migration=KnowledgeFSProfileMigrationResponse.model_validate(migration_raw),
settings=current,
if isinstance(migration_raw, dict) and ("runState" in migration_raw or "run_state" in migration_raw):
return KnowledgeFSSettingsUpdateResponse(
migration=KnowledgeFSProfileMigrationResponse.model_validate(migration_raw),
settings=current,
)
if payload.embedding is not None:
KnowledgeFSEmbeddingSettingsResponse.model_validate(migration_raw)
else:
KnowledgeFSRetrievalSettingsResponse.model_validate(migration_raw)
refreshed = self.get_settings(
tenant_id=tenant_id,
account_id=account_id,
control_space_id=control_space_id,
)
return KnowledgeFSSettingsUpdateResponse(settings=refreshed)
raw = self._interactive(
tenant_id=tenant_id,

View File

@ -1287,6 +1287,77 @@ def test_active_settings_use_durable_profile_migration_routes() -> None:
}
def test_active_settings_accept_direct_unpublished_profile_activation() -> None:
class DirectActivationRemote(ActiveSettingsRemote):
def execute_json(self, request: KnowledgeFSRemoteJSONRequest):
if request.operation_id == "updateRetrievalProfile":
self.requests.append(request)
return {
"defaultMode": "fast",
"reasoningModel": {
"model": "reason-v1",
"pluginId": "plugin-1",
"provider": "provider-1",
},
"rerank": {
"enabled": True,
"model": {
"model": "rerank-v1",
"pluginId": "plugin-1",
"provider": "provider-1",
},
},
"revision": 5,
"scoreThreshold": {"enabled": True, "stage": "rerank", "value": 0.51},
"topK": 3,
}
return super().execute_json(request)
remote = DirectActivationRemote()
facade = KnowledgeFSDataFacade(
broker=RecordingBroker(),
remote=remote,
) # type: ignore[arg-type]
result = facade.update_settings(
tenant_id="tenant-1",
account_id="account-1",
control_space_id="control-1",
payload=KnowledgeFSSettingsPayload(
expected_revision=9,
retrieval=KnowledgeFSProductRetrievalProfile(
default_mode="fast",
reasoning_model=KnowledgeFSProfileModelSelection(
model="reason-v1",
plugin_id="plugin-1",
provider="provider-1",
),
rerank=KnowledgeFSProductRerankProfile(
enabled=True,
model=KnowledgeFSProfileModelSelection(
model="rerank-v1",
plugin_id="plugin-1",
provider="provider-1",
),
),
score_threshold=KnowledgeFSProductScoreThreshold(
enabled=True,
stage="rerank",
value=0.51,
),
top_k=3,
),
),
)
assert result.migration is None
assert [request.operation_id for request in remote.requests] == [
"getSettings",
"updateRetrievalProfile",
"getSettings",
]
def test_setup_required_settings_without_active_profile_use_product_settings_route() -> None:
remote = ActiveSettingsRemote(
active_profile_available=False,

View File

@ -0,0 +1,17 @@
# Accept direct unpublished profile activation responses
## Summary
- Accept either an asynchronous profile migration response or a direct profile response from KnowledgeFS profile update operations.
- Validate direct embedding and retrieval profile responses, then reload settings so the console receives the committed revision.
- Add regression coverage for direct unpublished retrieval profile activation.
## Verification
- `uv run --project api pytest api/tests/unit_tests/services/test_knowledge_fs_data_facade.py` (90 passed)
- `uv run --project api ruff check api/services/knowledge_fs/data_facade.py api/tests/unit_tests/services/test_knowledge_fs_data_facade.py`
- `uv run --project api ruff format --check api/services/knowledge_fs/data_facade.py api/tests/unit_tests/services/test_knowledge_fs_data_facade.py`
## Deployment note
Profile activation can synchronously perform model capability preflight. Deployments using the 10-second default `KNOWLEDGE_FS_TIMEOUT_SECONDS` may time out before KnowledgeFS returns; increase the API-side value within its supported 60-second maximum and refresh settings before retrying an ambiguously timed-out mutation.