fix: bad model field ref

This commit is contained in:
Junyan Qin
2026-03-13 11:47:31 +08:00
parent 6e77351eda
commit 10c716be0c
5 changed files with 74 additions and 15 deletions

View File

@@ -105,9 +105,14 @@ class LLMModelsService:
)
)
pipeline = result.first()
if pipeline is not None and pipeline.config['ai']['local-agent']['model'] == '':
if pipeline is not None:
model_config = pipeline.config.get('ai', {}).get('local-agent', {}).get('model', {})
if not model_config.get('primary', ''):
pipeline_config = pipeline.config
pipeline_config['ai']['local-agent']['model'] = model_data['uuid']
pipeline_config['ai']['local-agent']['model'] = {
'primary': model_data['uuid'],
'fallbacks': [],
}
pipeline_data = {'config': pipeline_config}
await self.ap.pipeline_service.update_pipeline(pipeline.uuid, pipeline_data)

View File

@@ -41,7 +41,10 @@
"runner": "local-agent"
},
"local-agent": {
"model": "",
"model": {
"primary": "",
"fallbacks": []
},
"max-round": 10,
"prompt": [
{

View File

@@ -194,7 +194,7 @@ def sample_query(sample_message_chain, sample_message_event, mock_adapter):
pipeline_config={
'ai': {
'runner': {'runner': 'local-agent'},
'local-agent': {'model': 'test-model-uuid', 'prompt': 'test-prompt'},
'local-agent': {'model': {'primary': 'test-model-uuid', 'fallbacks': []}, 'prompt': 'test-prompt'},
},
'output': {'misc': {'at-sender': False, 'quote-origin': False}},
'trigger': {'misc': {'combine-quote-message': False}},
@@ -219,7 +219,7 @@ def sample_pipeline_config():
return {
'ai': {
'runner': {'runner': 'local-agent'},
'local-agent': {'model': 'test-model-uuid', 'prompt': 'test-prompt'},
'local-agent': {'model': {'primary': 'test-model-uuid', 'fallbacks': []}, 'prompt': 'test-prompt'},
},
'output': {'misc': {'at-sender': False, 'quote-origin': False}},
'trigger': {'misc': {'combine-quote-message': False}},

View File

@@ -34,6 +34,35 @@ export default function DynamicFormComponent({
const previousInitialValues = useRef(initialValues);
const { t } = useTranslation();
// Normalize a form value according to its field type.
// This ensures legacy/malformed data (e.g. a plain string for
// model-fallback-selector) is coerced to the expected shape
// so that downstream components never crash.
const normalizeFieldValue = (
item: IDynamicFormItemSchema,
value: unknown,
): unknown => {
if (item.type === 'model-fallback-selector') {
if (value != null && typeof value === 'object' && !Array.isArray(value)) {
const obj = value as Record<string, unknown>;
return {
primary: typeof obj.primary === 'string' ? obj.primary : '',
fallbacks: Array.isArray(obj.fallbacks)
? (obj.fallbacks as unknown[]).filter(
(v): v is string => typeof v === 'string',
)
: [],
};
}
// Legacy string format or any other unexpected type
return {
primary: typeof value === 'string' ? value : '',
fallbacks: [],
};
}
return value;
};
// 根据 itemConfigList 动态生成 zod schema
const formSchema = z.object(
itemConfigList.reduce(
@@ -116,10 +145,10 @@ export default function DynamicFormComponent({
resolver: zodResolver(formSchema),
defaultValues: itemConfigList.reduce((acc, item) => {
// 优先使用 initialValues如果没有则使用默认值
const value = initialValues?.[item.name] ?? item.default;
const rawValue = initialValues?.[item.name] ?? item.default;
return {
...acc,
[item.name]: value,
[item.name]: normalizeFieldValue(item, rawValue),
};
}, {} as FormValues),
});
@@ -144,7 +173,8 @@ export default function DynamicFormComponent({
// 合并默认值和初始值
const mergedValues = itemConfigList.reduce(
(acc, item) => {
acc[item.name] = initialValues[item.name] ?? item.default;
const rawValue = initialValues[item.name] ?? item.default;
acc[item.name] = normalizeFieldValue(item, rawValue) as object;
return acc;
},
{} as Record<string, object>,

View File

@@ -348,9 +348,30 @@ export default function DynamicFormItemComponent({
{} as Record<string, LLMModel[]>,
);
const modelValue = field.value as {
primary: string;
fallbacks: string[];
const rawModelValue = field.value;
const modelValue: { primary: string; fallbacks: string[] } =
rawModelValue != null &&
typeof rawModelValue === 'object' &&
!Array.isArray(rawModelValue)
? {
primary:
typeof (rawModelValue as Record<string, unknown>).primary ===
'string'
? ((rawModelValue as Record<string, unknown>)
.primary as string)
: '',
fallbacks: Array.isArray(
(rawModelValue as Record<string, unknown>).fallbacks,
)
? (
(rawModelValue as Record<string, unknown>)
.fallbacks as unknown[]
).filter((v): v is string => typeof v === 'string')
: [],
}
: {
primary: typeof rawModelValue === 'string' ? rawModelValue : '',
fallbacks: [],
};
const renderModelSelect = (