docs: add master-agent chat controls plan
This commit is contained in:
650
docs/superpowers/plans/2026-03-31-master-agent-chat-controls.md
Normal file
650
docs/superpowers/plans/2026-03-31-master-agent-chat-controls.md
Normal file
@@ -0,0 +1,650 @@
|
||||
# 主 Agent 对话控制与异步回复 Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** 让 `master-agent` 单聊改成“快速入队 + 异步回流”,并为当前对话补上模型选择、推理强度选择和微信式右上角三点菜单。
|
||||
|
||||
**Architecture:** 后端在文件型状态中为 `master-agent` 会话新增对话级控制项,并把消息发送接口改成优先快速返回 `queued/running` 状态;主 Agent 继续走现有 `Master Codex Node / OpenAI API` 路线完成真实回复回写。Android 聊天页把右上角动作收成微信式 `...` 菜单,并用轮询项目详情的方式展示“思考中 / 失败 / 已回复”状态。
|
||||
|
||||
**Tech Stack:** Next.js App Router, TypeScript, file-backed state store, Android AppCompat/Java, node:test, Gradle unit tests
|
||||
|
||||
---
|
||||
|
||||
### Task 1: 为 `master-agent` 会话补对话级模型与推理强度配置
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
|
||||
- Modify: `/Users/kris/code/boss/src/lib/boss-projections.ts`
|
||||
- Modify: `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/route.ts`
|
||||
- Create: `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/agent-controls/route.ts`
|
||||
- Test: `/Users/kris/code/boss/tests/master-agent-chat-controls.test.ts`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,覆盖 `master-agent` 对话配置读写**
|
||||
|
||||
```ts
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import {
|
||||
readState,
|
||||
updateProjectAgentControls,
|
||||
getProjectAgentControls,
|
||||
} from "@/lib/boss-data";
|
||||
|
||||
test("master-agent 会话可保存模型与推理强度覆盖", async () => {
|
||||
await updateProjectAgentControls("master-agent", {
|
||||
modelOverride: "gpt-5.4",
|
||||
reasoningEffortOverride: "high",
|
||||
});
|
||||
|
||||
const controls = await getProjectAgentControls("master-agent");
|
||||
assert.equal(controls?.modelOverride, "gpt-5.4");
|
||||
assert.equal(controls?.reasoningEffortOverride, "high");
|
||||
|
||||
const state = await readState();
|
||||
const project = state.projects.find((item) => item.id === "master-agent");
|
||||
assert.equal(project?.agentControls?.modelOverride, "gpt-5.4");
|
||||
assert.equal(project?.agentControls?.reasoningEffortOverride, "high");
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认当前失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-chat-controls.test.ts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
FAIL ... updateProjectAgentControls is not a function
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在状态模型中增加 `agentControls` 和读写 helper**
|
||||
|
||||
```ts
|
||||
export type ReasoningEffort = "low" | "medium" | "high";
|
||||
|
||||
export interface ProjectAgentControls {
|
||||
modelOverride?: string;
|
||||
reasoningEffortOverride?: ReasoningEffort;
|
||||
updatedAt: string;
|
||||
}
|
||||
|
||||
export interface Project {
|
||||
// ...
|
||||
agentControls?: ProjectAgentControls;
|
||||
}
|
||||
|
||||
export async function getProjectAgentControls(projectId: string) {
|
||||
const state = await readState();
|
||||
return state.projects.find((item) => item.id === projectId)?.agentControls;
|
||||
}
|
||||
|
||||
export async function updateProjectAgentControls(
|
||||
projectId: string,
|
||||
payload: {
|
||||
modelOverride?: string;
|
||||
reasoningEffortOverride?: ReasoningEffort;
|
||||
},
|
||||
) {
|
||||
return withStateLock(async (state) => {
|
||||
const project = state.projects.find((item) => item.id === projectId);
|
||||
if (!project) throw new Error("PROJECT_NOT_FOUND");
|
||||
project.agentControls = {
|
||||
modelOverride: payload.modelOverride?.trim() || undefined,
|
||||
reasoningEffortOverride: payload.reasoningEffortOverride,
|
||||
updatedAt: new Date().toISOString(),
|
||||
};
|
||||
return project.agentControls;
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 补投影和 API**
|
||||
|
||||
```ts
|
||||
// src/lib/boss-projections.ts
|
||||
agentControls: project.id === "master-agent" ? project.agentControls ?? null : undefined,
|
||||
```
|
||||
|
||||
```ts
|
||||
// src/app/api/v1/projects/[projectId]/agent-controls/route.ts
|
||||
export async function GET(_: NextRequest, context: { params: Promise<{ projectId: string }> }) {
|
||||
const session = await requireRequestSession(_);
|
||||
if (!session) return NextResponse.json({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
|
||||
const { projectId } = await context.params;
|
||||
const controls = await getProjectAgentControls(projectId);
|
||||
return NextResponse.json({ ok: true, controls: controls ?? null });
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest, context: { params: Promise<{ projectId: string }> }) {
|
||||
const session = await requireRequestSession(request);
|
||||
if (!session) return NextResponse.json({ ok: false, message: "UNAUTHORIZED" }, { status: 401 });
|
||||
const { projectId } = await context.params;
|
||||
const body = (await request.json()) as { modelOverride?: string; reasoningEffortOverride?: "low" | "medium" | "high" };
|
||||
const controls = await updateProjectAgentControls(projectId, body);
|
||||
return NextResponse.json({ ok: true, controls });
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 再跑测试确认通过**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-chat-controls.test.ts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
# tests 1
|
||||
# pass 1
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
git add tests/master-agent-chat-controls.test.ts src/lib/boss-data.ts src/lib/boss-projections.ts src/app/api/v1/projects/[projectId]/route.ts src/app/api/v1/projects/[projectId]/agent-controls/route.ts
|
||||
git commit -m "feat: add master-agent chat controls state"
|
||||
```
|
||||
|
||||
### Task 2: 把主 Agent 消息接口改成快速返回 `queued/running`
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/messages/route.ts`
|
||||
- Modify: `/Users/kris/code/boss/src/lib/boss-master-agent.ts`
|
||||
- Test: `/Users/kris/code/boss/tests/master-agent-message-queue.test.ts`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,覆盖发送后立即返回任务状态**
|
||||
|
||||
```ts
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { POST } from "@/app/api/v1/projects/[projectId]/messages/route";
|
||||
|
||||
test("master-agent 发送后优先返回 queued 状态", async () => {
|
||||
const request = new Request("http://localhost/api/v1/projects/master-agent/messages", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
cookie: "boss_session=test",
|
||||
},
|
||||
body: JSON.stringify({ body: "帮我检查当前主控", kind: "text" }),
|
||||
});
|
||||
|
||||
const response = await POST(request as never, {
|
||||
params: Promise.resolve({ projectId: "master-agent" }),
|
||||
});
|
||||
const json = await response.json();
|
||||
|
||||
assert.equal(json.ok, true);
|
||||
assert.equal(json.task.taskType, "conversation_reply");
|
||||
assert.match(json.masterReplyState, /queued|running|completed/);
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认当前失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-message-queue.test.ts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
FAIL ... masterReplyState is undefined
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在 `boss-master-agent.ts` 中拆分“入队”和“完成回写”语义**
|
||||
|
||||
```ts
|
||||
export async function replyToMasterAgentUserMessage(params: {
|
||||
requestMessageId: string;
|
||||
requestText: string;
|
||||
requestedBy?: string;
|
||||
requestedByAccount?: string;
|
||||
currentSessionExpiresAt?: string;
|
||||
}) {
|
||||
const runtime = await getMasterAgentRuntime();
|
||||
const task = await queueMasterAgentTask({
|
||||
taskType: "conversation_reply",
|
||||
projectId: "master-agent",
|
||||
requestMessageId: params.requestMessageId,
|
||||
requestText: params.requestText,
|
||||
requestedBy: params.requestedBy,
|
||||
requestedByAccount: params.requestedByAccount,
|
||||
model: runtime.model,
|
||||
reasoningEffort: runtime.reasoningEffort,
|
||||
});
|
||||
|
||||
if (runtime.provider === "openai_api") {
|
||||
void runQueuedMasterAgentReply(task.taskId, params.currentSessionExpiresAt);
|
||||
}
|
||||
|
||||
return {
|
||||
ok: true as const,
|
||||
taskId: task.taskId,
|
||||
state: runtime.provider === "openai_api" ? "running" as const : "queued" as const,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 在消息路由中统一返回 `masterReplyState`**
|
||||
|
||||
```ts
|
||||
if (projectId === "master-agent" && (body.kind ?? "text") === "text" && message.body.trim()) {
|
||||
const queued = await replyToMasterAgentUserMessage({
|
||||
requestMessageId: message.id,
|
||||
requestText: message.body,
|
||||
requestedBy: session.displayName,
|
||||
requestedByAccount: session.account,
|
||||
currentSessionExpiresAt: session.expiresAt,
|
||||
});
|
||||
|
||||
masterReply = {
|
||||
ok: queued.ok,
|
||||
taskId: queued.taskId,
|
||||
};
|
||||
task = {
|
||||
taskId: queued.taskId,
|
||||
taskType: "conversation_reply",
|
||||
status: queued.state === "queued" ? "queued" : "running",
|
||||
};
|
||||
masterReplyState = queued.state;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 再跑测试确认通过**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-message-queue.test.ts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
# tests 1
|
||||
# pass 1
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
git add tests/master-agent-message-queue.test.ts src/app/api/v1/projects/[projectId]/messages/route.ts src/lib/boss-master-agent.ts
|
||||
git commit -m "feat: queue master-agent replies asynchronously"
|
||||
```
|
||||
|
||||
### Task 3: 让主 Agent 实际调用优先读取当前对话模型与推理强度
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/kris/code/boss/src/lib/boss-master-agent.ts`
|
||||
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
|
||||
- Test: `/Users/kris/code/boss/tests/master-agent-config-resolution.test.ts`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,覆盖当前对话 override 优先级**
|
||||
|
||||
```ts
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { resolveMasterAgentExecutionConfig } from "@/lib/boss-master-agent";
|
||||
|
||||
test("当前对话 override 优先于主控账号默认值", async () => {
|
||||
const resolved = await resolveMasterAgentExecutionConfig("master-agent");
|
||||
assert.equal(resolved.model, "gpt-5.4");
|
||||
assert.equal(resolved.reasoningEffort, "high");
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认当前失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-config-resolution.test.ts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
FAIL ... resolveMasterAgentExecutionConfig is not a function
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 增加统一解析函数并接入 OpenAI / Master Node 执行路径**
|
||||
|
||||
```ts
|
||||
export async function resolveMasterAgentExecutionConfig(projectId: string) {
|
||||
const runtime = await getMasterAgentRuntimeAccount();
|
||||
const controls = await getProjectAgentControls(projectId);
|
||||
return {
|
||||
provider: runtime.account.provider,
|
||||
model: controls?.modelOverride || runtime.account.model || "gpt-5.4",
|
||||
reasoningEffort: controls?.reasoningEffortOverride || runtime.account.reasoningEffort || "medium",
|
||||
account: runtime.account,
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
```ts
|
||||
// generateOpenAiReply
|
||||
body: JSON.stringify({
|
||||
model: params.model,
|
||||
reasoning: { effort: params.reasoningEffort },
|
||||
instructions: buildMasterAgentInstructions(),
|
||||
input: buildRuntimeDigest(state, params.requestText, params.currentSessionExpiresAt),
|
||||
}),
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 再跑测试确认通过**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-config-resolution.test.ts
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
# tests 1
|
||||
# pass 1
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
git add tests/master-agent-config-resolution.test.ts src/lib/boss-master-agent.ts src/lib/boss-data.ts
|
||||
git commit -m "feat: apply per-chat model and reasoning controls"
|
||||
```
|
||||
|
||||
### Task 4: Android 聊天页改成微信式三点菜单,并接入模型/推理强度设置
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java`
|
||||
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/BossApiClient.java`
|
||||
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/BossScreenActivity.java`
|
||||
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ProjectDetailActivityUiTest.java`
|
||||
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/BossApiClientDispatchPlansTest.java`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,覆盖主 Agent 页显示三点菜单与设置请求**
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void masterAgentHeaderShowsWechatMoreMenu() {
|
||||
ProjectDetailActivity.ChromeBindings bindings =
|
||||
ProjectDetailActivity.computeChromeBindingsForTesting(
|
||||
"master-agent",
|
||||
false,
|
||||
false,
|
||||
true,
|
||||
"主 Agent",
|
||||
""
|
||||
);
|
||||
|
||||
assertThat(bindings.showHeaderAction).isTrue();
|
||||
assertThat(bindings.headerActionLabel).isEqualTo("...");
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void updateMasterAgentControlsPostsModelAndReasoning() throws Exception {
|
||||
BossApiClient client = new BossApiClient(new InMemorySharedPreferences(), "https://boss.hyzq.net");
|
||||
// 断言 request body 带 modelOverride / reasoningEffortOverride
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认当前失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss/android
|
||||
./gradlew testDebugUnitTest --tests com.hyzq.boss.ProjectDetailActivityUiTest --tests com.hyzq.boss.BossApiClientDispatchPlansTest --no-daemon
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
FAIL ... headerActionLabel
|
||||
FAIL ... updateMasterAgentControls
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 在 Android API 客户端里补 controls 读写**
|
||||
|
||||
```java
|
||||
public ApiResponse getProjectAgentControls(String projectId) throws IOException, JSONException {
|
||||
return requestWithRestore("GET", "/api/v1/projects/" + encode(projectId) + "/agent-controls", null);
|
||||
}
|
||||
|
||||
public ApiResponse updateProjectAgentControls(
|
||||
String projectId,
|
||||
String modelOverride,
|
||||
String reasoningEffortOverride
|
||||
) throws IOException, JSONException {
|
||||
JSONObject payload = new JSONObject();
|
||||
payload.put("modelOverride", modelOverride);
|
||||
payload.put("reasoningEffortOverride", reasoningEffortOverride);
|
||||
return requestWithRestore("POST", "/api/v1/projects/" + encode(projectId) + "/agent-controls", payload);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 在聊天页把右上角改成 `...`,并弹出单选菜单**
|
||||
|
||||
```java
|
||||
if ("master-agent".equals(projectId)) {
|
||||
setHeaderAction("...", v -> showMasterAgentMoreMenu());
|
||||
}
|
||||
|
||||
private void showMasterAgentMoreMenu() {
|
||||
String[] items = new String[] {"模型", "推理强度", "会话信息", "刷新"};
|
||||
new AlertDialog.Builder(this)
|
||||
.setItems(items, (dialog, which) -> {
|
||||
if (which == 0) openModelPicker();
|
||||
else if (which == 1) openReasoningPicker();
|
||||
else if (which == 2) openConversationInfo();
|
||||
else reload();
|
||||
})
|
||||
.show();
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: 再跑 Android 单测确认通过**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss/android
|
||||
./gradlew testDebugUnitTest --tests com.hyzq.boss.ProjectDetailActivityUiTest --tests com.hyzq.boss.BossApiClientDispatchPlansTest --no-daemon
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
git add android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java android/app/src/main/java/com/hyzq/boss/BossApiClient.java android/app/src/main/java/com/hyzq/boss/BossScreenActivity.java android/app/src/test/java/com/hyzq/boss/ProjectDetailActivityUiTest.java android/app/src/test/java/com/hyzq/boss/BossApiClientDispatchPlansTest.java
|
||||
git commit -m "feat: add master-agent chat controls menu"
|
||||
```
|
||||
|
||||
### Task 5: Android 主 Agent 聊天页改成“立即显示思考中,再异步收回复”
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/kris/code/boss/android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java`
|
||||
- Test: `/Users/kris/code/boss/android/app/src/test/java/com/hyzq/boss/ProjectDetailActivityChatFlowTest.java`
|
||||
|
||||
- [ ] **Step 1: 写失败测试,覆盖发送后立即显示等待态**
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void masterAgentSendShowsThinkingStateWhenTaskQueued() {
|
||||
// 构造发送响应: { task: { taskId: "task-1", taskType: "conversation_reply", status: "queued" }, masterReplyState: "queued" }
|
||||
// 断言聊天页出现“主 Agent 思考中”
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑测试确认当前失败**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss/android
|
||||
./gradlew testDebugUnitTest --tests com.hyzq.boss.ProjectDetailActivityChatFlowTest --no-daemon
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
FAIL ... expected "主 Agent 思考中"
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 实现等待态与轮询收束**
|
||||
|
||||
```java
|
||||
if ("master-agent".equals(projectId) && taskStatusQueuedOrRunning(response)) {
|
||||
showPendingMasterAgentState("主 Agent 思考中");
|
||||
scheduleProjectReloadPoll(REPLY_WAIT_POLL_INTERVAL_MS, REPLY_WAIT_TIMEOUT_MS);
|
||||
return;
|
||||
}
|
||||
```
|
||||
|
||||
```java
|
||||
private void scheduleProjectReloadPoll(long intervalMs, long timeoutMs) {
|
||||
long startedAt = System.currentTimeMillis();
|
||||
contentLayout.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isFinishing() && System.currentTimeMillis() - startedAt < timeoutMs) {
|
||||
reload(false);
|
||||
contentLayout.postDelayed(this, intervalMs);
|
||||
}
|
||||
}
|
||||
}, intervalMs);
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 再跑测试确认通过**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss/android
|
||||
./gradlew testDebugUnitTest --tests com.hyzq.boss.ProjectDetailActivityChatFlowTest --no-daemon
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
git add android/app/src/main/java/com/hyzq/boss/ProjectDetailActivity.java android/app/src/test/java/com/hyzq/boss/ProjectDetailActivityChatFlowTest.java
|
||||
git commit -m "feat: show queued state for master-agent replies"
|
||||
```
|
||||
|
||||
### Task 6: 文档、验证、部署
|
||||
|
||||
**Files:**
|
||||
- Modify: `/Users/kris/code/boss/README.md`
|
||||
- Modify: `/Users/kris/code/boss/docs/architecture/current_runtime_and_deploy_status_cn.md`
|
||||
- Modify: `/Users/kris/code/boss/docs/architecture/api_and_service_inventory_cn.md`
|
||||
|
||||
- [ ] **Step 1: 跑 Node 与 Android 测试**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npx --yes tsx --test tests/master-agent-chat-controls.test.ts tests/master-agent-message-queue.test.ts tests/master-agent-config-resolution.test.ts
|
||||
cd /Users/kris/code/boss/android
|
||||
./gradlew testDebugUnitTest --tests com.hyzq.boss.ProjectDetailActivityUiTest --tests com.hyzq.boss.BossApiClientDispatchPlansTest --tests com.hyzq.boss.ProjectDetailActivityChatFlowTest --no-daemon
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
pass ... master-agent-chat-controls
|
||||
pass ... master-agent-message-queue
|
||||
pass ... master-agent-config-resolution
|
||||
BUILD SUCCESSFUL
|
||||
```
|
||||
|
||||
- [ ] **Step 2: 跑基础验证**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
npm run lint
|
||||
npm run build
|
||||
curl -sS http://127.0.0.1:3000/api/health
|
||||
curl -sS http://127.0.0.1:4317/health
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
lint 通过
|
||||
build 通过
|
||||
{"ok":true,...}
|
||||
{"ok":true,...}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: 更新文档**
|
||||
|
||||
```md
|
||||
- 主 Agent 单聊发送已改成快速入队;前台会立即显示“主 Agent 思考中”,不再同步长等待
|
||||
- `master-agent` 对话当前支持对话级 `模型 / 推理强度` 覆盖
|
||||
- 原生 Android 聊天页右上角已改成微信式 `...` 菜单,包含 `模型 / 推理强度 / 会话信息 / 刷新`
|
||||
```
|
||||
|
||||
- [ ] **Step 4: 部署并验证公网**
|
||||
|
||||
Run:
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
./scripts/deploy-server.sh
|
||||
"$HOME/.codex/skills/boss-server-debug/scripts/server_ssh.sh" exec "curl -sS http://127.0.0.1:3000/api/health"
|
||||
curl -sS https://boss.hyzq.net/api/health
|
||||
```
|
||||
|
||||
Expected:
|
||||
|
||||
```text
|
||||
{"ok":true,...}
|
||||
{"ok":true,...}
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
cd /Users/kris/code/boss
|
||||
git add README.md docs/architecture/current_runtime_and_deploy_status_cn.md docs/architecture/api_and_service_inventory_cn.md
|
||||
git commit -m "docs: document master-agent chat controls"
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user