mirror of
https://github.com/langgenius/dify.git
synced 2026-08-24 12:32:54 -04:00
fix(agent-v2): accept composer UI ids on manual metadata filter conditions (#40171)
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -836,7 +836,12 @@ def _knowledge_metadata_filtering_config(
|
||||
return DifyKnowledgeMetadataFilteringConfig(
|
||||
mode=metadata_filtering.mode,
|
||||
model_config=_knowledge_model_config(metadata_filtering.metadata_model_config),
|
||||
conditions=cast(Any, metadata_filtering.conditions.model_dump(mode="json"))
|
||||
conditions=cast(
|
||||
Any,
|
||||
metadata_filtering.conditions.model_dump(
|
||||
mode="json", exclude={"conditions": {"__all__": {"id", "metadata_id"}}}
|
||||
),
|
||||
)
|
||||
if metadata_filtering.conditions is not None
|
||||
else None,
|
||||
)
|
||||
|
||||
@@ -420,8 +420,19 @@ class AgentKnowledgeRetrievalConfig(BaseModel):
|
||||
|
||||
|
||||
class AgentKnowledgeMetadataCondition(BaseModel):
|
||||
"""One manual metadata filter clause.
|
||||
|
||||
``id`` and ``metadata_id`` are UI-only bookkeeping the composer sends on
|
||||
every save (a stable row key and a reference to the selected metadata
|
||||
field). They are persisted here for round-tripping the composer's draft
|
||||
state but are stripped before building the Agent runtime request, whose
|
||||
DTO only accepts ``name``/``comparison_operator``/``value``.
|
||||
"""
|
||||
|
||||
model_config = ConfigDict(extra="forbid")
|
||||
|
||||
id: str | None = None
|
||||
metadata_id: str | None = None
|
||||
name: str = Field(min_length=1, max_length=255)
|
||||
comparison_operator: SupportedComparisonOperator
|
||||
value: ConditionValue = None
|
||||
|
||||
@@ -14302,9 +14302,19 @@ the current roster/workflow APIs scoped to Dify Agent.
|
||||
|
||||
#### AgentKnowledgeMetadataCondition
|
||||
|
||||
One manual metadata filter clause.
|
||||
|
||||
``id`` and ``metadata_id`` are UI-only bookkeeping the composer sends on
|
||||
every save (a stable row key and a reference to the selected metadata
|
||||
field). They are persisted here for round-tripping the composer's draft
|
||||
state but are stripped before building the Agent runtime request, whose
|
||||
DTO only accepts ``name``/``comparison_operator``/``value``.
|
||||
|
||||
| Name | Type | Description | Required |
|
||||
| ---- | ---- | ----------- | -------- |
|
||||
| comparison_operator | string, <br>**Available values:** "<", "=", ">", "after", "before", "contains", "empty", "end with", "in", "is", "is not", "not contains", "not empty", "not in", "start with", "≠", "≤", "≥" | *Enum:* `"<"`, `"="`, `">"`, `"after"`, `"before"`, `"contains"`, `"empty"`, `"end with"`, `"in"`, `"is"`, `"is not"`, `"not contains"`, `"not empty"`, `"not in"`, `"start with"`, `"≠"`, `"≤"`, `"≥"` | Yes |
|
||||
| id | string | | No |
|
||||
| metadata_id | string | | No |
|
||||
| name | string | | Yes |
|
||||
| value | string<br>[ string ]<br>number | | No |
|
||||
|
||||
|
||||
@@ -744,7 +744,13 @@ def test_build_maps_agent_soul_knowledge_to_knowledge_layer_config():
|
||||
"conditions": {
|
||||
"logical_operator": "and",
|
||||
"conditions": [
|
||||
{"name": "category", "comparison_operator": "contains", "value": "auth"}
|
||||
{
|
||||
"id": "cond-1",
|
||||
"metadata_id": "meta-1",
|
||||
"name": "category",
|
||||
"comparison_operator": "contains",
|
||||
"value": "auth",
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
|
||||
@@ -365,6 +365,51 @@ def test_knowledge_runtime_requirements_block_publish_but_not_draft_save(knowled
|
||||
ComposerConfigValidator.validate_publish_payload(publish_payload)
|
||||
|
||||
|
||||
def test_manual_metadata_filtering_condition_accepts_composer_ui_identifiers():
|
||||
"""The composer's condition editor always sends ``id`` (list row key) and
|
||||
``metadata_id`` (selected metadata field reference) alongside every
|
||||
condition. Rejecting them as unknown fields broke every save of a manual
|
||||
metadata filter (see GH issue #40169)."""
|
||||
payload = ComposerSavePayload.model_validate(
|
||||
{
|
||||
"variant": ComposerVariant.AGENT_APP,
|
||||
"save_strategy": ComposerSaveStrategy.SAVE_TO_CURRENT_VERSION,
|
||||
"agent_soul": {
|
||||
"knowledge": {
|
||||
"sets": [
|
||||
{
|
||||
"id": "support",
|
||||
"name": "Support KB",
|
||||
"datasets": [{"id": "dataset-1"}],
|
||||
"query": {"mode": "generated_query"},
|
||||
"retrieval": {"mode": "multiple", "top_k": 4},
|
||||
"metadata_filtering": {
|
||||
"mode": "manual",
|
||||
"conditions": {
|
||||
"logical_operator": "and",
|
||||
"conditions": [
|
||||
{
|
||||
"id": "b149eceb-191a-40a2-9f11-61cf21ebd147",
|
||||
"metadata_id": "ad6cf326-eadf-46e8-a2d5-9cb892d2cc84",
|
||||
"name": "category",
|
||||
"comparison_operator": "is",
|
||||
"value": "auth",
|
||||
}
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
}
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
condition = payload.agent_soul.knowledge.sets[0].metadata_filtering.conditions.conditions[0]
|
||||
assert condition.id == "b149eceb-191a-40a2-9f11-61cf21ebd147"
|
||||
assert condition.metadata_id == "ad6cf326-eadf-46e8-a2d5-9cb892d2cc84"
|
||||
|
||||
|
||||
def test_agent_soul_model_config_is_first_class_without_credentials():
|
||||
config = AgentSoulConfig(
|
||||
model=AgentSoulModelConfig(
|
||||
|
||||
@@ -1882,6 +1882,8 @@ export type AgentKnowledgeMetadataCondition = {
|
||||
| '≠'
|
||||
| '≤'
|
||||
| '≥'
|
||||
id?: string | null
|
||||
metadata_id?: string | null
|
||||
name: string
|
||||
value?: string | Array<string> | number | null
|
||||
}
|
||||
|
||||
@@ -2357,6 +2357,14 @@ export const zAgentKnowledgeRetrievalConfig = z.object({
|
||||
|
||||
/**
|
||||
* AgentKnowledgeMetadataCondition
|
||||
*
|
||||
* One manual metadata filter clause.
|
||||
*
|
||||
* ``id`` and ``metadata_id`` are UI-only bookkeeping the composer sends on
|
||||
* every save (a stable row key and a reference to the selected metadata
|
||||
* field). They are persisted here for round-tripping the composer's draft
|
||||
* state but are stripped before building the Agent runtime request, whose
|
||||
* DTO only accepts ``name``/``comparison_operator``/``value``.
|
||||
*/
|
||||
export const zAgentKnowledgeMetadataCondition = z.object({
|
||||
comparison_operator: z.enum([
|
||||
@@ -2379,6 +2387,8 @@ export const zAgentKnowledgeMetadataCondition = z.object({
|
||||
'≤',
|
||||
'≥',
|
||||
]),
|
||||
id: z.string().nullish(),
|
||||
metadata_id: z.string().nullish(),
|
||||
name: z.string().min(1).max(255),
|
||||
value: z.union([z.string(), z.array(z.string()), z.number()]).nullish(),
|
||||
})
|
||||
|
||||
@@ -3097,6 +3097,8 @@ export type AgentKnowledgeMetadataCondition = {
|
||||
| '≠'
|
||||
| '≤'
|
||||
| '≥'
|
||||
id?: string | null
|
||||
metadata_id?: string | null
|
||||
name: string
|
||||
value?: string | Array<string> | number | null
|
||||
}
|
||||
|
||||
@@ -4048,6 +4048,14 @@ export const zMessageInfiniteScrollPaginationResponse = z.object({
|
||||
|
||||
/**
|
||||
* AgentKnowledgeMetadataCondition
|
||||
*
|
||||
* One manual metadata filter clause.
|
||||
*
|
||||
* ``id`` and ``metadata_id`` are UI-only bookkeeping the composer sends on
|
||||
* every save (a stable row key and a reference to the selected metadata
|
||||
* field). They are persisted here for round-tripping the composer's draft
|
||||
* state but are stripped before building the Agent runtime request, whose
|
||||
* DTO only accepts ``name``/``comparison_operator``/``value``.
|
||||
*/
|
||||
export const zAgentKnowledgeMetadataCondition = z.object({
|
||||
comparison_operator: z.enum([
|
||||
@@ -4070,6 +4078,8 @@ export const zAgentKnowledgeMetadataCondition = z.object({
|
||||
'≤',
|
||||
'≥',
|
||||
]),
|
||||
id: z.string().nullish(),
|
||||
metadata_id: z.string().nullish(),
|
||||
name: z.string().min(1).max(255),
|
||||
value: z.union([z.string(), z.array(z.string()), z.number()]).nullish(),
|
||||
})
|
||||
|
||||
@@ -1130,6 +1130,8 @@ export type AgentKnowledgeMetadataCondition = {
|
||||
| '≠'
|
||||
| '≤'
|
||||
| '≥'
|
||||
id?: string | null
|
||||
metadata_id?: string | null
|
||||
name: string
|
||||
value?: string | Array<string> | number | null
|
||||
}
|
||||
|
||||
@@ -1439,6 +1439,14 @@ export const zAgentKnowledgeRetrievalConfig = z.object({
|
||||
|
||||
/**
|
||||
* AgentKnowledgeMetadataCondition
|
||||
*
|
||||
* One manual metadata filter clause.
|
||||
*
|
||||
* ``id`` and ``metadata_id`` are UI-only bookkeeping the composer sends on
|
||||
* every save (a stable row key and a reference to the selected metadata
|
||||
* field). They are persisted here for round-tripping the composer's draft
|
||||
* state but are stripped before building the Agent runtime request, whose
|
||||
* DTO only accepts ``name``/``comparison_operator``/``value``.
|
||||
*/
|
||||
export const zAgentKnowledgeMetadataCondition = z.object({
|
||||
comparison_operator: z.enum([
|
||||
@@ -1461,6 +1469,8 @@ export const zAgentKnowledgeMetadataCondition = z.object({
|
||||
'≤',
|
||||
'≥',
|
||||
]),
|
||||
id: z.string().nullish(),
|
||||
metadata_id: z.string().nullish(),
|
||||
name: z.string().min(1).max(255),
|
||||
value: z.union([z.string(), z.array(z.string()), z.number()]).nullish(),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user