docs: add execution foundation implementation plan

This commit is contained in:
kris
2026-04-02 20:43:59 +08:00
parent 3a45e41b1b
commit 5e23e1d408

View File

@@ -0,0 +1,868 @@
# Boss 执行底座抽象层重构 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:** 在不改变现有生产行为的前提下,为 Boss 建立稳定的执行底座抽象层,把当前主 Agent、普通线程回复、群聊分发的底层执行职责从散落逻辑中抽出为后续接入 `ClawBackendAdapter``OmxTeamBackendAdapter` 做准备。
**Architecture:** 先新增 `src/lib/execution/` 下的接口与默认实现,再把 `boss-master-agent.ts``local-agent/server.mjs` 和关键 API route 逐步映射到这些抽象。整个过程坚持“先平移、不改行为”,所有已有主链继续沿用 `boss-state.json + master-agent queue + local-agent + codex exec resume`
**Tech Stack:** Next.js App Router、TypeScript、Node.js、文件型状态 `data/boss-state.json`、原生 `local-agent`、现有测试栈 `tsx --test`、Android/前台不改行为。
---
### Task 1: 定义执行底座类型与默认 contract
**Files:**
- Create: `/Users/kris/code/boss/src/lib/execution/types.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/execution-backend.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/orchestration-backend.ts`
- Test: `/Users/kris/code/boss/tests/execution-foundation-contracts.test.ts`
- [ ] **Step 1: 写失败测试,定义执行底座 contract 期望**
```ts
import assert from "node:assert/strict";
import test from "node:test";
import {
createExecutionRequest,
isQueuedExecutionResult,
isImmediateExecutionResult,
} from "@/lib/execution/types";
test("ExecutionRequest 工厂会生成稳定默认字段", () => {
const request = createExecutionRequest({
kind: "master_agent_reply",
projectId: "master-agent",
requestMessageId: "msg-1",
body: "你好",
});
assert.equal(request.kind, "master_agent_reply");
assert.equal(request.projectId, "master-agent");
assert.equal(request.requestMessageId, "msg-1");
assert.equal(request.body, "你好");
assert.equal(request.targetProjectId, undefined);
assert.equal(request.targetThreadId, undefined);
});
test("ExecutionResult 类型守卫能区分 queued 与 immediate", () => {
const queued = {
status: "queued",
taskId: "task-1",
backendId: "master-codex-node",
};
const completed = {
status: "completed",
backendId: "openai-api",
output: "done",
};
assert.equal(isQueuedExecutionResult(queued), true);
assert.equal(isImmediateExecutionResult(queued), false);
assert.equal(isQueuedExecutionResult(completed), false);
assert.equal(isImmediateExecutionResult(completed), true);
});
```
- [ ] **Step 2: 运行测试,确认当前失败**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-foundation-contracts.test.ts
```
Expected:
```text
ERR_MODULE_NOT_FOUND
```
- [ ] **Step 3: 写最小 contract 类型与工厂函数**
```ts
// /Users/kris/code/boss/src/lib/execution/types.ts
import type { ReasoningEffort } from "@/lib/boss-data";
export type ExecutionRequestKind =
| "master_agent_reply"
| "thread_reply"
| "dispatch_execution"
| "attachment_analysis";
export interface ExecutionRequest {
kind: ExecutionRequestKind;
projectId: string;
requestMessageId: string;
body: string;
requestedByAccount?: string;
requestedByLabel?: string;
taskId?: string;
targetThreadId?: string;
targetProjectId?: string;
modelOverride?: string;
reasoningEffortOverride?: ReasoningEffort;
}
export interface ExecutionQueuedResult {
status: "queued" | "running";
taskId: string;
backendId: string;
sessionId?: string;
}
export interface ExecutionImmediateResult {
status: "completed" | "failed";
backendId: string;
output?: string;
error?: string;
}
export interface ExecutionBackendDescription {
backendId: string;
label: string;
mode: "local" | "remote" | "api";
}
export function createExecutionRequest(input: ExecutionRequest): ExecutionRequest {
return { ...input };
}
export function isQueuedExecutionResult(
value: ExecutionQueuedResult | ExecutionImmediateResult,
): value is ExecutionQueuedResult {
return value.status === "queued" || value.status === "running";
}
export function isImmediateExecutionResult(
value: ExecutionQueuedResult | ExecutionImmediateResult,
): value is ExecutionImmediateResult {
return value.status === "completed" || value.status === "failed";
}
```
```ts
// /Users/kris/code/boss/src/lib/execution/execution-backend.ts
import type {
ExecutionBackendDescription,
ExecutionImmediateResult,
ExecutionQueuedResult,
ExecutionRequest,
} from "@/lib/execution/types";
export interface ExecutionBackend {
backendId: string;
canHandle(input: ExecutionRequest): Promise<boolean> | boolean;
execute(input: ExecutionRequest): Promise<ExecutionQueuedResult | ExecutionImmediateResult>;
describe(input: ExecutionRequest): Promise<ExecutionBackendDescription>;
}
```
```ts
// /Users/kris/code/boss/src/lib/execution/orchestration-backend.ts
export interface OrchestrationBackend {
backendId: string;
describe(): Promise<{ backendId: string; label: string }>;
}
```
- [ ] **Step 4: 再跑测试,确认 contract 生效**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-foundation-contracts.test.ts
```
Expected:
```text
# pass 2
```
- [ ] **Step 5: 提交**
```bash
cd /Users/kris/code/boss
git add tests/execution-foundation-contracts.test.ts src/lib/execution/types.ts src/lib/execution/execution-backend.ts src/lib/execution/orchestration-backend.ts
git commit -m "feat: add execution foundation contracts"
```
### Task 2: 抽离 PromptAssembler 与 MemoryResolver
**Files:**
- Create: `/Users/kris/code/boss/src/lib/execution/prompt-assembler.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/memory-resolver.ts`
- Modify: `/Users/kris/code/boss/src/lib/boss-master-agent.ts`
- Test: `/Users/kris/code/boss/tests/execution-prompt-assembler.test.ts`
- Test: `/Users/kris/code/boss/tests/execution-memory-resolver.test.ts`
- Test: `/Users/kris/code/boss/tests/master-agent-config-resolution.test.ts`
- [ ] **Step 1: 写失败测试,固定记忆筛选与 prompt 拼装顺序**
```ts
import assert from "node:assert/strict";
import test from "node:test";
import {
buildExecutionPromptForTesting,
resolveRelevantMemoriesForTesting,
} from "@/lib/execution/prompt-assembler";
test("PromptAssembler 会按固定顺序拼管理员提示词、用户提示词、对话提示词和记忆", () => {
const prompt = buildExecutionPromptForTesting({
globalPrompt: "GLOBAL",
userPrompt: "USER",
conversationPrompt: "CONVERSATION",
projectMemories: [{ title: "项目记忆", content: "PROJECT", projectId: "boss-console", tags: [] }],
userMemories: [{ title: "用户记忆", content: "USER_MEMORY", tags: [] }],
requestText: "继续",
});
assert.match(prompt, /GLOBAL/);
assert.match(prompt, /USER/);
assert.match(prompt, /CONVERSATION/);
assert.match(prompt, /PROJECT/);
assert.match(prompt, /USER_MEMORY/);
assert.ok(prompt.indexOf("GLOBAL") < prompt.indexOf("USER"));
assert.ok(prompt.indexOf("USER") < prompt.indexOf("CONVERSATION"));
});
test("MemoryResolver 在 master-agent 会话下优先挑当前请求命中的项目记忆", () => {
const resolved = resolveRelevantMemoriesForTesting({
projectId: "master-agent",
requestText: "boss-console 的审批流",
memories: [
{ memoryId: "m1", scope: "project", projectId: "boss-console", title: "审批流", content: "boss-console approval", tags: ["approval"] },
{ memoryId: "m2", scope: "project", projectId: "wenshenapp", title: "UI", content: "wechat ui", tags: ["ui"] },
],
});
assert.equal(resolved.projectMemories.length, 1);
assert.equal(resolved.projectMemories[0]?.projectId, "boss-console");
});
```
- [ ] **Step 2: 运行测试,确认当前失败**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-prompt-assembler.test.ts tests/execution-memory-resolver.test.ts
```
Expected:
```text
ERR_MODULE_NOT_FOUND
```
- [ ] **Step 3: 写最小实现,并让 boss-master-agent 改用新模块**
```ts
// /Users/kris/code/boss/src/lib/execution/memory-resolver.ts
export function resolveRelevantMemories(input: {
projectId: string;
requestText?: string;
memories: Array<{
memoryId: string;
scope: "global" | "project";
projectId?: string;
title: string;
content: string;
tags?: string[];
}>;
}) {
const lowered = input.requestText?.toLowerCase() ?? "";
const projectMemories = input.memories.filter((memory) => {
if (memory.scope !== "project") return false;
if (input.projectId !== "master-agent") {
return memory.projectId === input.projectId;
}
if (!lowered) return true;
return [memory.projectId, memory.title, memory.content, ...(memory.tags ?? [])]
.filter(Boolean)
.some((value) => value!.toLowerCase().includes(lowered) || lowered.includes(value!.toLowerCase()));
});
const userMemories = input.memories.filter((memory) => memory.scope === "global");
return {
projectMemories: projectMemories.slice(0, 6),
userMemories: userMemories.slice(0, 8),
};
}
export const resolveRelevantMemoriesForTesting = resolveRelevantMemories;
```
```ts
// /Users/kris/code/boss/src/lib/execution/prompt-assembler.ts
import { resolveRelevantMemories } from "@/lib/execution/memory-resolver";
export function buildExecutionPrompt(input: {
globalPrompt?: string | null;
userPrompt?: string | null;
conversationPrompt?: string | null;
projectMemories: Array<{ title: string; content: string; projectId?: string; tags?: string[] }>;
userMemories: Array<{ title: string; content: string; tags?: string[] }>;
requestText: string;
}) {
return [
input.globalPrompt?.trim() ? `管理员全局主提示词:\n${input.globalPrompt.trim()}` : null,
input.userPrompt?.trim() ? `用户私有主提示词:\n${input.userPrompt.trim()}` : null,
input.conversationPrompt?.trim() ? `当前对话附加提示词:\n${input.conversationPrompt.trim()}` : null,
input.projectMemories.length
? `项目记忆:\n${input.projectMemories.map((item) => `- [${item.projectId ?? "unknown"}] ${item.title}: ${item.content}`).join("\n")}`
: null,
input.userMemories.length
? `用户通用记忆:\n${input.userMemories.map((item) => `- ${item.title}: ${item.content}`).join("\n")}`
: null,
`当前消息:\n${input.requestText}`,
].filter(Boolean).join("\n\n");
}
export const buildExecutionPromptForTesting = buildExecutionPrompt;
export { resolveRelevantMemoriesForTesting } from "@/lib/execution/memory-resolver";
```
`/Users/kris/code/boss/src/lib/boss-master-agent.ts` 中,把当前内联的 memory selection 与 prompt assembly 改成调用:
```ts
import { buildExecutionPrompt } from "@/lib/execution/prompt-assembler";
import { resolveRelevantMemories } from "@/lib/execution/memory-resolver";
```
并在 `resolveMasterAgentExecutionConfig(...)` 中改成:
```ts
const memoryScope = listUserMasterMemoriesView(state, resolvedAccountId, { includeArchived: false });
const { projectMemories, userMemories } = resolveRelevantMemories({
projectId,
requestText,
memories: memoryScope,
});
const executionPrompt = buildExecutionPrompt({
globalPrompt: promptPolicy?.globalPrompt ?? null,
userPrompt: userPrompt?.content ?? null,
conversationPrompt: scopedAgentControls?.promptOverride ?? null,
projectMemories,
userMemories,
requestText: requestText ?? "",
});
```
- [ ] **Step 4: 跑新测试和既有主 Agent 测试**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-prompt-assembler.test.ts tests/execution-memory-resolver.test.ts tests/master-agent-config-resolution.test.ts
```
Expected:
```text
# pass
```
- [ ] **Step 5: 提交**
```bash
cd /Users/kris/code/boss
git add tests/execution-prompt-assembler.test.ts tests/execution-memory-resolver.test.ts tests/master-agent-config-resolution.test.ts src/lib/execution/prompt-assembler.ts src/lib/execution/memory-resolver.ts src/lib/boss-master-agent.ts
git commit -m "refactor: extract execution prompt assembly"
```
### Task 3: 抽离 PermissionPolicy 与 ToolRegistry
**Files:**
- Create: `/Users/kris/code/boss/src/lib/execution/permission-policy.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/tool-registry.ts`
- Modify: `/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/messages/route.ts`
- Modify: `/Users/kris/code/boss/src/lib/boss-data.ts`
- Test: `/Users/kris/code/boss/tests/execution-permission-policy.test.ts`
- Test: `/Users/kris/code/boss/tests/group-message-dispatch-plan.test.ts`
- Test: `/Users/kris/code/boss/tests/dispatch-plan-confirmation.test.ts`
- [ ] **Step 1: 写失败测试,固定 approval_required 和 tool policy 语义**
```ts
import assert from "node:assert/strict";
import test from "node:test";
import { evaluatePermissionPolicyForTesting } from "@/lib/execution/permission-policy";
test("approval_required 群聊在已有待确认推荐时拒绝继续直接执行", () => {
const result = evaluatePermissionPolicyForTesting({
project: {
id: "group-1",
isGroup: true,
collaborationMode: "approval_required",
approvalState: "pending_user",
},
hasPendingDispatchPlan: true,
});
assert.equal(result.allowed, false);
assert.equal(result.requiresApproval, true);
assert.match(result.reason ?? "", /等待确认/);
});
```
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-permission-policy.test.ts
```
Expected:
```text
ERR_MODULE_NOT_FOUND
```
- [ ] **Step 3: 写权限策略与工具注册最小实现,并在消息 route 中复用**
```ts
// /Users/kris/code/boss/src/lib/execution/permission-policy.ts
export function evaluatePermissionPolicy(input: {
project?: {
id: string;
isGroup: boolean;
collaborationMode: "development" | "approval_required";
approvalState: "not_required" | "pending_agent" | "pending_user" | "approved" | "rejected";
};
hasPendingDispatchPlan?: boolean;
}) {
const project = input.project;
if (!project) {
return {
allowed: true,
requiresApproval: false,
toolPolicy: { allowedTools: [], deniedTools: [] },
collaborationPolicy: {
mode: "development" as const,
canDispatchDirectly: true,
canCrossThreadTalk: true,
},
};
}
if (project.isGroup && project.collaborationMode === "approval_required" && input.hasPendingDispatchPlan) {
return {
allowed: false,
requiresApproval: true,
reason: "当前还有一条主 Agent 推荐等待确认,请先确认或拒绝后再继续发送新指令。",
toolPolicy: { allowedTools: [], deniedTools: ["dispatch_execution"] },
collaborationPolicy: {
mode: "approval_required" as const,
canDispatchDirectly: false,
canCrossThreadTalk: false,
},
};
}
return {
allowed: true,
requiresApproval: project.isGroup && project.collaborationMode === "approval_required",
toolPolicy: { allowedTools: ["conversation_reply", "dispatch_execution"], deniedTools: [] },
collaborationPolicy: {
mode: project.collaborationMode,
canDispatchDirectly: project.collaborationMode === "development",
canCrossThreadTalk: project.collaborationMode === "development",
},
};
}
export const evaluatePermissionPolicyForTesting = evaluatePermissionPolicy;
```
```ts
// /Users/kris/code/boss/src/lib/execution/tool-registry.ts
export function listExecutionTools() {
return [
{ name: "conversation_reply", kind: "execution" },
{ name: "dispatch_execution", kind: "execution" },
{ name: "attachment_analysis", kind: "analysis" },
] as const;
}
```
`/Users/kris/code/boss/src/app/api/v1/projects/[projectId]/messages/route.ts` 中,把 `approval_required + pending plan` 判断替换成:
```ts
const permission = evaluatePermissionPolicy({
project,
hasPendingDispatchPlan: Boolean(pendingPlan),
});
if (!permission.allowed) {
return NextResponse.json(
{
ok: false,
message: permission.reason,
pendingPlan,
collaborationGate: buildCollaborationGate(project),
},
{ status: 409 },
);
}
```
- [ ] **Step 4: 跑权限测试与现有 dispatch 测试**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-permission-policy.test.ts tests/group-message-dispatch-plan.test.ts tests/dispatch-plan-confirmation.test.ts
```
Expected:
```text
# pass
```
- [ ] **Step 5: 提交**
```bash
cd /Users/kris/code/boss
git add tests/execution-permission-policy.test.ts tests/group-message-dispatch-plan.test.ts tests/dispatch-plan-confirmation.test.ts src/lib/execution/permission-policy.ts src/lib/execution/tool-registry.ts src/app/api/v1/projects/[projectId]/messages/route.ts
git commit -m "refactor: extract execution permission policy"
```
### Task 4: 抽离 ExecutionBackendSelector 与默认执行后端
**Files:**
- Create: `/Users/kris/code/boss/src/lib/execution/backend-selector.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/backends/master-codex-node-backend.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/backends/openai-backend.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/backends/aliyun-qwen-backend.ts`
- Modify: `/Users/kris/code/boss/src/lib/boss-master-agent.ts`
- Test: `/Users/kris/code/boss/tests/execution-backend-selector.test.ts`
- Test: `/Users/kris/code/boss/tests/master-agent-openai-fallback.test.ts`
- Test: `/Users/kris/code/boss/tests/master-agent-message-queue.test.ts`
- [ ] **Step 1: 写失败测试,固定后端选择优先级**
```ts
import assert from "node:assert/strict";
import test from "node:test";
import { selectExecutionBackendForTesting } from "@/lib/execution/backend-selector";
test("主控可用时优先选择当前主控 backend", async () => {
const backend = await selectExecutionBackendForTesting({
primary: { provider: "master_codex_node", status: "ready" },
backups: [{ provider: "aliyun_qwen_api", status: "ready" }],
});
assert.equal(backend.backendId, "master-codex-node");
});
test("主控 degraded 时回退到可用阿里备用 backend", async () => {
const backend = await selectExecutionBackendForTesting({
primary: { provider: "master_codex_node", status: "degraded" },
backups: [{ provider: "aliyun_qwen_api", status: "ready" }],
});
assert.equal(backend.backendId, "aliyun-qwen");
});
```
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-backend-selector.test.ts
```
Expected:
```text
ERR_MODULE_NOT_FOUND
```
- [ ] **Step 3: 写 selector 和默认 backend 壳,并让 boss-master-agent 通过 selector 取 backend**
```ts
// /Users/kris/code/boss/src/lib/execution/backend-selector.ts
export async function selectExecutionBackend(input: {
primary: { provider: string; status: string };
backups: Array<{ provider: string; status: string }>;
}) {
if (input.primary.provider === "master_codex_node" && input.primary.status === "ready") {
return { backendId: "master-codex-node" };
}
const qwen = input.backups.find((item) => item.provider === "aliyun_qwen_api" && item.status === "ready");
if (qwen) {
return { backendId: "aliyun-qwen" };
}
const openai = input.backups.find((item) => item.provider === "openai_api" && item.status === "ready");
if (openai) {
return { backendId: "openai-api" };
}
return { backendId: "master-codex-node" };
}
export const selectExecutionBackendForTesting = selectExecutionBackend;
```
`/Users/kris/code/boss/src/lib/boss-master-agent.ts` 中,把 provider fallback 的选择逻辑收进一个单独调用:
```ts
const selectedBackend = await selectExecutionBackend({
primary: { provider: runtime.account.provider, status: runtime.account.status },
backups: state.aiAccounts
.filter((item) => item.accountId !== runtime.account.accountId)
.map((item) => ({ provider: item.provider, status: item.status })),
});
```
并让后续 provider-specific 分支改成按 `selectedBackend.backendId` 分派,而不是继续直接拼条件。
- [ ] **Step 4: 跑 selector 测试和既有 fallback 测试**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/execution-backend-selector.test.ts tests/master-agent-openai-fallback.test.ts tests/master-agent-message-queue.test.ts
```
Expected:
```text
# pass
```
- [ ] **Step 5: 提交**
```bash
cd /Users/kris/code/boss
git add tests/execution-backend-selector.test.ts tests/master-agent-openai-fallback.test.ts tests/master-agent-message-queue.test.ts src/lib/execution/backend-selector.ts src/lib/execution/backends/master-codex-node-backend.ts src/lib/execution/backends/openai-backend.ts src/lib/execution/backends/aliyun-qwen-backend.ts src/lib/boss-master-agent.ts
git commit -m "refactor: add execution backend selector"
```
### Task 5: 抽离 RemoteRuntimeAdapter 与 OrchestrationBackend
**Files:**
- Create: `/Users/kris/code/boss/src/lib/execution/remote-runtime-adapter.ts`
- Create: `/Users/kris/code/boss/src/lib/execution/backends/boss-native-orchestrator.ts`
- Modify: `/Users/kris/code/boss/local-agent/server.mjs`
- Modify: `/Users/kris/code/boss/src/app/api/v1/master-agent/tasks/[taskId]/complete/route.ts`
- Test: `/Users/kris/code/boss/tests/remote-runtime-adapter.test.ts`
- Test: `/Users/kris/code/boss/tests/dispatch-execution-result.test.ts`
- Test: `/Users/kris/code/boss/tests/local-agent-codex-task-runner.test.mjs`
- [ ] **Step 1: 写失败测试,固定远程执行结果和编排分层**
```ts
import assert from "node:assert/strict";
import test from "node:test";
import { normalizeRemoteExecutionResultForTesting } from "@/lib/execution/remote-runtime-adapter";
test("RemoteRuntimeAdapter 会把 local-agent 回写标准化成统一结果", () => {
const normalized = normalizeRemoteExecutionResultForTesting({
status: "completed",
dispatchExecutionId: "dx-1",
targetProjectId: "project-1",
targetThreadId: "thread-1",
rawThreadReply: "链路正常",
});
assert.equal(normalized.status, "completed");
assert.equal(normalized.targetProjectId, "project-1");
assert.equal(normalized.rawThreadReply, "链路正常");
});
```
- [ ] **Step 2: 运行测试确认失败**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/remote-runtime-adapter.test.ts
```
Expected:
```text
ERR_MODULE_NOT_FOUND
```
- [ ] **Step 3: 写最小 adapter并让 complete route 和 local-agent 对齐这个结构**
```ts
// /Users/kris/code/boss/src/lib/execution/remote-runtime-adapter.ts
export function normalizeRemoteExecutionResult(input: {
status: "completed" | "failed";
dispatchExecutionId?: string;
targetProjectId?: string;
targetThreadId?: string;
rawThreadReply?: string;
replyBody?: string;
errorMessage?: string;
}) {
return {
status: input.status,
dispatchExecutionId: input.dispatchExecutionId,
targetProjectId: input.targetProjectId,
targetThreadId: input.targetThreadId,
rawThreadReply: input.rawThreadReply,
replyBody: input.replyBody,
errorMessage: input.errorMessage,
};
}
export const normalizeRemoteExecutionResultForTesting = normalizeRemoteExecutionResult;
```
`/Users/kris/code/boss/src/app/api/v1/master-agent/tasks/[taskId]/complete/route.ts` 中增加:
```ts
import { normalizeRemoteExecutionResult } from "@/lib/execution/remote-runtime-adapter";
```
并把 body 传入 `completeMasterAgentTask` 前先标准化:
```ts
const normalized = normalizeRemoteExecutionResult(body);
```
`/Users/kris/code/boss/local-agent/server.mjs` 中,把 `conversation_reply / dispatch_execution` 结果拼装收进一个小 helper输出结构与 `normalizeRemoteExecutionResult` 对齐。
- [ ] **Step 4: 跑 adapter 测试和既有 dispatch/local-agent 测试**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test tests/remote-runtime-adapter.test.ts tests/dispatch-execution-result.test.ts
node --test tests/local-agent-codex-task-runner.test.mjs
```
Expected:
```text
# pass
```
- [ ] **Step 5: 提交**
```bash
cd /Users/kris/code/boss
git add tests/remote-runtime-adapter.test.ts tests/dispatch-execution-result.test.ts tests/local-agent-codex-task-runner.test.mjs src/lib/execution/remote-runtime-adapter.ts src/lib/execution/backends/boss-native-orchestrator.ts src/app/api/v1/master-agent/tasks/[taskId]/complete/route.ts local-agent/server.mjs
git commit -m "refactor: add remote runtime adapter"
```
### 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: 跑本轮完整验证矩阵**
Run:
```bash
cd /Users/kris/code/boss
npx --yes tsx --test \
tests/execution-foundation-contracts.test.ts \
tests/execution-prompt-assembler.test.ts \
tests/execution-memory-resolver.test.ts \
tests/execution-permission-policy.test.ts \
tests/execution-backend-selector.test.ts \
tests/remote-runtime-adapter.test.ts \
tests/master-agent-config-resolution.test.ts \
tests/master-agent-openai-fallback.test.ts \
tests/master-agent-message-queue.test.ts \
tests/group-message-dispatch-plan.test.ts \
tests/dispatch-plan-confirmation.test.ts \
tests/dispatch-execution-result.test.ts
node --test tests/local-agent-codex-task-runner.test.mjs
npm run lint
npm run build
```
Expected:
```text
All tests pass
Next.js build succeeds
```
- [ ] **Step 2: 更新文档,说明执行底座抽象层已落地,但不改变生产主链**
在文档中至少补下面这些事实:
```md
- 当前 Boss 已新增 `src/lib/execution/` 执行底座抽象层
- 当前生产主链仍然沿用 `local-agent -> codex exec resume`
- 当前已完成 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 的默认实现
- 当前 `claw-code``oh-my-codex` 尚未正式接入生产链,只是 contract ready
```
- [ ] **Step 3: 再跑一次 lint/build 确认文档与代码最终状态一致**
Run:
```bash
cd /Users/kris/code/boss
npm run lint
npm run build
```
Expected:
```text
No new errors
```
- [ ] **Step 4: 提交**
```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: record execution foundation refactor"
```
## Self-Review
### Spec coverage
- 已覆盖执行底座抽象层总目标
- 已覆盖 `ExecutionBackend / Selector / SessionRuntime / PermissionPolicy / ToolRegistry / PromptAssembler / MemoryResolver / RemoteRuntimeAdapter / OrchestrationBackend`
- 已覆盖现有主链不变的约束
- 已覆盖后续接 `claw-code / oh-my-codex` 前的 contract-ready 目标
### Placeholder scan
-`TODO / TBD / implement later`
- 每个任务都给了明确文件、测试、命令和 commit 边界
### Type consistency
- `ExecutionRequest / ExecutionQueuedResult / ExecutionImmediateResult / PermissionCheckResult` 在各任务中保持一致
- `ExecutionBackend``OrchestrationBackend` 已分层,没有混用
## Execution Handoff
Plan complete and saved to `/Users/kris/code/boss/docs/superpowers/plans/2026-04-02-boss-execution-foundation.md`. Two execution options:
**1. Subagent-Driven (recommended)** - I dispatch a fresh subagent per task, review between tasks, fast iteration
**2. Inline Execution** - Execute tasks in this session using executing-plans, batch execution with checkpoints
**Which approach?**