feat: per-task model/effort/approval + relay models endpoint (#59)

Co-authored-by: host <host@test.local>
This commit is contained in:
openqjandhost authored and GitHub committed 2026-10-27 01:44:53 +08:00
1 parent cff152c5a2
commit 8b2f3968dc
9 files changed
+521 -16

No files matched your search

+49
View File
@@ -86,6 +86,26 @@
<label><input id="goalMode" type="checkbox"> goal 模式</label>
</div>
<textarea id="prompt" placeholder="任务 prompt(必填)"></textarea>
<div class="bar">
<select id="modelSelect">
<option value="">模型:默认(跟随配置)</option>
</select>
<input id="modelCustom" type="text" placeholder="手动输入模型(中转列表取不到时用)" style="display:none">
<select id="effortSelect">
<option value="">推理强度:默认(跟随配置)</option>
<option value="low">low</option>
<option value="medium">medium</option>
<option value="high">high</option>
<option value="xhigh">xhigh</option>
<option value="max">max</option>
</select>
<select id="approvalSelect">
<option value="">权限:默认(跟随配置)</option>
<option value="ask">请求批准</option>
<option value="auto">帮我批准</option>
<option value="full">完全访问</option>
</select>
</div>
<div id="goalFields" style="display:none">
<input id="goal" type="text" placeholder="goal(缺省用 prompt)" style="width:100%; box-sizing:border-box; margin:6px 0;">
<input id="verifyCommand" type="text" placeholder="verify_command 验收命令(goal 模式必填项按服务端规则)" style="width:100%; box-sizing:border-box; margin:6px 0;">
@@ -157,6 +177,23 @@ async function api(path, method, body) {
return data;
}
async function loadRelayModels() {
// 中转模型下拉:服务端现取现回,只含模型 id。取不到时不挡
// 提交,留手动输入框给用户填。
var sel = $("#modelSelect");
try {
var d = await api("/relay/models", "GET");
var models = d.models || [];
sel.innerHTML = "<option value=''>模型:默认(跟随配置)</option>" +
models.map(function (m) {
return "<option value='" + esc(m) + "'>" + esc(m) + "</option>";
}).join("");
$("#modelCustom").style.display = "none";
} catch (e) {
$("#modelCustom").style.display = "inline";
}
}
async function loadHealth() {
try {
var h = await api("/health", "GET");
@@ -229,6 +266,8 @@ async function showDetail(taskId) {
$("#detail").innerHTML =
"状态 <b class='st-" + esc(t.status) + "'>" + esc(t.status) + "</b> | " +
"executor " + esc(t.executor || "") + " | 主机 " + esc(t.worktree_host || "") +
" | 模型 " + esc(t.model || "默认") + " | 强度 " + esc(t.effort || "默认") +
" | 权限 " + esc(t.approval || "默认") +
(t.pr_url ? " | <a href='" + esc(t.pr_url) + "' target='_blank' rel='noopener'>PR #" + esc(t.pr_number) + "</a>" : "") +
"<br>prompt:<br>" + esc(t.prompt || "");
var body = "";
@@ -268,6 +307,7 @@ $("#saveKey").onclick = function () {
loadProjects();
loadWorkers();
if ($("#projectSelect").value) loadTasks();
if (getKey()) loadRelayModels();
};
$("#clearKey").onclick = function () { localStorage.removeItem(KEY_STORE); setKeyState(); };
$("#refreshHealth").onclick = loadHealth;
@@ -297,6 +337,15 @@ $("#createTask").onclick = async function () {
var body = { project_id: pid, prompt: prompt };
var ex = $("#executor").value;
if (ex) body.executor = ex;
var model = $("#modelCustom").value.trim() || $("#modelSelect").value;
if (model) body.model = model;
var eff = $("#effortSelect").value;
if (eff) body.effort = eff;
var ap = $("#approvalSelect").value;
if (ap) {
if (ap === "full" && !confirm("完全访问 = 自动批准 + 不受工作区限制,agent 可读写工作区外路径。确认提交吗?")) return;
body.approval = ap;
}
if ($("#goalMode").checked) {
body.goal = $("#goal").value.trim() || prompt;
body.verify_command = $("#verifyCommand").value.trim();