mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 03:13:41 +08:00
feat(agent): re-enable per-Agent model override
This commit is contained in:
parent
b0f5dadbe6
commit
92bd8e9b6e
@ -155,9 +155,13 @@ public class AgentGraphBuilder {
|
||||
// the agent's bound-skill requires-model. Falls back to the
|
||||
// global default when no preferred provider satisfies, so the
|
||||
// existing "no default model" error path stays intact.
|
||||
// RFC-03 Lane G1 — honor per-Agent model override when set.
|
||||
// resolveModel() looks up entity.modelName in enabled-only models;
|
||||
// null / blank / unmatched silently fall back to getDefaultModel(),
|
||||
// preserving the legacy behavior for Agents without an override.
|
||||
ModelConfigEntity globalDefault;
|
||||
try {
|
||||
globalDefault = modelConfigService.getDefaultModel();
|
||||
globalDefault = modelConfigService.resolveModel(entity.getModelName());
|
||||
} catch (Exception e) {
|
||||
throw new MateClawException("err.agent.no_default_model", "无法构建 Agent:请先在「设置 → 模型」中配置并启用默认模型");
|
||||
}
|
||||
|
||||
@ -31,10 +31,22 @@ public class AgentEntity {
|
||||
private String systemPrompt;
|
||||
|
||||
/**
|
||||
* 保留但不再生效:运行时统一使用全局默认模型(ModelConfigService.getDefaultModel())。
|
||||
* 该字段为历史残留,仅保留以避免数据库迁移。
|
||||
* Per-Agent model override.
|
||||
*
|
||||
* <p>When non-blank, the runtime resolves this value via
|
||||
* {@code ModelConfigService.resolveModel(...)} — a case-sensitive,
|
||||
* enabled-only lookup against {@code mate_model_config.model_name}.
|
||||
* On match, the resolved entity is used as the primary model in
|
||||
* place of {@code getDefaultModel()}.
|
||||
*
|
||||
* <p>Null / blank → fall back to the global default (preserves the
|
||||
* original behavior). Stale rows whose named model has been removed
|
||||
* or disabled also fall back, since {@code resolveModel} returns the
|
||||
* default when no enabled match is found.
|
||||
*
|
||||
* <p>RFC-03 Lane G1 — re-enables this field after it was silently
|
||||
* deprecated in earlier work; the database column is unchanged.
|
||||
*/
|
||||
@Deprecated
|
||||
private String modelName;
|
||||
|
||||
/** 最大迭代次数 */
|
||||
|
||||
@ -233,6 +233,7 @@ err.llm.pkce_failed=PKCE \u751f\u6210\u5931\u8d25
|
||||
err.llm.chatgpt_stream_failed=ChatGPT \u6d41\u5f0f\u8c03\u7528\u5931\u8d25
|
||||
err.llm.chatgpt_error=ChatGPT \u8fd4\u56de\u9519\u8bef
|
||||
err.llm.chatgpt_account_missing=chatgpt-account-id \u7f3a\u5931
|
||||
err.llm.model_not_supported=\u6a21\u578b ID \u4e0d\u652f\u6301\u5728 DashScope \u539f\u751f\u534f\u8bae\u4e2d\u4f7f\u7528\u3002\u70b9\u7248\u672c\u683c\u5f0f\u7684\u7cfb\u5217\uff08\u4f8b\u5982 qwen3.5-*\u3001qwen3.6-*\uff09\u53ea\u80fd\u901a\u8fc7\u517c\u5bb9\u6a21\u5f0f\u4f7f\u7528\u3002\u8bf7\u4f7f\u7528\u5141\u8bb8\u7684 ID\uff0c\u5982 qwen-max / qwen-plus / qwen3-max\u3002
|
||||
# datasource
|
||||
err.datasource.not_found=\u6570\u636e\u6e90\u4e0d\u5b58\u5728
|
||||
err.datasource.sql_empty=SQL \u4e0d\u80fd\u4e3a\u7a7a
|
||||
|
||||
@ -773,6 +773,9 @@ export default {
|
||||
systemPrompt: 'System Prompt',
|
||||
maxIterations: 'Max Iterations',
|
||||
defaultThinkingLevel: 'Default Thinking Level',
|
||||
modelName: 'Model',
|
||||
modelGlobalDefault: 'Use global default',
|
||||
modelHint: 'Override the global default model for this Agent. Leave blank to follow Settings → Models.',
|
||||
tags: 'Tags',
|
||||
enabled: 'Enabled',
|
||||
},
|
||||
|
||||
@ -775,6 +775,9 @@ export default {
|
||||
systemPrompt: '系统提示词',
|
||||
maxIterations: '最大迭代次数',
|
||||
defaultThinkingLevel: '默认思考深度',
|
||||
modelName: '模型',
|
||||
modelGlobalDefault: '使用全局默认模型',
|
||||
modelHint: '为此 Agent 单独指定模型,留空则跟随「设置 → 模型」中的全局默认。',
|
||||
tags: '标签',
|
||||
enabled: '启用',
|
||||
},
|
||||
|
||||
@ -204,6 +204,18 @@
|
||||
<label class="form-label">{{ t('agents.fields.maxIterations') }}</label>
|
||||
<input v-model.number="form.maxIterations" type="number" min="1" max="50" class="form-input" />
|
||||
</div>
|
||||
<!-- RFC-03 Lane G1: per-Agent model override. Empty value falls
|
||||
back to the global default in ModelConfigService.resolveModel. -->
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ t('agents.fields.modelName') }}</label>
|
||||
<select v-model="form.modelName" class="form-input">
|
||||
<option value="">{{ t('agents.fields.modelGlobalDefault') }}</option>
|
||||
<option v-for="m in availableModels" :key="m.id" :value="m.modelName">
|
||||
{{ m.name }} ({{ m.provider }}/{{ m.modelName }})
|
||||
</option>
|
||||
</select>
|
||||
<p class="form-hint">{{ t('agents.fields.modelHint') }}</p>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="form-label">{{ t('agents.fields.defaultThinkingLevel') }}</label>
|
||||
<select v-model="form.defaultThinkingLevel" class="form-input">
|
||||
@ -368,6 +380,9 @@ const selectedToolNames = ref<string[]>([])
|
||||
// RFC-009 PR-3: per-agent provider preference order
|
||||
const availableProviders = ref<{ id: string; name: string }[]>([])
|
||||
const selectedProviderIds = ref<string[]>([])
|
||||
// RFC-03 Lane G1: per-Agent model override picker — populated from the
|
||||
// global enabled-models list, blank value means "fall back to default".
|
||||
const availableModels = ref<Array<{ id: number; name: string; provider: string; modelName: string }>>([])
|
||||
|
||||
// Template selector state
|
||||
const showTemplateSelector = ref(false)
|
||||
@ -387,6 +402,7 @@ const defaultForm = (): Partial<Agent> & { name: string; defaultThinkingLevel: s
|
||||
description: '',
|
||||
agentType: 'react',
|
||||
systemPrompt: '',
|
||||
modelName: '', // RFC-03 G1 — empty means "use global default"
|
||||
maxIterations: 10,
|
||||
// Empty so SkillIcon's fallback (🤖) shows instead of pinning a literal
|
||||
// emoji into form.icon — otherwise the picker thinks the user picked
|
||||
@ -419,6 +435,9 @@ const filteredAgents = computed(() => {
|
||||
|
||||
onMounted(() => {
|
||||
loadAgents()
|
||||
// RFC-03 G1: load models once for the per-Agent override dropdown.
|
||||
// Failure is non-fatal — the dropdown just shows only "global default".
|
||||
loadAvailableModels()
|
||||
})
|
||||
|
||||
async function loadAgents() {
|
||||
@ -430,6 +449,20 @@ async function loadAgents() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadAvailableModels() {
|
||||
try {
|
||||
const res: any = await modelApi.listEnabled()
|
||||
availableModels.value = (res.data || []).map((m: any) => ({
|
||||
id: m.id,
|
||||
name: m.name,
|
||||
provider: m.provider,
|
||||
modelName: m.modelName,
|
||||
}))
|
||||
} catch {
|
||||
// Silent — the picker still works (empty list = only "default" option).
|
||||
}
|
||||
}
|
||||
|
||||
function parseTags(tags: string): string[] {
|
||||
return tags.split(',').map(s => s.trim()).filter(Boolean)
|
||||
}
|
||||
@ -515,6 +548,7 @@ async function openEditModal(agent: Agent) {
|
||||
description: agent.description || '',
|
||||
agentType: agent.agentType,
|
||||
systemPrompt: agent.systemPrompt || '',
|
||||
modelName: agent.modelName || '',
|
||||
maxIterations: agent.maxIterations,
|
||||
icon: agent.icon || '',
|
||||
tags: agent.tags || '',
|
||||
|
||||
Loading…
Reference in New Issue
Block a user