feat: queue master-agent chat replies
This commit is contained in:
@@ -69,6 +69,31 @@ public class BossApiClientDispatchPlansTest {
|
||||
assertEquals("{}", connection.requestBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getProjectAgentControlsUsesScopedEndpoint() throws Exception {
|
||||
RecordingConnection connection = new RecordingConnection(new URL("https://boss.hyzq.net/api/v1/projects/master-agent/agent-controls"));
|
||||
RecordingBossApiClient apiClient = new RecordingBossApiClient(connection);
|
||||
|
||||
BossApiClient.ApiResponse response = apiClient.getProjectAgentControls("master-agent");
|
||||
|
||||
assertEquals(200, response.statusCode);
|
||||
assertEquals("/api/v1/projects/master-agent/agent-controls", apiClient.lastPath);
|
||||
assertEquals("GET", connection.requestMethodValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateProjectAgentControlsWritesModelAndReasoningOverrides() throws Exception {
|
||||
RecordingConnection connection = new RecordingConnection(new URL("https://boss.hyzq.net/api/v1/projects/master-agent/agent-controls"));
|
||||
RecordingBossApiClient apiClient = new RecordingBossApiClient(connection);
|
||||
|
||||
BossApiClient.ApiResponse response = apiClient.updateProjectAgentControls("master-agent", "gpt-5.4", "high");
|
||||
|
||||
assertEquals(200, response.statusCode);
|
||||
assertEquals("/api/v1/projects/master-agent/agent-controls", apiClient.lastPath);
|
||||
assertEquals("POST", connection.requestMethodValue);
|
||||
assertEquals("{\"modelOverride\":\"gpt-5.4\",\"reasoningEffortOverride\":\"high\"}", connection.requestBody());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void sendProjectMessageUsesExtendedReadTimeoutForMasterAgent() throws Exception {
|
||||
RecordingConnection connection = new RecordingConnection(new URL("https://boss.hyzq.net/api/v1/projects/master-agent/messages"));
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.hyzq.boss;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.robolectric.Robolectric;
|
||||
import org.robolectric.RobolectricTestRunner;
|
||||
import org.robolectric.annotation.Config;
|
||||
import org.robolectric.shadows.ShadowDialog;
|
||||
import org.robolectric.util.ReflectionHelpers;
|
||||
|
||||
@RunWith(RobolectricTestRunner.class)
|
||||
@Config(sdk = 34)
|
||||
public class ProjectDetailActivityMasterAgentMenuTest {
|
||||
@Test
|
||||
public void masterAgentMoreMenuShowsWechatActions() {
|
||||
Intent intent = new Intent()
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "master-agent")
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "主 Agent");
|
||||
ProjectDetailActivityUiTest.TestProjectDetailActivity activity = Robolectric
|
||||
.buildActivity(ProjectDetailActivityUiTest.TestProjectDetailActivity.class, intent)
|
||||
.setup()
|
||||
.get();
|
||||
|
||||
ReflectionHelpers.callInstanceMethod(activity, "showMasterAgentMoreMenu");
|
||||
|
||||
android.app.Dialog latestDialog = ShadowDialog.getLatestDialog();
|
||||
assertTrue(latestDialog instanceof AlertDialog);
|
||||
AlertDialog actionDialog = (AlertDialog) latestDialog;
|
||||
ListView listView = actionDialog.getListView();
|
||||
|
||||
assertMenuItem(listView, 0, "模型");
|
||||
assertMenuItem(listView, 1, "推理强度");
|
||||
assertMenuItem(listView, 2, "会话信息");
|
||||
assertMenuItem(listView, 3, "刷新");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void masterAgentWaitingStateRendersThinkingPlaceholder() throws Exception {
|
||||
Intent intent = new Intent()
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "master-agent")
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "主 Agent");
|
||||
ProjectDetailActivityUiTest.TestProjectDetailActivity activity = Robolectric
|
||||
.buildActivity(ProjectDetailActivityUiTest.TestProjectDetailActivity.class, intent)
|
||||
.setup()
|
||||
.get();
|
||||
|
||||
ReflectionHelpers.setField(activity, "conversationInfoReady", true);
|
||||
ReflectionHelpers.setField(activity, "masterAgentReplyWaiting", true);
|
||||
ReflectionHelpers.setField(activity, "masterAgentReplyBaselineMessageId", "msg-user-1");
|
||||
|
||||
JSONObject 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("senderLabel", "Boss 超级管理员")
|
||||
.put("body", "帮我检查当前主控")
|
||||
.put("kind", "text")));
|
||||
JSONObject payload = new JSONObject().put("project", project);
|
||||
|
||||
ReflectionHelpers.callInstanceMethod(
|
||||
activity,
|
||||
"renderProject",
|
||||
ReflectionHelpers.ClassParameter.from(JSONObject.class, payload),
|
||||
ReflectionHelpers.ClassParameter.from(JSONArray.class, null),
|
||||
ReflectionHelpers.ClassParameter.from(JSONObject.class, null)
|
||||
);
|
||||
|
||||
View contentRoot = activity.findViewById(R.id.screen_content);
|
||||
assertNotNull(contentRoot);
|
||||
assertTrue(viewTreeContainsText(contentRoot, "主 Agent 思考中"));
|
||||
}
|
||||
|
||||
private static void assertMenuItem(ListView listView, int index, String expectedText) {
|
||||
View item = listView.getAdapter().getView(index, null, listView);
|
||||
assertTrue(viewTreeContainsText(item, expectedText));
|
||||
}
|
||||
|
||||
private static boolean viewTreeContainsText(View root, String expectedText) {
|
||||
if (root instanceof TextView) {
|
||||
CharSequence text = ((TextView) root).getText();
|
||||
if (expectedText.contentEquals(text)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (!(root instanceof ViewGroup)) {
|
||||
return false;
|
||||
}
|
||||
ViewGroup group = (ViewGroup) root;
|
||||
for (int index = 0; index < group.getChildCount(); index += 1) {
|
||||
if (viewTreeContainsText(group.getChildAt(index), expectedText)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -232,6 +232,27 @@ public class ProjectDetailActivityUiTest {
|
||||
assertFalse(viewTreeContainsText(messageView, "Boss 超级管理员 · 10:26"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void masterAgentHeaderUsesWechatMoreMenuLabel() {
|
||||
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.callInstanceMethod(activity, "updateSelectionUi");
|
||||
|
||||
Button headerAction = activity.findViewById(R.id.screen_header_action);
|
||||
assertEquals(View.VISIBLE, headerAction.getVisibility());
|
||||
assertEquals("...", headerAction.getText().toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void outgoingAttachmentMetaPrefersTimeOnly() throws Exception {
|
||||
Intent intent = new Intent()
|
||||
|
||||
Reference in New Issue
Block a user