feat: surface codex account runtime notices
This commit is contained in:
@@ -1437,6 +1437,65 @@ public final class BossUi {
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject accountStatus = progress == null ? null : progress.optJSONObject("accountStatus");
|
||||
JSONObject modelVerification = progress == null ? null : progress.optJSONObject("modelVerification");
|
||||
JSONArray verifications = modelVerification == null ? null : modelVerification.optJSONArray("verifications");
|
||||
boolean hasAccountStatus = accountStatus != null ||
|
||||
(verifications != null && verifications.length() > 0);
|
||||
if (hasAccountStatus) {
|
||||
card.addView(divider(context));
|
||||
card.addView(sectionTitle(context, "账号状态"));
|
||||
if (accountStatus != null) {
|
||||
String authMode = accountStatus.optString("authMode", "").trim();
|
||||
String planType = accountStatus.optString("planType", "").trim();
|
||||
if (!TextUtils.isEmpty(authMode) || !TextUtils.isEmpty(planType)) {
|
||||
String label = !TextUtils.isEmpty(authMode) && !TextUtils.isEmpty(planType)
|
||||
? "认证 " + authMode + " · " + planType
|
||||
: !TextUtils.isEmpty(authMode) ? "认证 " + authMode : "套餐 " + planType;
|
||||
card.addView(detailRow(context, "◇", label, "", false));
|
||||
}
|
||||
String limitName = accountStatus.optString("limitName", "").trim();
|
||||
int usedPercent = accountStatus.optInt("usedPercent", -1);
|
||||
if (!TextUtils.isEmpty(limitName) || usedPercent >= 0) {
|
||||
String label = "额度";
|
||||
if (!TextUtils.isEmpty(limitName)) {
|
||||
label += " " + limitName;
|
||||
}
|
||||
if (usedPercent >= 0) {
|
||||
label += " · " + usedPercent + "%";
|
||||
}
|
||||
card.addView(detailRow(context, "◷", label, "", false));
|
||||
}
|
||||
int windowDurationMins = accountStatus.optInt("windowDurationMins", 0);
|
||||
if (windowDurationMins > 0) {
|
||||
card.addView(detailRow(context, "", "窗口 " + windowDurationMins + " 分钟", "", false, true));
|
||||
}
|
||||
String creditsBalance = accountStatus.optString("creditsBalance", "").trim();
|
||||
if (!TextUtils.isEmpty(creditsBalance)) {
|
||||
card.addView(detailRow(context, "", "余额 " + creditsBalance, "", false, true));
|
||||
}
|
||||
}
|
||||
if (verifications != null && verifications.length() > 0) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < verifications.length(); i += 1) {
|
||||
String verification = verifications.optString(i, "").trim();
|
||||
if (TextUtils.isEmpty(verification)) {
|
||||
continue;
|
||||
}
|
||||
if (builder.length() > 0) {
|
||||
builder.append(", ");
|
||||
}
|
||||
builder.append(verification);
|
||||
if (builder.length() > 120) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (builder.length() > 0) {
|
||||
card.addView(detailRow(context, "◇", "模型校验 " + builder, "", false));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSONObject modelRoute = progress == null ? null : progress.optJSONObject("modelRoute");
|
||||
JSONObject tokenUsage = progress == null ? null : progress.optJSONObject("tokenUsage");
|
||||
JSONArray mcpServers = progress == null ? null : progress.optJSONArray("mcpServers");
|
||||
|
||||
@@ -1069,6 +1069,58 @@ public class ProjectDetailActivityUiTest {
|
||||
assertFalse(viewTreeContainsText(messageView, "sk-secret"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executionProgressMessageRendersCodexAccountStatusAndVerificationSections() throws Exception {
|
||||
Intent intent = new Intent()
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_ID, "thread-account")
|
||||
.putExtra(ProjectDetailActivity.EXTRA_PROJECT_NAME, "Boss开发主线程");
|
||||
TestProjectDetailActivity activity = Robolectric
|
||||
.buildActivity(TestProjectDetailActivity.class, intent)
|
||||
.setup()
|
||||
.get();
|
||||
|
||||
JSONObject message = new JSONObject()
|
||||
.put("id", "progress-account-1")
|
||||
.put("sender", "master")
|
||||
.put("senderLabel", "主 Agent")
|
||||
.put("body", "执行进度")
|
||||
.put("kind", "execution_progress")
|
||||
.put("sentAt", "2026-06-01T10:28:00+08:00")
|
||||
.put("executionProgress", new JSONObject()
|
||||
.put("status", "running")
|
||||
.put("steps", new JSONArray()
|
||||
.put(new JSONObject().put("text", "同步 Codex 账号运行态").put("status", "running")))
|
||||
.put("accountStatus", new JSONObject()
|
||||
.put("authMode", "chatgpt")
|
||||
.put("planType", "team")
|
||||
.put("limitName", "Codex")
|
||||
.put("usedPercent", 88)
|
||||
.put("windowDurationMins", 180)
|
||||
.put("resetsAt", 1770003600)
|
||||
.put("creditsBalance", "120.5")
|
||||
.put("hasCredits", true)
|
||||
.put("unlimitedCredits", false)
|
||||
.put("accessToken", "sk-secret-should-not-render"))
|
||||
.put("modelVerification", new JSONObject()
|
||||
.put("verifications", new JSONArray().put("trustedAccessForCyber"))
|
||||
.put("turnId", "turn-secret-should-not-render")));
|
||||
|
||||
View messageView = ReflectionHelpers.callInstanceMethod(
|
||||
activity,
|
||||
"buildMessageView",
|
||||
ReflectionHelpers.ClassParameter.from(JSONObject.class, message)
|
||||
);
|
||||
|
||||
assertTrue(viewTreeContainsText(messageView, "账号状态"));
|
||||
assertTrue(viewTreeContainsText(messageView, "认证 chatgpt · team"));
|
||||
assertTrue(viewTreeContainsText(messageView, "额度 Codex · 88%"));
|
||||
assertTrue(viewTreeContainsText(messageView, "窗口 180 分钟"));
|
||||
assertTrue(viewTreeContainsText(messageView, "余额 120.5"));
|
||||
assertTrue(viewTreeContainsText(messageView, "模型校验 trustedAccessForCyber"));
|
||||
assertFalse(viewTreeContainsText(messageView, "sk-secret"));
|
||||
assertFalse(viewTreeContainsText(messageView, "turn-secret"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void executionProgressMessageRendersCodexThreadGoalSettingsAndCompactionSections() throws Exception {
|
||||
Intent intent = new Intent()
|
||||
|
||||
Reference in New Issue
Block a user