fix: persist master-agent wait state in chat
This commit is contained in:
@@ -331,6 +331,7 @@ npm run aab:release
|
|||||||
- 当前本机 Codex 节点 `mac-studio` 已绑定到 `17600003315`
|
- 当前本机 Codex 节点 `mac-studio` 已绑定到 `17600003315`
|
||||||
- 主 Agent 对话当前真实执行链路是:`Boss Web -> 写入用户消息 -> 返回 queued/running -> master-agent task queue -> local-agent / OpenAI API -> complete task -> project ledger`
|
- 主 Agent 对话当前真实执行链路是:`Boss Web -> 写入用户消息 -> 返回 queued/running -> master-agent task queue -> local-agent / OpenAI API -> complete task -> project ledger`
|
||||||
- `master-agent` 单聊当前已改成“快速入队 + 异步回流”:发送后会立即返回任务包和 `masterReplyState`,前台先显示“主 Agent 思考中”,真实回复稍后自动回写到账本
|
- `master-agent` 单聊当前已改成“快速入队 + 异步回流”:发送后会立即返回任务包和 `masterReplyState`,前台先显示“主 Agent 思考中”,真实回复稍后自动回写到账本
|
||||||
|
- 原生 Android 当前会把 `master-agent` 的等待态保留在消息流里:发送后常驻显示“主 Agent 思考中”,超时后改成“主 Agent 回复超时 + 重试等待”,收到新回复后会自动清掉,不再只靠 toast 提示
|
||||||
- `master-agent` 单聊当前已支持当前对话级别的 `模型 / 推理强度` 覆盖,服务端会优先把该会话的 `agentControls` 用到实际 OpenAI 回复和 Master Codex Node 执行 prompt 中
|
- `master-agent` 单聊当前已支持当前对话级别的 `模型 / 推理强度` 覆盖,服务端会优先把该会话的 `agentControls` 用到实际 OpenAI 回复和 Master Codex Node 执行 prompt 中
|
||||||
- 原生 Android 当前在 `master-agent` 聊天页右上角提供微信式 `...` 菜单,菜单项包含 `模型 / 推理强度 / 会话信息 / 刷新`
|
- 原生 Android 当前在 `master-agent` 聊天页右上角提供微信式 `...` 菜单,菜单项包含 `模型 / 推理强度 / 会话信息 / 刷新`
|
||||||
- 服务器已经部署 `Postfix + Dovecot`,邮箱别名 `verify@boss.hyzq.net` / `no-reply@boss.hyzq.net` 当前会投递到本机 `bossmail` 邮箱
|
- 服务器已经部署 `Postfix + Dovecot`,邮箱别名 `verify@boss.hyzq.net` / `no-reply@boss.hyzq.net` 当前会投递到本机 `bossmail` 邮箱
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
private boolean renderForcedScrollToBottom;
|
private boolean renderForcedScrollToBottom;
|
||||||
private boolean conversationInfoReady;
|
private boolean conversationInfoReady;
|
||||||
private boolean masterAgentReplyWaiting;
|
private boolean masterAgentReplyWaiting;
|
||||||
|
private boolean masterAgentReplyTimedOut;
|
||||||
private @Nullable String masterAgentReplyBaselineMessageId;
|
private @Nullable String masterAgentReplyBaselineMessageId;
|
||||||
private String currentScreenTitle;
|
private String currentScreenTitle;
|
||||||
private String currentScreenSubtitle;
|
private String currentScreenSubtitle;
|
||||||
@@ -327,15 +328,17 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
appendContent(BossUi.buildMessagePlaceholder(this, "还没有项目消息,先发一条开始对话。"));
|
appendContent(BossUi.buildMessagePlaceholder(this, "还没有项目消息,先发一条开始对话。"));
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean masterAgentStillWaiting = isMasterAgentConversation()
|
boolean masterAgentHasReply = isMasterAgentConversation()
|
||||||
&& masterAgentReplyWaiting
|
&& ProjectChatUiState.hasReplyBeyondBaseline(project, masterAgentReplyBaselineMessageId);
|
||||||
&& !ProjectChatUiState.hasReplyBeyondBaseline(project, masterAgentReplyBaselineMessageId);
|
if (masterAgentHasReply) {
|
||||||
if (isMasterAgentConversation() && masterAgentReplyWaiting && !masterAgentStillWaiting) {
|
clearMasterAgentReplyState();
|
||||||
masterAgentReplyWaiting = false;
|
|
||||||
masterAgentReplyBaselineMessageId = null;
|
|
||||||
}
|
}
|
||||||
if (masterAgentStillWaiting) {
|
if (isMasterAgentConversation()) {
|
||||||
appendContent(buildMasterAgentThinkingPlaceholder());
|
if (masterAgentReplyWaiting) {
|
||||||
|
appendContent(buildMasterAgentReplyStateView(false));
|
||||||
|
} else if (masterAgentReplyTimedOut) {
|
||||||
|
appendContent(buildMasterAgentReplyStateView(true));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
@@ -1471,8 +1474,31 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
return value.trim();
|
return value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private View buildMasterAgentThinkingPlaceholder() {
|
private View buildMasterAgentReplyStateView(boolean timedOut) {
|
||||||
return BossUi.buildHintPill(this, "主 Agent 思考中");
|
LinearLayout container = new LinearLayout(this);
|
||||||
|
container.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
container.addView(BossUi.buildCard(
|
||||||
|
this,
|
||||||
|
timedOut ? "主 Agent 回复超时" : "主 Agent 思考中",
|
||||||
|
timedOut
|
||||||
|
? "消息已经发送,但暂时还没有收到回复。你可以继续等待最新结果。"
|
||||||
|
: "消息已发送,正在等待主 Agent 回复。",
|
||||||
|
timedOut
|
||||||
|
? "超时后不会丢失状态,收到新回复会自动清掉。"
|
||||||
|
: "稍后收到回复后,这个状态会自动消失。"
|
||||||
|
));
|
||||||
|
if (timedOut) {
|
||||||
|
Button retryButton = BossUi.buildMiniActionButton(this, "重试等待", true);
|
||||||
|
retryButton.setOnClickListener(v -> retryMasterAgentReplyWait());
|
||||||
|
container.addView(BossUi.buildInlineActionRow(this, retryButton));
|
||||||
|
}
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearMasterAgentReplyState() {
|
||||||
|
masterAgentReplyWaiting = false;
|
||||||
|
masterAgentReplyTimedOut = false;
|
||||||
|
masterAgentReplyBaselineMessageId = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void scrollChatToBottom() {
|
private void scrollChatToBottom() {
|
||||||
@@ -1866,7 +1892,7 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
updateComposerSendButtonState();
|
updateComposerSendButtonState();
|
||||||
setRefreshing(true);
|
setRefreshing(true);
|
||||||
showMessage(waitingMessage);
|
showMessage(waitingMessage);
|
||||||
executor.execute(() -> pollUntilReply(waitSpec, includeDispatchPlans));
|
enqueueReplyWaitPoll(waitSpec.baselineMessageId, includeDispatchPlans);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startMasterAgentReplyWait(
|
private void startMasterAgentReplyWait(
|
||||||
@@ -1875,17 +1901,22 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
String waitingMessage
|
String waitingMessage
|
||||||
) {
|
) {
|
||||||
masterAgentReplyWaiting = true;
|
masterAgentReplyWaiting = true;
|
||||||
|
masterAgentReplyTimedOut = false;
|
||||||
masterAgentReplyBaselineMessageId = waitSpec.baselineMessageId;
|
masterAgentReplyBaselineMessageId = waitSpec.baselineMessageId;
|
||||||
composerSending = false;
|
composerSending = false;
|
||||||
updateComposerSendButtonState();
|
updateComposerSendButtonState();
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
showMessage(waitingMessage);
|
showMessage(waitingMessage);
|
||||||
reload(true);
|
reload(true);
|
||||||
replyWaitExecutor.execute(() -> pollUntilReply(waitSpec, includeDispatchPlans));
|
enqueueReplyWaitPoll(waitSpec.baselineMessageId, includeDispatchPlans);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void enqueueReplyWaitPoll(@Nullable String baselineMessageId, boolean includeDispatchPlans) {
|
||||||
|
replyWaitExecutor.execute(() -> pollUntilReply(baselineMessageId, includeDispatchPlans));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void pollUntilReply(
|
private void pollUntilReply(
|
||||||
ProjectChatUiState.ReplyWaitSpec waitSpec,
|
@Nullable String baselineMessageId,
|
||||||
boolean includeDispatchPlans
|
boolean includeDispatchPlans
|
||||||
) {
|
) {
|
||||||
long deadlineAt = System.currentTimeMillis() + REPLY_WAIT_TIMEOUT_MS;
|
long deadlineAt = System.currentTimeMillis() + REPLY_WAIT_TIMEOUT_MS;
|
||||||
@@ -1894,7 +1925,7 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
while (!Thread.currentThread().isInterrupted() && System.currentTimeMillis() < deadlineAt) {
|
while (!Thread.currentThread().isInterrupted() && System.currentTimeMillis() < deadlineAt) {
|
||||||
ProjectSnapshot snapshot = fetchProjectSnapshot(includeDispatchPlans);
|
ProjectSnapshot snapshot = fetchProjectSnapshot(includeDispatchPlans);
|
||||||
JSONObject project = snapshot.payload.optJSONObject("project");
|
JSONObject project = snapshot.payload.optJSONObject("project");
|
||||||
boolean hasReply = ProjectChatUiState.hasReplyBeyondBaseline(project, waitSpec.baselineMessageId);
|
boolean hasReply = ProjectChatUiState.hasReplyBeyondBaseline(project, baselineMessageId);
|
||||||
|
|
||||||
if (!renderedInitialSnapshot || hasReply) {
|
if (!renderedInitialSnapshot || hasReply) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
@@ -1910,10 +1941,7 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
|
|
||||||
if (hasReply) {
|
if (hasReply) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (isMasterAgentConversation()) {
|
clearMasterAgentReplyState();
|
||||||
masterAgentReplyWaiting = false;
|
|
||||||
masterAgentReplyBaselineMessageId = null;
|
|
||||||
}
|
|
||||||
composerSending = false;
|
composerSending = false;
|
||||||
updateComposerSendButtonState();
|
updateComposerSendButtonState();
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
@@ -1928,19 +1956,19 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (isMasterAgentConversation()) {
|
if (isMasterAgentConversation()) {
|
||||||
masterAgentReplyWaiting = false;
|
masterAgentReplyWaiting = false;
|
||||||
masterAgentReplyBaselineMessageId = null;
|
masterAgentReplyTimedOut = true;
|
||||||
}
|
}
|
||||||
composerSending = false;
|
composerSending = false;
|
||||||
updateComposerSendButtonState();
|
updateComposerSendButtonState();
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
showMessage("对方还在处理中,稍后下拉刷新查看最新回复。");
|
showMessage("主 Agent 回复超时,可重试等待最新回复。");
|
||||||
reload(false);
|
reload(false);
|
||||||
});
|
});
|
||||||
} catch (Exception error) {
|
} catch (Exception error) {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
if (isMasterAgentConversation()) {
|
if (isMasterAgentConversation()) {
|
||||||
masterAgentReplyWaiting = false;
|
masterAgentReplyWaiting = false;
|
||||||
masterAgentReplyBaselineMessageId = null;
|
masterAgentReplyTimedOut = true;
|
||||||
}
|
}
|
||||||
composerSending = false;
|
composerSending = false;
|
||||||
updateComposerSendButtonState();
|
updateComposerSendButtonState();
|
||||||
@@ -1951,6 +1979,20 @@ public class ProjectDetailActivity extends BossScreenActivity {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void retryMasterAgentReplyWait() {
|
||||||
|
if (!isMasterAgentConversation() || TextUtils.isEmpty(masterAgentReplyBaselineMessageId)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
masterAgentReplyWaiting = true;
|
||||||
|
masterAgentReplyTimedOut = false;
|
||||||
|
composerSending = false;
|
||||||
|
updateComposerSendButtonState();
|
||||||
|
setRefreshing(false);
|
||||||
|
showMessage("已重新开始等待主 Agent 回复");
|
||||||
|
reload(true);
|
||||||
|
enqueueReplyWaitPoll(masterAgentReplyBaselineMessageId, false);
|
||||||
|
}
|
||||||
|
|
||||||
static ChromeBindings buildChromeBindings(
|
static ChromeBindings buildChromeBindings(
|
||||||
ProjectChatUiState.ChromeState chromeState,
|
ProjectChatUiState.ChromeState chromeState,
|
||||||
boolean composerBusy
|
boolean composerBusy
|
||||||
|
|||||||
@@ -253,6 +253,132 @@ public class ProjectDetailActivityUiTest {
|
|||||||
assertEquals("...", headerAction.getText().toString());
|
assertEquals("...", headerAction.getText().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderProjectKeepsMasterAgentWaitingStateVisibleInMessageFlow() throws Exception {
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "master-agent")
|
||||||
|
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "主 Agent");
|
||||||
|
TestProjectDetailActivity activity = Robolectric
|
||||||
|
.buildActivity(TestProjectDetailActivity.class, intent)
|
||||||
|
.setup()
|
||||||
|
.get();
|
||||||
|
|
||||||
|
ReflectionHelpers.setField(activity, "conversationInfoReady", true);
|
||||||
|
ReflectionHelpers.setField(activity, "currentScreenTitle", "主 Agent");
|
||||||
|
ReflectionHelpers.setField(activity, "currentScreenSubtitle", "单聊会话");
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyWaiting", true);
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyTimedOut", false);
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyBaselineMessageId", "msg-user-1");
|
||||||
|
|
||||||
|
JSONObject project = new JSONObject()
|
||||||
|
.put("project", new JSONObject()
|
||||||
|
.put("id", "master-agent")
|
||||||
|
.put("name", "主 Agent")
|
||||||
|
.put("messages", new JSONArray()
|
||||||
|
.put(new JSONObject().put("id", "msg-user-1").put("sender", "user"))));
|
||||||
|
|
||||||
|
ReflectionHelpers.callInstanceMethod(
|
||||||
|
activity,
|
||||||
|
"renderProject",
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONObject.class, project),
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONArray.class, null),
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONObject.class, null)
|
||||||
|
);
|
||||||
|
|
||||||
|
View content = activity.findViewById(R.id.screen_content);
|
||||||
|
assertTrue(viewTreeContainsText(content, "主 Agent 思考中"));
|
||||||
|
assertFalse(viewTreeContainsText(content, "重试等待"));
|
||||||
|
assertFalse(ReflectionHelpers.getField(activity, "masterAgentReplyTimedOut"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderProjectShowsRetryEntryAfterMasterAgentWaitTimesOut() throws Exception {
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "master-agent")
|
||||||
|
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "主 Agent");
|
||||||
|
TestProjectDetailActivity activity = Robolectric
|
||||||
|
.buildActivity(TestProjectDetailActivity.class, intent)
|
||||||
|
.setup()
|
||||||
|
.get();
|
||||||
|
|
||||||
|
ReflectionHelpers.setField(activity, "conversationInfoReady", true);
|
||||||
|
ReflectionHelpers.setField(activity, "currentScreenTitle", "主 Agent");
|
||||||
|
ReflectionHelpers.setField(activity, "currentScreenSubtitle", "单聊会话");
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyWaiting", false);
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyTimedOut", true);
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyBaselineMessageId", "msg-user-1");
|
||||||
|
|
||||||
|
JSONObject project = new JSONObject()
|
||||||
|
.put("project", new JSONObject()
|
||||||
|
.put("id", "master-agent")
|
||||||
|
.put("name", "主 Agent")
|
||||||
|
.put("messages", new JSONArray()
|
||||||
|
.put(new JSONObject().put("id", "msg-user-1").put("sender", "user"))));
|
||||||
|
|
||||||
|
ReflectionHelpers.callInstanceMethod(
|
||||||
|
activity,
|
||||||
|
"renderProject",
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONObject.class, project),
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONArray.class, null),
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONObject.class, null)
|
||||||
|
);
|
||||||
|
|
||||||
|
View content = activity.findViewById(R.id.screen_content);
|
||||||
|
View retryButton = findClickableViewContainingText(content, "重试等待");
|
||||||
|
assertNotNull(retryButton);
|
||||||
|
assertTrue(viewTreeContainsText(content, "主 Agent 回复超时"));
|
||||||
|
|
||||||
|
retryButton.performClick();
|
||||||
|
|
||||||
|
assertTrue(ReflectionHelpers.<Boolean>getField(activity, "masterAgentReplyWaiting"));
|
||||||
|
assertFalse(ReflectionHelpers.<Boolean>getField(activity, "masterAgentReplyTimedOut"));
|
||||||
|
assertEquals(1, activity.replyWaitPollCount);
|
||||||
|
assertEquals("msg-user-1", activity.lastReplyWaitBaselineMessageId);
|
||||||
|
assertFalse(activity.lastReplyWaitIncludeDispatchPlans);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void renderProjectClearsMasterAgentWaitStateAfterNewReplyArrives() throws Exception {
|
||||||
|
Intent intent = new Intent()
|
||||||
|
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "master-agent")
|
||||||
|
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "主 Agent");
|
||||||
|
TestProjectDetailActivity activity = Robolectric
|
||||||
|
.buildActivity(TestProjectDetailActivity.class, intent)
|
||||||
|
.setup()
|
||||||
|
.get();
|
||||||
|
|
||||||
|
ReflectionHelpers.setField(activity, "conversationInfoReady", true);
|
||||||
|
ReflectionHelpers.setField(activity, "currentScreenTitle", "主 Agent");
|
||||||
|
ReflectionHelpers.setField(activity, "currentScreenSubtitle", "单聊会话");
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyWaiting", true);
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyTimedOut", true);
|
||||||
|
ReflectionHelpers.setField(activity, "masterAgentReplyBaselineMessageId", "msg-user-1");
|
||||||
|
|
||||||
|
JSONObject project = new JSONObject()
|
||||||
|
.put("project", new JSONObject()
|
||||||
|
.put("id", "master-agent")
|
||||||
|
.put("name", "主 Agent")
|
||||||
|
.put("messages", new JSONArray()
|
||||||
|
.put(new JSONObject().put("id", "msg-user-1").put("sender", "user"))
|
||||||
|
.put(new JSONObject().put("id", "msg-thread-1").put("sender", "assistant"))
|
||||||
|
.put(new JSONObject().put("id", "msg-thread-2").put("sender", "assistant"))));
|
||||||
|
|
||||||
|
ReflectionHelpers.callInstanceMethod(
|
||||||
|
activity,
|
||||||
|
"renderProject",
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONObject.class, project),
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONArray.class, null),
|
||||||
|
ReflectionHelpers.ClassParameter.from(JSONObject.class, null)
|
||||||
|
);
|
||||||
|
|
||||||
|
View content = activity.findViewById(R.id.screen_content);
|
||||||
|
assertFalse(viewTreeContainsText(content, "主 Agent 思考中"));
|
||||||
|
assertFalse(viewTreeContainsText(content, "主 Agent 回复超时"));
|
||||||
|
assertFalse(ReflectionHelpers.<Boolean>getField(activity, "masterAgentReplyWaiting"));
|
||||||
|
assertFalse(ReflectionHelpers.<Boolean>getField(activity, "masterAgentReplyTimedOut"));
|
||||||
|
assertEquals(null, ReflectionHelpers.getField(activity, "masterAgentReplyBaselineMessageId"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void outgoingAttachmentMetaPrefersTimeOnly() throws Exception {
|
public void outgoingAttachmentMetaPrefersTimeOnly() throws Exception {
|
||||||
Intent intent = new Intent()
|
Intent intent = new Intent()
|
||||||
@@ -521,10 +647,21 @@ public class ProjectDetailActivityUiTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static class TestProjectDetailActivity extends ProjectDetailActivity {
|
public static class TestProjectDetailActivity extends ProjectDetailActivity {
|
||||||
|
int replyWaitPollCount;
|
||||||
|
String lastReplyWaitBaselineMessageId;
|
||||||
|
boolean lastReplyWaitIncludeDispatchPlans;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean shouldLoadOnCreate() {
|
boolean shouldLoadOnCreate() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void enqueueReplyWaitPoll(String baselineMessageId, boolean includeDispatchPlans) {
|
||||||
|
replyWaitPollCount += 1;
|
||||||
|
lastReplyWaitBaselineMessageId = baselineMessageId;
|
||||||
|
lastReplyWaitIncludeDispatchPlans = includeDispatchPlans;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class InMemorySharedPreferences implements SharedPreferences {
|
private static final class InMemorySharedPreferences implements SharedPreferences {
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ cd /Users/kris/code/boss
|
|||||||
- 主 Agent 当前真实对话链路已验证通过:`Boss Web -> /api/v1/projects/master-agent/messages -> master-agent task queue -> local-agent -> codex exec -> /complete -> 项目消息账本`
|
- 主 Agent 当前真实对话链路已验证通过:`Boss Web -> /api/v1/projects/master-agent/messages -> master-agent task queue -> local-agent -> codex exec -> /complete -> 项目消息账本`
|
||||||
- 主 Agent 单聊当前已改成“快速入队 + 异步回流”:`POST /api/v1/projects/master-agent/messages` 会先返回 `masterReplyState + task`,真实回复随后再回写消息账本
|
- 主 Agent 单聊当前已改成“快速入队 + 异步回流”:`POST /api/v1/projects/master-agent/messages` 会先返回 `masterReplyState + task`,真实回复随后再回写消息账本
|
||||||
- 当前对话级 `agentControls` 已经生效:`master-agent` 会话支持 `modelOverride / reasoningEffortOverride`,并会优先作用到实际 OpenAI 回复和 Master Codex Node 执行 prompt
|
- 当前对话级 `agentControls` 已经生效:`master-agent` 会话支持 `modelOverride / reasoningEffortOverride`,并会优先作用到实际 OpenAI 回复和 Master Codex Node 执行 prompt
|
||||||
|
- 原生 Android 当前会把 `master-agent` 的等待态保留在消息流里:发送后常驻显示“主 Agent 思考中”,超时后改成“主 Agent 回复超时 + 重试等待”,收到新回复后会自动清掉,不再只靠 toast 提示
|
||||||
- `GET /api/v1/app-logs` 当前已支持登录态分页查询
|
- `GET /api/v1/app-logs` 当前已支持登录态分页查询
|
||||||
- `POST /api/v1/app-logs`、`POST /api/v1/devices/[deviceId]/skills`、`POST /api/v1/workers/[workerId]/thread-context` 当前都要求有效设备 token 或匹配登录会话
|
- `POST /api/v1/app-logs`、`POST /api/v1/devices/[deviceId]/skills`、`POST /api/v1/workers/[workerId]/thread-context` 当前都要求有效设备 token 或匹配登录会话
|
||||||
- 设备页当前只保留生产设备;旧演示脏数据已经从设备、运维和审计聚合视图里剔除
|
- 设备页当前只保留生产设备;旧演示脏数据已经从设备、运维和审计聚合视图里剔除
|
||||||
|
|||||||
Reference in New Issue
Block a user