feat: show codex app server summaries on android

This commit is contained in:
AI Bot
2026-06-04 15:08:27 +08:00
parent 3080f57dbc
commit a5d44b0cac
6 changed files with 212 additions and 9 deletions

View File

@@ -187,6 +187,64 @@ public class DeviceDetailActivity extends BossScreenActivity {
null,
null
));
if (WechatSurfaceMapper.hasCodexAppServerMetadata(device)) {
appendContent(BossUi.buildWechatMenuRow(
this,
"模型",
WechatSurfaceMapper.deviceCodexModelSummary(device),
null,
null,
null
));
appendContent(BossUi.buildWechatMenuRow(
this,
"扩展",
WechatSurfaceMapper.deviceCodexExtensionSummary(device),
null,
null,
null
));
appendContent(BossUi.buildWechatMenuRow(
this,
"治理",
WechatSurfaceMapper.deviceCodexGovernanceSummary(device),
null,
null,
null
));
appendContent(BossUi.buildWechatMenuRow(
this,
"账号",
WechatSurfaceMapper.deviceCodexAccountSummary(device),
null,
null,
null
));
appendContent(BossUi.buildWechatMenuRow(
this,
"线程",
WechatSurfaceMapper.deviceCodexThreadSummary(device),
null,
null,
null
));
appendContent(BossUi.buildWechatMenuRow(
this,
"轮次",
WechatSurfaceMapper.deviceCodexTurnSummary(device),
null,
null,
null
));
appendContent(BossUi.buildWechatMenuRow(
this,
"线程操作",
WechatSurfaceMapper.deviceCodexThreadActionSummary(device),
null,
null,
null
));
}
appendContent(BossUi.buildWechatMenuRow(
this,
"线程协作",

View File

@@ -252,6 +252,10 @@ public final class WechatSurfaceMapper {
return resolveDeviceCapability(device, "codexAppServer") != null;
}
public static boolean hasCodexAppServerMetadata(JSONObject device) {
return resolveCodexAppServerMetadata(device) != null;
}
public static String deviceCodexAppServerStatusLabel(JSONObject device) {
JSONObject capability = resolveDeviceCapability(device, "codexAppServer");
boolean connected = capability != null && capability.optBoolean("connected", false);
@@ -270,6 +274,64 @@ public final class WechatSurfaceMapper {
return "最近上报 " + lastSeenAt;
}
public static String deviceCodexModelSummary(JSONObject device) {
JSONObject metadata = resolveCodexAppServerMetadata(device);
int modelCount = metadataArrayLength(metadata, "models");
if (modelCount <= 0) {
return "未发现";
}
return modelCount + ""
+ " · 默认 " + metadataText(metadata, "defaultModelId")
+ " · 快速 " + metadataText(metadata, "fastModelId")
+ " · 深度 " + metadataText(metadata, "deepModelId");
}
public static String deviceCodexExtensionSummary(JSONObject device) {
JSONObject metadata = resolveCodexAppServerMetadata(device);
return "Skill " + metadataArrayLength(metadata, "skills") + ""
+ " · Plugin " + metadataArrayLength(metadata, "plugins") + ""
+ " · App " + metadataArrayLength(metadata, "apps") + "";
}
public static String deviceCodexGovernanceSummary(JSONObject device) {
JSONObject metadata = resolveCodexAppServerMetadata(device);
return "实验特性 " + metadataArrayLength(metadata, "experimentalFeatures") + ""
+ " · 协作模式 " + metadataArrayLength(metadata, "collaborationModes") + ""
+ " · MCP " + metadataArrayLength(metadata, "mcpServers") + ""
+ " · 权限 " + metadataArrayLength(metadata, "permissionProfiles") + "";
}
public static String deviceCodexAccountSummary(JSONObject device) {
JSONObject metadata = resolveCodexAppServerMetadata(device);
JSONObject accountSummary = metadata == null ? null : metadata.optJSONObject("accountSummary");
JSONObject rateLimitSummary = metadata == null ? null : metadata.optJSONObject("rateLimitSummary");
return objectText(accountSummary, "authMode")
+ " · 套餐 " + objectText(accountSummary, "planType")
+ " · 额度 " + objectInt(rateLimitSummary, "maxUsedPercent") + "%";
}
public static String deviceCodexThreadSummary(JSONObject device) {
JSONObject summary = resolveCodexAppServerMetadataObject(device, "threadSummary");
return objectInt(summary, "threadCount") + ""
+ " · 已加载 " + objectInt(summary, "loadedThreadCount") + ""
+ " · 活跃 " + objectInt(summary, "activeThreadCount") + "";
}
public static String deviceCodexTurnSummary(JSONObject device) {
JSONObject summary = resolveCodexAppServerMetadataObject(device, "threadTurnSummary");
return objectInt(summary, "totalTurnCount") + ""
+ " · 运行中 " + objectInt(summary, "runningTurnCount") + ""
+ " · 完成 " + objectInt(summary, "completedTurnCount") + "";
}
public static String deviceCodexThreadActionSummary(JSONObject device) {
JSONObject summary = resolveCodexAppServerMetadataObject(device, "threadActionSummary");
return objectInt(summary, "actionCount") + ""
+ " · 生命周期 " + objectInt(summary, "lifecycleActionCount") + ""
+ " · 活跃干预 " + objectInt(summary, "liveTurnActionCount") + ""
+ " · " + (summary != null && summary.optBoolean("shellActionAvailable", false) ? "Shell 可用" : "Shell 不可用");
}
public static String deviceCodexThreadCollaborationSummary(JSONObject device) {
JSONObject summary = resolveCodexAppServerMetadataObject(device, "threadCollaborationSummary");
if (summary == null) {
@@ -528,11 +590,43 @@ public final class WechatSurfaceMapper {
}
private static JSONObject resolveCodexAppServerMetadataObject(JSONObject device, String key) {
JSONObject capability = resolveDeviceCapability(device, "codexAppServer");
JSONObject metadata = capability == null ? null : capability.optJSONObject("metadata");
JSONObject metadata = resolveCodexAppServerMetadata(device);
return metadata == null ? null : metadata.optJSONObject(key);
}
private static JSONObject resolveCodexAppServerMetadata(JSONObject device) {
JSONObject capability = resolveDeviceCapability(device, "codexAppServer");
return capability == null ? null : capability.optJSONObject("metadata");
}
private static int metadataArrayLength(JSONObject metadata, String key) {
if (metadata == null) {
return 0;
}
JSONArray array = metadata.optJSONArray(key);
return array == null ? 0 : array.length();
}
private static String metadataText(JSONObject metadata, String key) {
if (metadata == null) {
return "未知";
}
String value = metadata.optString(key, "").trim();
return value.isEmpty() ? "未知" : value;
}
private static String objectText(JSONObject object, String key) {
if (object == null) {
return "未知";
}
String value = object.optString(key, "").trim();
return value.isEmpty() ? "未知" : value;
}
private static int objectInt(JSONObject object, String key) {
return object == null ? 0 : object.optInt(key, 0);
}
public static RootTopAction rootTopAction(String activeTab, boolean refreshing) {
return rootTopAction(activeTab, refreshing, false);
}