feat: 任务间互发消息(API + agent 标记块,不中断任务)
同项目任务互发消息、对方做完可回消息:API POST /tasks/<目标>/messages (from_task_id,目标项目 create_task + 发送项目 read 鉴权)与 agent 回合输出标记块(worker 回合后解析投递,不用联网、不用凭证,本地 与 Docker 都通)。投递不中断任务:对方运行中/排队中排成后续消息 (轮次边界执行,direct 优先);对方终态则续跑复活(resume_message + queued),A→B→A 往返不受回合时序影响。拒绝项:自己、跨项目、goal 目标、已合并、复活位被占;每轮最多 5 块,仅 completed 轮次投递; 目标执行时配额门照常生效。控制台后续消息列显示发送方,新增给 其他任务发消息框(落已代理的 /tasks 下,不用改 nginx)。 测试:新增 test_peer_messages(15)、test_peer_messages_server(8)、 test_worker_peer(4);全量 cloud 654、host 64、deploy 19 全过(cloud 4 跳过)。
This commit is contained in:
1 parent
4901a1090b
commit
ef30558f7c
11 files changed
+1171
-23
No files matched your search
+42
-1
@@ -263,6 +263,17 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="followupList" class="muted"></div>
|
||||
<h3>给其他任务发消息</h3>
|
||||
<div id="peerMessageForm">
|
||||
<input id="peerTarget" placeholder="目标任务 id(与本任务同项目;对方运行中排队执行、已终态则续跑复活,绝不打断当前轮)" style="width:100%">
|
||||
<textarea id="peerBody" placeholder="消息正文(以本任务名义发出;对方 agent 会看到发送方任务 id,可照此回消息)"></textarea>
|
||||
<div class="bar">
|
||||
<button id="btnQueuePeerMessage">排队发给对方</button>
|
||||
<button id="btnDirectPeerMessage" class="primary">直接发送</button>
|
||||
<span id="peerMsg" class="muted"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div id="peerMessageList" class="muted"></div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
@@ -666,6 +677,8 @@ async function showDetail(taskId) {
|
||||
$("#agentBox").innerHTML = "子代理链路加载中…";
|
||||
loadAgents(taskId);
|
||||
loadFollowups(taskId);
|
||||
loadPeerMessages(taskId);
|
||||
$("#peerMsg").textContent = "";
|
||||
} catch (e) { $("#detail").innerHTML = "<span class='err'>加载失败:" + esc(e.message) + "</span>"; }
|
||||
}
|
||||
|
||||
@@ -688,7 +701,8 @@ async function loadFollowups(taskId) {
|
||||
var list = d.followups || [];
|
||||
if (!list.length) { box.innerHTML = "(暂无后续消息)"; return; }
|
||||
box.innerHTML = list.map(function (f) {
|
||||
return "[" + esc(f.mode) + "|" + esc(f.status) + "] " + esc(String(f.body || "").slice(0, 120));
|
||||
var from = f.sender_task_id ? "来自任务 " + esc(String(f.sender_task_id).slice(0, 8)) + "|" : "";
|
||||
return "[" + esc(f.mode) + "|" + esc(f.status) + "] " + from + esc(String(f.body || "").slice(0, 120));
|
||||
}).join("<br>");
|
||||
} catch (e) { box.innerHTML = "<span class='err'>后续消息加载失败:" + esc(e.message) + "</span>"; }
|
||||
}
|
||||
@@ -899,8 +913,35 @@ $("#btnContinueConfirm").onclick = async function () {
|
||||
loadTasks();
|
||||
} catch (e) { $("#continueMsgSpan").innerHTML = "<span class='err'>继续失败:" + esc(e.message) + "</span>"; }
|
||||
};
|
||||
async function loadPeerMessages(taskId) {
|
||||
var box = $("#peerMessageList");
|
||||
try {
|
||||
var d = await api("/tasks/" + encodeURIComponent(taskId) + "/messages", "GET");
|
||||
var list = d.messages || [];
|
||||
if (!list.length) { box.innerHTML = "(本任务尚未发出任务间消息)"; return; }
|
||||
box.innerHTML = list.map(function (f) {
|
||||
return "[发给 " + esc(String(f.task_id).slice(0, 8)) + "|" + esc(f.mode) + "|" + esc(f.status) + "] " + esc(String(f.body || "").slice(0, 120));
|
||||
}).join("<br>");
|
||||
} catch (e) { box.innerHTML = "<span class='err'>发出消息加载失败:" + esc(e.message) + "</span>"; }
|
||||
}
|
||||
async function postPeerMessage(mode) {
|
||||
if (!currentTask) return;
|
||||
var target = $("#peerTarget").value.trim();
|
||||
var text = $("#peerBody").value.trim();
|
||||
if (!target) { $("#peerMsg").textContent = "目标任务 id 不能为空"; return; }
|
||||
if (!text) { $("#peerMsg").textContent = "消息正文不能为空"; return; }
|
||||
try {
|
||||
var d = await api("/tasks/" + encodeURIComponent(target) + "/messages", "POST", { from_task_id: currentTask.id, body: text, mode: mode });
|
||||
$("#peerMsg").innerHTML = "<span class='ok'>已发送(" + esc(d.delivery) + ")</span>";
|
||||
$("#peerBody").value = "";
|
||||
loadPeerMessages(currentTask.id);
|
||||
} catch (e) { $("#peerMsg").innerHTML = "<span class='err'>发送失败:" + esc(e.message) + "</span>"; }
|
||||
}
|
||||
|
||||
$("#btnQueueFollowup").onclick = function () { postFollowup("queued"); };
|
||||
$("#btnDirectFollowup").onclick = function () { postFollowup("direct"); };
|
||||
$("#btnQueuePeerMessage").onclick = function () { postPeerMessage("queued"); };
|
||||
$("#btnDirectPeerMessage").onclick = function () { postPeerMessage("direct"); };
|
||||
$("#btnCost").onclick = async function () {
|
||||
if (!currentTask) return;
|
||||
try {
|
||||
|
||||
Reference in new issue
Block a user