refactor: standardize level names across all roles (#195 phase 1)
Rename levels to use consistent industry-standard terminology: - dev: medior → mid - qa: reviewer → mid, tester → junior, add senior level - architect: opus → senior, sonnet → junior Add backward-compatible migration for projects.json and openclaw.json config via level aliases in selectors and projects parser. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -102,7 +102,7 @@ export function createAutoConfigureModelsTool(api: OpenClawPluginApi) {
|
||||
if (modelCount === 1) {
|
||||
message += "ℹ️ Only one authenticated model found — assigned to all roles.";
|
||||
} else {
|
||||
message += "ℹ️ Models assigned by capability tier (Tier 1 → senior, Tier 2 → medior/reviewer, Tier 3 → junior/tester).";
|
||||
message += "ℹ️ Models assigned by capability tier (Tier 1 → senior, Tier 2 → mid, Tier 3 → junior).";
|
||||
}
|
||||
|
||||
if (preferProvider) {
|
||||
|
||||
@@ -14,29 +14,31 @@ import {
|
||||
|
||||
describe("architect tiers", () => {
|
||||
it("should recognize architect levels", () => {
|
||||
assert.strictEqual(isArchitectLevel("opus"), true);
|
||||
assert.strictEqual(isArchitectLevel("sonnet"), true);
|
||||
assert.strictEqual(isArchitectLevel("medior"), false);
|
||||
assert.strictEqual(isArchitectLevel("junior"), true);
|
||||
assert.strictEqual(isArchitectLevel("senior"), true);
|
||||
assert.strictEqual(isArchitectLevel("mid"), false);
|
||||
});
|
||||
|
||||
it("should map architect levels to role", () => {
|
||||
assert.strictEqual(levelRole("opus"), "architect");
|
||||
assert.strictEqual(levelRole("sonnet"), "architect");
|
||||
// "junior" and "senior" appear in dev first (registry order), so roleForLevel returns "dev"
|
||||
// This is expected — use isArchitectLevel for architect-specific checks
|
||||
assert.strictEqual(levelRole("junior"), "dev");
|
||||
assert.strictEqual(levelRole("senior"), "dev");
|
||||
});
|
||||
|
||||
it("should resolve default architect models", () => {
|
||||
assert.strictEqual(defaultModel("architect", "opus"), "anthropic/claude-opus-4-5");
|
||||
assert.strictEqual(defaultModel("architect", "sonnet"), "anthropic/claude-sonnet-4-5");
|
||||
assert.strictEqual(defaultModel("architect", "senior"), "anthropic/claude-opus-4-5");
|
||||
assert.strictEqual(defaultModel("architect", "junior"), "anthropic/claude-sonnet-4-5");
|
||||
});
|
||||
|
||||
it("should resolve architect model from config", () => {
|
||||
const config = { models: { architect: { opus: "custom/model" } } };
|
||||
assert.strictEqual(resolveModel("architect", "opus", config), "custom/model");
|
||||
const config = { models: { architect: { senior: "custom/model" } } };
|
||||
assert.strictEqual(resolveModel("architect", "senior", config), "custom/model");
|
||||
});
|
||||
|
||||
it("should have architect emoji", () => {
|
||||
assert.strictEqual(levelEmoji("architect", "opus"), "🏗️");
|
||||
assert.strictEqual(levelEmoji("architect", "sonnet"), "📐");
|
||||
assert.strictEqual(levelEmoji("architect", "senior"), "🏗️");
|
||||
assert.strictEqual(levelEmoji("architect", "junior"), "📐");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -81,25 +83,25 @@ describe("architect workflow states", () => {
|
||||
});
|
||||
|
||||
describe("architect model selection", () => {
|
||||
it("should select sonnet for standard design tasks", () => {
|
||||
it("should select junior for standard design tasks", () => {
|
||||
const result = selectLevel("Design: Add caching layer", "Simple caching strategy", "architect");
|
||||
assert.strictEqual(result.level, "sonnet");
|
||||
assert.strictEqual(result.level, "junior");
|
||||
});
|
||||
|
||||
it("should select opus for complex design tasks", () => {
|
||||
it("should select senior for complex design tasks", () => {
|
||||
const result = selectLevel("Design: System-wide refactor", "Major migration and redesign of the architecture", "architect");
|
||||
assert.strictEqual(result.level, "opus");
|
||||
assert.strictEqual(result.level, "senior");
|
||||
});
|
||||
});
|
||||
|
||||
describe("architect session key parsing", () => {
|
||||
it("should parse architect session key", () => {
|
||||
const result = parseDevClawSessionKey("agent:devclaw:subagent:my-project-architect-opus");
|
||||
const result = parseDevClawSessionKey("agent:devclaw:subagent:my-project-architect-senior");
|
||||
assert.deepStrictEqual(result, { projectName: "my-project", role: "architect" });
|
||||
});
|
||||
|
||||
it("should parse architect sonnet session key", () => {
|
||||
const result = parseDevClawSessionKey("agent:devclaw:subagent:webapp-architect-sonnet");
|
||||
it("should parse architect junior session key", () => {
|
||||
const result = parseDevClawSessionKey("agent:devclaw:subagent:webapp-architect-junior");
|
||||
assert.deepStrictEqual(result, { projectName: "webapp", role: "architect" });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -58,7 +58,7 @@ Example:
|
||||
complexity: {
|
||||
type: "string",
|
||||
enum: ["simple", "medium", "complex"],
|
||||
description: "Suggests architect level: simple/medium → sonnet, complex → opus. Defaults to medium.",
|
||||
description: "Suggests architect level: simple/medium → junior, complex → senior. Defaults to medium.",
|
||||
},
|
||||
dryRun: {
|
||||
type: "boolean",
|
||||
@@ -110,7 +110,7 @@ Example:
|
||||
});
|
||||
|
||||
// Select level based on complexity
|
||||
const level = complexity === "complex" ? "opus" : "sonnet";
|
||||
const level = complexity === "complex" ? "senior" : "junior";
|
||||
|
||||
if (dryRun) {
|
||||
return jsonResult({
|
||||
|
||||
@@ -8,7 +8,8 @@ import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
|
||||
import { jsonResult } from "openclaw/plugin-sdk";
|
||||
import type { ToolContext } from "../types.js";
|
||||
import { runSetup, type SetupOpts } from "../setup/index.js";
|
||||
import { DEV_LEVELS, QA_LEVELS, DEFAULT_MODELS } from "../tiers.js";
|
||||
import { DEFAULT_MODELS } from "../tiers.js";
|
||||
import { getLevelsForRole } from "../roles/index.js";
|
||||
|
||||
export function createSetupTool(api: OpenClawPluginApi) {
|
||||
return (ctx: ToolContext) => ({
|
||||
@@ -45,9 +46,9 @@ export function createSetupTool(api: OpenClawPluginApi) {
|
||||
type: "string",
|
||||
description: `Default: ${DEFAULT_MODELS.dev.junior}`,
|
||||
},
|
||||
medior: {
|
||||
mid: {
|
||||
type: "string",
|
||||
description: `Default: ${DEFAULT_MODELS.dev.medior}`,
|
||||
description: `Default: ${DEFAULT_MODELS.dev.mid}`,
|
||||
},
|
||||
senior: {
|
||||
type: "string",
|
||||
@@ -59,13 +60,17 @@ export function createSetupTool(api: OpenClawPluginApi) {
|
||||
type: "object",
|
||||
description: "QA level models",
|
||||
properties: {
|
||||
reviewer: {
|
||||
junior: {
|
||||
type: "string",
|
||||
description: `Default: ${DEFAULT_MODELS.qa.reviewer}`,
|
||||
description: `Default: ${DEFAULT_MODELS.qa.junior}`,
|
||||
},
|
||||
tester: {
|
||||
mid: {
|
||||
type: "string",
|
||||
description: `Default: ${DEFAULT_MODELS.qa.tester}`,
|
||||
description: `Default: ${DEFAULT_MODELS.qa.mid}`,
|
||||
},
|
||||
senior: {
|
||||
type: "string",
|
||||
description: `Default: ${DEFAULT_MODELS.qa.senior}`,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -109,8 +114,9 @@ export function createSetupTool(api: OpenClawPluginApi) {
|
||||
}
|
||||
lines.push(
|
||||
"Models:",
|
||||
...DEV_LEVELS.map((t) => ` dev.${t}: ${result.models.dev[t]}`),
|
||||
...QA_LEVELS.map((t) => ` qa.${t}: ${result.models.qa[t]}`),
|
||||
...getLevelsForRole("dev").map((t) => ` dev.${t}: ${result.models.dev[t]}`),
|
||||
...getLevelsForRole("qa").map((t) => ` qa.${t}: ${result.models.qa[t]}`),
|
||||
...getLevelsForRole("architect").map((t) => ` architect.${t}: ${result.models.architect[t]}`),
|
||||
"",
|
||||
);
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ export function createWorkStartTool(api: OpenClawPluginApi) {
|
||||
projectGroupId: { type: "string", description: "Project group ID." },
|
||||
issueId: { type: "number", description: "Issue ID. If omitted, picks next by priority." },
|
||||
role: { type: "string", enum: getAllRoleIds(), description: "Worker role. Auto-detected from label if omitted." },
|
||||
level: { type: "string", description: "Developer level (junior/medior/senior/reviewer). Auto-detected if omitted." },
|
||||
level: { type: "string", description: "Worker level (junior/mid/senior). Auto-detected if omitted." },
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
Reference in New Issue
Block a user