mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 01:10:23 +08:00
Fix endpoint condition source handling
This commit is contained in:
@@ -586,10 +586,10 @@ fn evaluate_local_condition(
|
|||||||
let current_value = if condition_source_is_headers(source) {
|
let current_value = if condition_source_is_headers(source) {
|
||||||
request_headers.and_then(|headers| get_header_condition_value(headers, path))
|
request_headers.and_then(|headers| get_header_condition_value(headers, path))
|
||||||
} else {
|
} else {
|
||||||
let target = if source.eq_ignore_ascii_case("current") {
|
let target = if source.eq_ignore_ascii_case("original") {
|
||||||
body
|
|
||||||
} else {
|
|
||||||
original_body.unwrap_or(body)
|
original_body.unwrap_or(body)
|
||||||
|
} else {
|
||||||
|
body
|
||||||
};
|
};
|
||||||
parse_body_path(path).and_then(|path| get_nested_value(target, &path))
|
parse_body_path(path).and_then(|path| get_nested_value(target, &path))
|
||||||
};
|
};
|
||||||
@@ -1552,7 +1552,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn body_conditions_default_to_original_request_body() {
|
fn body_conditions_default_to_current_request_body() {
|
||||||
let rules = serde_json::json!([
|
let rules = serde_json::json!([
|
||||||
{"action":"set","path":"model","value":"provider-model"},
|
{"action":"set","path":"model","value":"provider-model"},
|
||||||
{"action":"set","path":"metadata.original_hit","value":true,"condition":{"path":"model","op":"eq","value":"client-model"}},
|
{"action":"set","path":"metadata.original_hit","value":true,"condition":{"path":"model","op":"eq","value":"client-model"}},
|
||||||
@@ -1570,8 +1570,36 @@ mod tests {
|
|||||||
));
|
));
|
||||||
|
|
||||||
assert_eq!(body["model"], "provider-model");
|
assert_eq!(body["model"], "provider-model");
|
||||||
assert_eq!(body["metadata"]["original_hit"], true);
|
assert!(body["metadata"].get("original_hit").is_none());
|
||||||
assert!(body["metadata"].get("current_hit").is_none());
|
assert_eq!(body["metadata"]["current_hit"], true);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn body_conditions_default_to_current_request_body_for_wildcard_drop() {
|
||||||
|
let rules = serde_json::json!([
|
||||||
|
{
|
||||||
|
"action": "drop",
|
||||||
|
"path": "tools[*]",
|
||||||
|
"condition": {"path": "$item.name", "op": "eq", "value": "Agent"}
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
let original = serde_json::json!({
|
||||||
|
"model": "client-model"
|
||||||
|
});
|
||||||
|
let mut body = serde_json::json!({
|
||||||
|
"tools": [
|
||||||
|
{"name": "Agent"},
|
||||||
|
{"name": "Bash"}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
assert!(apply_local_body_rules(
|
||||||
|
&mut body,
|
||||||
|
Some(&rules),
|
||||||
|
Some(&original)
|
||||||
|
));
|
||||||
|
|
||||||
|
assert_eq!(body["tools"], serde_json::json!([{"name": "Bash"}]));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ export interface BodyRuleConditionLeaf {
|
|||||||
path: string
|
path: string
|
||||||
op: BodyRuleConditionOp
|
op: BodyRuleConditionOp
|
||||||
value?: unknown // exists / not_exists 不需要 value
|
value?: unknown // exists / not_exists 不需要 value
|
||||||
source?: 'request_headers' // 不填表示请求体;填 request_headers 表示请求头
|
source?: 'body' | 'current' | 'original' | 'request_headers' | 'headers'
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface BodyRuleConditionAll {
|
export interface BodyRuleConditionAll {
|
||||||
|
|||||||
@@ -130,6 +130,9 @@
|
|||||||
<SelectItem value="body">
|
<SelectItem value="body">
|
||||||
请求体
|
请求体
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
<SelectItem value="original">
|
||||||
|
原始请求体
|
||||||
|
</SelectItem>
|
||||||
<SelectItem value="request_headers">
|
<SelectItem value="request_headers">
|
||||||
请求头
|
请求头
|
||||||
</SelectItem>
|
</SelectItem>
|
||||||
|
|||||||
@@ -1459,6 +1459,7 @@ const RESERVED_BODY_FIELDS = new Set([
|
|||||||
|
|
||||||
const BODY_RULE_JSON_ACTIONS = new Set(['set', 'drop', 'rename', 'append', 'insert', 'regex_replace'])
|
const BODY_RULE_JSON_ACTIONS = new Set(['set', 'drop', 'rename', 'append', 'insert', 'regex_replace'])
|
||||||
const CONDITION_JSON_OPS = new Set(['eq', 'neq', 'gt', 'lt', 'gte', 'lte', 'starts_with', 'ends_with', 'contains', 'matches', 'exists', 'not_exists', 'in', 'type_is'])
|
const CONDITION_JSON_OPS = new Set(['eq', 'neq', 'gt', 'lt', 'gte', 'lte', 'starts_with', 'ends_with', 'contains', 'matches', 'exists', 'not_exists', 'in', 'type_is'])
|
||||||
|
const CONDITION_JSON_SOURCES = new Set(['body', 'current', 'original', 'request_headers', 'headers'])
|
||||||
|
|
||||||
function isJsonObject(value: unknown): value is Record<string, unknown> {
|
function isJsonObject(value: unknown): value is Record<string, unknown> {
|
||||||
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
return value !== null && typeof value === 'object' && !Array.isArray(value)
|
||||||
@@ -1508,8 +1509,8 @@ function validateJsonConditionShape(condition: Record<string, unknown>, label: s
|
|||||||
if (typeof condition.op !== 'string' || !CONDITION_JSON_OPS.has(condition.op)) {
|
if (typeof condition.op !== 'string' || !CONDITION_JSON_OPS.has(condition.op)) {
|
||||||
return `${label}.op 无效`
|
return `${label}.op 无效`
|
||||||
}
|
}
|
||||||
if (condition.source !== undefined && condition.source !== 'request_headers') {
|
if (condition.source !== undefined && (typeof condition.source !== 'string' || !CONDITION_JSON_SOURCES.has(condition.source))) {
|
||||||
return `${label}.source 只能是 request_headers;请求体条件不要填写 source`
|
return `${label}.source 无效`
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import type { BodyRuleCondition, BodyRuleConditionOp } from '@/api/endpoints'
|
import type { BodyRuleCondition, BodyRuleConditionOp } from '@/api/endpoints'
|
||||||
|
|
||||||
export type ConditionSource = 'body' | 'request_headers'
|
export type ConditionSource = 'body' | 'original' | 'request_headers'
|
||||||
export type ConditionGroupMode = 'all' | 'any'
|
export type ConditionGroupMode = 'all' | 'any'
|
||||||
|
|
||||||
export interface EditableConditionLeaf {
|
export interface EditableConditionLeaf {
|
||||||
@@ -96,6 +96,8 @@ export function conditionToEditable(condition?: BodyRuleCondition | null): Edita
|
|||||||
: '',
|
: '',
|
||||||
source: source === 'request_headers' || source === 'headers'
|
source: source === 'request_headers' || source === 'headers'
|
||||||
? 'request_headers'
|
? 'request_headers'
|
||||||
|
: source === 'original'
|
||||||
|
? 'original'
|
||||||
: 'body',
|
: 'body',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,7 +119,11 @@ export function editableConditionToApi(node: EditableConditionNode | null): Body
|
|||||||
const base = {
|
const base = {
|
||||||
path,
|
path,
|
||||||
op: node.op,
|
op: node.op,
|
||||||
...(node.source === 'request_headers' ? { source: 'request_headers' as const } : {}),
|
...(node.source === 'request_headers'
|
||||||
|
? { source: 'request_headers' as const }
|
||||||
|
: node.source === 'original'
|
||||||
|
? { source: 'original' as const }
|
||||||
|
: {}),
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.op === 'exists' || node.op === 'not_exists') {
|
if (node.op === 'exists' || node.op === 'not_exists') {
|
||||||
|
|||||||
Reference in New Issue
Block a user