chore: add claw smoke runtime sample
This commit is contained in:
20
.env.server.example
Normal file
20
.env.server.example
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
BOSS_AUTH_VERIFICATION_MODE=fixed
|
||||||
|
BOSS_AUTH_FIXED_CODE=000000
|
||||||
|
BOSS_STATE_FILE=/opt/boss/data/boss-state.json
|
||||||
|
|
||||||
|
# 切到真实邮件验证码时,改成:
|
||||||
|
# BOSS_AUTH_VERIFICATION_MODE=email
|
||||||
|
# BOSS_AUTH_FIXED_CODE=
|
||||||
|
|
||||||
|
BOSS_MAIL_DOMAIN=boss.hyzq.net
|
||||||
|
BOSS_MAIL_FROM_ADDRESS=verify@boss.hyzq.net
|
||||||
|
BOSS_MAIL_FROM_NAME=Boss Verify
|
||||||
|
BOSS_SENDMAIL_PATH=/usr/sbin/sendmail
|
||||||
|
|
||||||
|
# 可选:启用 ClawBackendAdapter(默认关闭)
|
||||||
|
# BOSS_CLAW_ENABLED=true
|
||||||
|
# BOSS_CLAW_COMMAND=node
|
||||||
|
# BOSS_CLAW_ARGS=scripts/claw-runtime-smoke.mjs
|
||||||
|
# BOSS_CLAW_WORKDIR=/opt/boss
|
||||||
|
# BOSS_CLAW_TIMEOUT_MS=45000
|
||||||
|
# BOSS_CLAW_DEFAULT_MODEL=gpt-5.4
|
||||||
@@ -59,6 +59,7 @@
|
|||||||
- 当前 Boss 已新增 `src/lib/execution/` 执行底座抽象层;当前生产主链仍然沿用 `local-agent -> codex exec resume`,只是执行责任已开始通过 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 默认实现收束
|
- 当前 Boss 已新增 `src/lib/execution/` 执行底座抽象层;当前生产主链仍然沿用 `local-agent -> codex exec resume`,只是执行责任已开始通过 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 默认实现收束
|
||||||
- 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有在显式配置 `BOSS_CLAW_*` 并在 `master-agent` 当前对话里显式选择 `claw-runtime` 时才会参与执行候选
|
- 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有在显式配置 `BOSS_CLAW_*` 并在 `master-agent` 当前对话里显式选择 `claw-runtime` 时才会参与执行候选
|
||||||
- 当前 `oh-my-codex` 仍未正式接入生产执行链;当前状态是 orchestration-ready,后续将通过独立 adapter 接入
|
- 当前 `oh-my-codex` 仍未正式接入生产执行链;当前状态是 orchestration-ready,后续将通过独立 adapter 接入
|
||||||
|
- 当前仓库已自带一个本地 smoke runtime:`scripts/claw-runtime-smoke.mjs`。在还没有真实 `claw-code` 可执行文件时,可以先用它验证 `ClawBackendAdapter -> backendOverride -> 异步回流` 整条链
|
||||||
- `GET http://127.0.0.1:4317/api/v1/skills` 正常,已返回本机扫描到的 Codex Skill
|
- `GET http://127.0.0.1:4317/api/v1/skills` 正常,已返回本机扫描到的 Codex Skill
|
||||||
- `POST http://127.0.0.1:4317/api/v1/heartbeat` 正常,且会顺带触发 `thread-context` 上报
|
- `POST http://127.0.0.1:4317/api/v1/heartbeat` 正常,且会顺带触发 `thread-context` 上报
|
||||||
- `launchd` 已加载:`~/Library/LaunchAgents/com.hyzq.boss.local-agent.plist`
|
- `launchd` 已加载:`~/Library/LaunchAgents/com.hyzq.boss.local-agent.plist`
|
||||||
|
|||||||
@@ -178,6 +178,7 @@
|
|||||||
- 已在生产代码中被 `boss-master-agent.ts`、`local-agent/server.mjs` 和 `master-agent task complete route` 使用
|
- 已在生产代码中被 `boss-master-agent.ts`、`local-agent/server.mjs` 和 `master-agent task complete route` 使用
|
||||||
- 当前仍服务 Boss 自身执行链
|
- 当前仍服务 Boss 自身执行链
|
||||||
- 当前已最小接入 `ClawBackendAdapter`,但默认关闭,仅在显式配置和显式选择时参与执行
|
- 当前已最小接入 `ClawBackendAdapter`,但默认关闭,仅在显式配置和显式选择时参与执行
|
||||||
|
- 当前仓库自带 `scripts/claw-runtime-smoke.mjs` 作为兼容 JSON 协议的 smoke runtime,可用于本地和服务器验证 `ClawBackendAdapter`
|
||||||
- 当前尚未接入 `oh-my-codex`
|
- 当前尚未接入 `oh-my-codex`
|
||||||
|
|
||||||
### 3.2 认证相关
|
### 3.2 认证相关
|
||||||
|
|||||||
@@ -29,6 +29,7 @@
|
|||||||
- 当前执行底座抽象层已落地在 `src/lib/execution/`,并已补齐 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 默认实现
|
- 当前执行底座抽象层已落地在 `src/lib/execution/`,并已补齐 `ExecutionBackend / PromptAssembler / PermissionPolicy / RemoteRuntimeAdapter / OrchestrationBackend` 默认实现
|
||||||
- 当前生产主链仍然沿用 `local-agent -> codex exec resume -> /api/v1/master-agent/tasks/[taskId]/complete`,执行底座重构以“先抽象、不改行为”为准
|
- 当前生产主链仍然沿用 `local-agent -> codex exec resume -> /api/v1/master-agent/tasks/[taskId]/complete`,执行底座重构以“先抽象、不改行为”为准
|
||||||
- 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有显式配置 `BOSS_CLAW_*` 并在 `master-agent` 当前对话中选择 `claw-runtime` 时才会参与执行候选
|
- 当前 `claw-code` 已以最小 `ClawBackendAdapter` 形式接入执行底座,但默认关闭;只有显式配置 `BOSS_CLAW_*` 并在 `master-agent` 当前对话中选择 `claw-runtime` 时才会参与执行候选
|
||||||
|
- 当前仓库已自带 `scripts/claw-runtime-smoke.mjs` 作为本地 smoke runtime;在没有真实 `claw-code` 可执行文件时,可先用 `BOSS_CLAW_COMMAND=node` 与 `BOSS_CLAW_ARGS=scripts/claw-runtime-smoke.mjs` 验证整条链
|
||||||
- 当前 `oh-my-codex` 还未正式接入生产链,只是已经具备 orchestration adapter-ready 的 contract 基础
|
- 当前 `oh-my-codex` 还未正式接入生产链,只是已经具备 orchestration adapter-ready 的 contract 基础
|
||||||
|
|
||||||
本地已知运行方式:
|
本地已知运行方式:
|
||||||
|
|||||||
62
scripts/claw-runtime-smoke.mjs
Normal file
62
scripts/claw-runtime-smoke.mjs
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
function writeJson(payload) {
|
||||||
|
process.stdout.write(`${JSON.stringify(payload)}\n`);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function readStdin() {
|
||||||
|
const chunks = [];
|
||||||
|
for await (const chunk of process.stdin) {
|
||||||
|
chunks.push(typeof chunk === "string" ? chunk : chunk.toString("utf8"));
|
||||||
|
}
|
||||||
|
return chunks.join("").trim();
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalizePayload(raw) {
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
error: "INVALID_CLAW_PAYLOAD: expected object",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ok: true,
|
||||||
|
payload: parsed,
|
||||||
|
};
|
||||||
|
} catch {
|
||||||
|
return {
|
||||||
|
ok: false,
|
||||||
|
error: "INVALID_CLAW_PAYLOAD: invalid json",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const raw = await readStdin();
|
||||||
|
const normalized = normalizePayload(raw);
|
||||||
|
|
||||||
|
if (!normalized.ok) {
|
||||||
|
writeJson({
|
||||||
|
status: "failed",
|
||||||
|
error: normalized.error,
|
||||||
|
});
|
||||||
|
process.exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
const payload = normalized.payload;
|
||||||
|
const requestKind = typeof payload.requestKind === "string" ? payload.requestKind : "unknown";
|
||||||
|
const model = typeof payload.model === "string" && payload.model.trim() ? payload.model.trim() : "default";
|
||||||
|
const reasoningEffort =
|
||||||
|
typeof payload.reasoningEffort === "string" && payload.reasoningEffort.trim()
|
||||||
|
? payload.reasoningEffort.trim()
|
||||||
|
: "default";
|
||||||
|
const executionPrompt =
|
||||||
|
typeof payload.executionPrompt === "string" && payload.executionPrompt.trim()
|
||||||
|
? payload.executionPrompt.trim()
|
||||||
|
: "链路正常";
|
||||||
|
|
||||||
|
writeJson({
|
||||||
|
status: "completed",
|
||||||
|
output: `Claw smoke completed: ${executionPrompt} (kind=${requestKind}, model=${model}, reasoning=${reasoningEffort})`,
|
||||||
|
});
|
||||||
61
tests/claw-runtime-smoke-script.test.ts
Normal file
61
tests/claw-runtime-smoke-script.test.ts
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
import test from "node:test";
|
||||||
|
import assert from "node:assert/strict";
|
||||||
|
import path from "node:path";
|
||||||
|
import { spawn } from "node:child_process";
|
||||||
|
|
||||||
|
function runSmoke(payload: unknown) {
|
||||||
|
return new Promise<{
|
||||||
|
exitCode: number | null;
|
||||||
|
stdout: string;
|
||||||
|
stderr: string;
|
||||||
|
}>((resolve, reject) => {
|
||||||
|
const scriptPath = path.resolve("scripts/claw-runtime-smoke.mjs");
|
||||||
|
const child = spawn(process.execPath, [scriptPath], {
|
||||||
|
cwd: "/Users/kris/code/boss",
|
||||||
|
stdio: ["pipe", "pipe", "pipe"],
|
||||||
|
});
|
||||||
|
|
||||||
|
let stdout = "";
|
||||||
|
let stderr = "";
|
||||||
|
child.stdout.setEncoding("utf8");
|
||||||
|
child.stderr.setEncoding("utf8");
|
||||||
|
child.stdout.on("data", (chunk) => {
|
||||||
|
stdout += chunk;
|
||||||
|
});
|
||||||
|
child.stderr.on("data", (chunk) => {
|
||||||
|
stderr += chunk;
|
||||||
|
});
|
||||||
|
child.on("error", reject);
|
||||||
|
child.on("close", (exitCode) => {
|
||||||
|
resolve({ exitCode, stdout, stderr });
|
||||||
|
});
|
||||||
|
|
||||||
|
child.stdin.write(JSON.stringify(payload));
|
||||||
|
child.stdin.end();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
test("claw runtime smoke script emits completed JSON for valid payload", async () => {
|
||||||
|
const result = await runSmoke({
|
||||||
|
requestKind: "master_agent_reply",
|
||||||
|
executionPrompt: "请回复链路正常",
|
||||||
|
model: "gpt-5.4",
|
||||||
|
reasoningEffort: "medium",
|
||||||
|
});
|
||||||
|
|
||||||
|
assert.equal(result.exitCode, 0);
|
||||||
|
assert.equal(result.stderr, "");
|
||||||
|
const parsed = JSON.parse(result.stdout);
|
||||||
|
assert.equal(parsed.status, "completed");
|
||||||
|
assert.match(parsed.output, /链路正常/);
|
||||||
|
assert.match(parsed.output, /gpt-5\.4/);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("claw runtime smoke script emits failed JSON for invalid payload", async () => {
|
||||||
|
const result = await runSmoke("not-an-object");
|
||||||
|
|
||||||
|
assert.equal(result.exitCode, 0);
|
||||||
|
const parsed = JSON.parse(result.stdout);
|
||||||
|
assert.equal(parsed.status, "failed");
|
||||||
|
assert.match(parsed.error, /INVALID_CLAW_PAYLOAD/);
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user