Align MCP/CLI naming and resolve default model/mode server-side (#291)
* Align create_agent naming and resolve defaults server-side * Fix test assertions for default model/mode resolution - Use config.model and config.modeId instead of non-existent snapshot.model - Strip legacy "default" model ID in normalizeConfig - Update runtimeInfo assertion to expect resolved default model * Fix CI: update CLI test for --title, fix formatting in checkout-git
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import { Command } from "commander";
|
import { Command, Option } from "commander";
|
||||||
import {
|
import {
|
||||||
getStructuredAgentResponse,
|
getStructuredAgentResponse,
|
||||||
StructuredAgentResponseError,
|
StructuredAgentResponseError,
|
||||||
@@ -22,7 +22,8 @@ export function addRunOptions(cmd: Command): Command {
|
|||||||
.description("Create and start an agent with a task")
|
.description("Create and start an agent with a task")
|
||||||
.argument("<prompt>", "The task/prompt for the agent")
|
.argument("<prompt>", "The task/prompt for the agent")
|
||||||
.option("-d, --detach", "Run in background (detached)")
|
.option("-d, --detach", "Run in background (detached)")
|
||||||
.option("--name <name>", "Assign a name/title to the agent")
|
.option("--title <title>", "Assign a title to the agent")
|
||||||
|
.addOption(new Option("--name <name>", "Hidden alias for --title").hideHelp())
|
||||||
.option(
|
.option(
|
||||||
"--provider <provider>",
|
"--provider <provider>",
|
||||||
"Agent provider, or provider/model (e.g. codex or codex/gpt-5.4)",
|
"Agent provider, or provider/model (e.g. codex or codex/gpt-5.4)",
|
||||||
@@ -82,6 +83,7 @@ export const agentRunSchema: OutputSchema<AgentRunResult> = {
|
|||||||
|
|
||||||
export interface AgentRunOptions extends CommandOptions {
|
export interface AgentRunOptions extends CommandOptions {
|
||||||
detach?: boolean;
|
detach?: boolean;
|
||||||
|
title?: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
provider?: string;
|
provider?: string;
|
||||||
model?: string;
|
model?: string;
|
||||||
@@ -325,6 +327,7 @@ export async function runRunCommand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resolvedProviderModel = resolveProviderAndModel(options);
|
const resolvedProviderModel = resolveProviderAndModel(options);
|
||||||
|
const resolvedTitle = options.title ?? options.name;
|
||||||
|
|
||||||
let client;
|
let client;
|
||||||
try {
|
try {
|
||||||
@@ -414,7 +417,7 @@ export async function runRunCommand(
|
|||||||
structuredAgent = await client.createAgent({
|
structuredAgent = await client.createAgent({
|
||||||
provider: resolvedProviderModel.provider,
|
provider: resolvedProviderModel.provider,
|
||||||
cwd,
|
cwd,
|
||||||
title: options.name,
|
title: resolvedTitle,
|
||||||
modeId: options.mode,
|
modeId: options.mode,
|
||||||
model: resolvedProviderModel.model,
|
model: resolvedProviderModel.model,
|
||||||
thinkingOptionId,
|
thinkingOptionId,
|
||||||
@@ -513,7 +516,7 @@ export async function runRunCommand(
|
|||||||
const agent = await client.createAgent({
|
const agent = await client.createAgent({
|
||||||
provider: resolvedProviderModel.provider,
|
provider: resolvedProviderModel.provider,
|
||||||
cwd,
|
cwd,
|
||||||
title: options.name,
|
title: resolvedTitle,
|
||||||
modeId: options.mode,
|
modeId: options.mode,
|
||||||
model: resolvedProviderModel.model,
|
model: resolvedProviderModel.model,
|
||||||
thinkingOptionId,
|
thinkingOptionId,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ try {
|
|||||||
assert.strictEqual(result.exitCode, 0, "run --help should exit 0");
|
assert.strictEqual(result.exitCode, 0, "run --help should exit 0");
|
||||||
assert(result.stdout.includes("-d"), "help should mention -d flag");
|
assert(result.stdout.includes("-d"), "help should mention -d flag");
|
||||||
assert(result.stdout.includes("--detach"), "help should mention --detach flag");
|
assert(result.stdout.includes("--detach"), "help should mention --detach flag");
|
||||||
assert(result.stdout.includes("--name"), "help should mention --name option");
|
assert(result.stdout.includes("--title"), "help should mention --title option");
|
||||||
assert(result.stdout.includes("--provider"), "help should mention --provider option");
|
assert(result.stdout.includes("--provider"), "help should mention --provider option");
|
||||||
assert(result.stdout.includes("--mode"), "help should mention --mode option");
|
assert(result.stdout.includes("--mode"), "help should mention --mode option");
|
||||||
assert(result.stdout.includes("--cwd"), "help should mention --cwd option");
|
assert(result.stdout.includes("--cwd"), "help should mention --cwd option");
|
||||||
|
|||||||
@@ -71,7 +71,6 @@ import type {
|
|||||||
AgentSessionConfig,
|
AgentSessionConfig,
|
||||||
} from "../server/agent/agent-sdk-types.js";
|
} from "../server/agent/agent-sdk-types.js";
|
||||||
import type { MutableDaemonConfig, MutableDaemonConfigPatch } from "../shared/messages.js";
|
import type { MutableDaemonConfig, MutableDaemonConfigPatch } from "../shared/messages.js";
|
||||||
import { getAgentProviderDefinition } from "../server/agent/provider-manifest.js";
|
|
||||||
import { isRelayClientWebSocketUrl } from "../shared/daemon-endpoints.js";
|
import { isRelayClientWebSocketUrl } from "../shared/daemon-endpoints.js";
|
||||||
import {
|
import {
|
||||||
asUint8Array,
|
asUint8Array,
|
||||||
@@ -3938,10 +3937,6 @@ function resolveAgentConfig(options: CreateAgentRequestOptions): AgentSessionCon
|
|||||||
throw new Error("createAgent requires provider and cwd");
|
throw new Error("createAgent requires provider and cwd");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!merged.modeId) {
|
|
||||||
merged.modeId = getAgentProviderDefinition(merged.provider).defaultModeId ?? undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...merged,
|
...merged,
|
||||||
provider: merged.provider,
|
provider: merged.provider,
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ export async function createAgentManagementMcpServer(
|
|||||||
.min(1, "Title is required")
|
.min(1, "Title is required")
|
||||||
.max(60, "Title must be 60 characters or fewer")
|
.max(60, "Title must be 60 characters or fewer")
|
||||||
.describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
|
.describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
|
||||||
agentType: AgentProviderEnum.optional().describe(
|
provider: AgentProviderEnum.optional().describe(
|
||||||
"Optional agent implementation to spawn. Defaults to 'claude'.",
|
"Optional agent implementation to spawn. Defaults to 'claude'.",
|
||||||
),
|
),
|
||||||
model: z.string().optional().describe("Model to use (e.g. claude-sonnet-4-20250514)"),
|
model: z.string().optional().describe("Model to use (e.g. claude-sonnet-4-20250514)"),
|
||||||
@@ -114,7 +114,10 @@ export async function createAgentManagementMcpServer(
|
|||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
.describe("Optional task to start immediately after creation (non-blocking)."),
|
.describe("Optional task to start immediately after creation (non-blocking)."),
|
||||||
initialMode: z.string().describe("Required session mode to configure before the first run."),
|
mode: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Optional session mode to configure before the first run."),
|
||||||
worktreeName: z
|
worktreeName: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -159,9 +162,9 @@ export async function createAgentManagementMcpServer(
|
|||||||
async (args) => {
|
async (args) => {
|
||||||
const {
|
const {
|
||||||
cwd,
|
cwd,
|
||||||
agentType,
|
provider,
|
||||||
initialPrompt,
|
initialPrompt,
|
||||||
initialMode,
|
mode,
|
||||||
worktreeName,
|
worktreeName,
|
||||||
baseBranch,
|
baseBranch,
|
||||||
background = false,
|
background = false,
|
||||||
@@ -171,9 +174,9 @@ export async function createAgentManagementMcpServer(
|
|||||||
labels,
|
labels,
|
||||||
} = args as {
|
} = args as {
|
||||||
cwd: string;
|
cwd: string;
|
||||||
agentType?: AgentProvider;
|
provider?: AgentProvider;
|
||||||
initialPrompt?: string;
|
initialPrompt?: string;
|
||||||
initialMode: string;
|
mode?: string;
|
||||||
worktreeName?: string;
|
worktreeName?: string;
|
||||||
baseBranch?: string;
|
baseBranch?: string;
|
||||||
background?: boolean;
|
background?: boolean;
|
||||||
@@ -201,13 +204,13 @@ export async function createAgentManagementMcpServer(
|
|||||||
worktreeConfig = worktree;
|
worktreeConfig = worktree;
|
||||||
}
|
}
|
||||||
|
|
||||||
const provider: AgentProvider = agentType ?? "claude";
|
const resolvedProvider: AgentProvider = provider ?? "claude";
|
||||||
const normalizedTitle = title?.trim() ?? null;
|
const normalizedTitle = title?.trim() ?? null;
|
||||||
const snapshot = await agentManager.createAgent(
|
const snapshot = await agentManager.createAgent(
|
||||||
{
|
{
|
||||||
provider,
|
provider: resolvedProvider,
|
||||||
cwd: resolvedCwd,
|
cwd: resolvedCwd,
|
||||||
modeId: initialMode,
|
modeId: mode,
|
||||||
title: normalizedTitle ?? undefined,
|
title: normalizedTitle ?? undefined,
|
||||||
model,
|
model,
|
||||||
thinkingOptionId: thinking,
|
thinkingOptionId: thinking,
|
||||||
|
|||||||
@@ -98,6 +98,22 @@ class TestAgentClient implements AgentClient {
|
|||||||
return new TestAgentSession(config);
|
return new TestAgentSession(config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async listModels() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
provider: "codex",
|
||||||
|
id: "gpt-5.4",
|
||||||
|
label: "GPT-5.4",
|
||||||
|
isDefault: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
provider: "codex",
|
||||||
|
id: "gpt-5.4-mini",
|
||||||
|
label: "GPT-5.4 Mini",
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
async resumeSession(
|
async resumeSession(
|
||||||
_handle: AgentPersistenceHandle,
|
_handle: AgentPersistenceHandle,
|
||||||
config?: Partial<AgentSessionConfig>,
|
config?: Partial<AgentSessionConfig>,
|
||||||
@@ -212,7 +228,7 @@ function createFeature(overrides: Partial<AgentFeature> = {}): AgentFeature {
|
|||||||
describe("AgentManager", () => {
|
describe("AgentManager", () => {
|
||||||
const logger = createTestLogger();
|
const logger = createTestLogger();
|
||||||
|
|
||||||
test("normalizeConfig does not inject default model when omitted", async () => {
|
test("normalizeConfig injects the provider default model when omitted", async () => {
|
||||||
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-test-"));
|
const workdir = mkdtempSync(join(tmpdir(), "agent-manager-test-"));
|
||||||
const storagePath = join(workdir, "agents");
|
const storagePath = join(workdir, "agents");
|
||||||
const storage = new AgentStorage(storagePath, logger);
|
const storage = new AgentStorage(storagePath, logger);
|
||||||
@@ -230,7 +246,8 @@ describe("AgentManager", () => {
|
|||||||
cwd: workdir,
|
cwd: workdir,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(snapshot.model).toBeUndefined();
|
expect(snapshot.config.model).toBe("gpt-5.4");
|
||||||
|
expect(snapshot.config.modeId).toBe("auto");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("normalizeConfig strips legacy 'default' model id", async () => {
|
test("normalizeConfig strips legacy 'default' model id", async () => {
|
||||||
@@ -252,7 +269,8 @@ describe("AgentManager", () => {
|
|||||||
model: "default",
|
model: "default",
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(snapshot.model).toBeUndefined();
|
expect(snapshot.config.model).toBe("gpt-5.4");
|
||||||
|
expect(snapshot.config.modeId).toBe("auto");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("createAgent passes daemon launch env through the provider launch context", async () => {
|
test("createAgent passes daemon launch env through the provider launch context", async () => {
|
||||||
@@ -292,6 +310,8 @@ describe("AgentManager", () => {
|
|||||||
expect(client.lastConfig).toEqual({
|
expect(client.lastConfig).toEqual({
|
||||||
provider: "codex",
|
provider: "codex",
|
||||||
cwd: workdir,
|
cwd: workdir,
|
||||||
|
model: "gpt-5.4",
|
||||||
|
modeId: "auto",
|
||||||
});
|
});
|
||||||
expect(client.lastLaunchContext).toEqual({
|
expect(client.lastLaunchContext).toEqual({
|
||||||
env: {
|
env: {
|
||||||
@@ -1432,7 +1452,7 @@ describe("AgentManager", () => {
|
|||||||
cwd: workdir,
|
cwd: workdir,
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(snapshot.runtimeInfo?.model ?? null).toBeNull();
|
expect(snapshot.runtimeInfo?.model).toBe("gpt-5.4");
|
||||||
|
|
||||||
await manager.runAgent(snapshot.id, "hello");
|
await manager.runAgent(snapshot.id, "hello");
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import type {
|
|||||||
PersistedAgentDescriptor,
|
PersistedAgentDescriptor,
|
||||||
} from "./agent-sdk-types.js";
|
} from "./agent-sdk-types.js";
|
||||||
import type { AgentStorage } from "./agent-storage.js";
|
import type { AgentStorage } from "./agent-storage.js";
|
||||||
import { AGENT_PROVIDER_IDS } from "./provider-manifest.js";
|
import { AGENT_PROVIDER_IDS, getAgentProviderDefinition } from "./provider-manifest.js";
|
||||||
|
|
||||||
export { AGENT_LIFECYCLE_STATUSES, type AgentLifecycleStatus };
|
export { AGENT_LIFECYCLE_STATUSES, type AgentLifecycleStatus };
|
||||||
|
|
||||||
@@ -2568,7 +2568,31 @@ export class AgentManager {
|
|||||||
|
|
||||||
if (typeof normalized.model === "string") {
|
if (typeof normalized.model === "string") {
|
||||||
const trimmed = normalized.model.trim();
|
const trimmed = normalized.model.trim();
|
||||||
normalized.model = trimmed.length > 0 ? trimmed : undefined;
|
normalized.model = trimmed.length > 0 && trimmed !== "default" ? trimmed : undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!normalized.model) {
|
||||||
|
const client = this.clients.get(normalized.provider);
|
||||||
|
if (client) {
|
||||||
|
try {
|
||||||
|
const models = await client.listModels();
|
||||||
|
const defaultModel = models.find((model) => model.isDefault) ?? models[0];
|
||||||
|
if (defaultModel) {
|
||||||
|
normalized.model = defaultModel.id;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
// Provider may not support model listing — leave model undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!normalized.modeId) {
|
||||||
|
try {
|
||||||
|
normalized.modeId =
|
||||||
|
getAgentProviderDefinition(normalized.provider).defaultModeId ?? undefined;
|
||||||
|
} catch {
|
||||||
|
// Unknown provider
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
|
|||||||
@@ -151,8 +151,8 @@ describe("agent MCP end-to-end (offline)", () => {
|
|||||||
args: {
|
args: {
|
||||||
cwd: agentCwd,
|
cwd: agentCwd,
|
||||||
title: "MCP e2e smoke",
|
title: "MCP e2e smoke",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialMode: "bypassPermissions",
|
mode: "bypassPermissions",
|
||||||
initialPrompt,
|
initialPrompt,
|
||||||
background: false,
|
background: false,
|
||||||
},
|
},
|
||||||
@@ -242,8 +242,8 @@ describe("agent MCP end-to-end (offline)", () => {
|
|||||||
args: {
|
args: {
|
||||||
cwd: agentCwd,
|
cwd: agentCwd,
|
||||||
title: "Injected MCP",
|
title: "Injected MCP",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialMode: "bypassPermissions",
|
mode: "bypassPermissions",
|
||||||
initialPrompt: "reply with done and stop",
|
initialPrompt: "reply with done and stop",
|
||||||
background: true,
|
background: true,
|
||||||
},
|
},
|
||||||
@@ -265,8 +265,8 @@ describe("agent MCP end-to-end (offline)", () => {
|
|||||||
args: {
|
args: {
|
||||||
cwd: disabledAgentCwd,
|
cwd: disabledAgentCwd,
|
||||||
title: "No injected MCP",
|
title: "No injected MCP",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialMode: "bypassPermissions",
|
mode: "bypassPermissions",
|
||||||
initialPrompt: "reply with done and stop",
|
initialPrompt: "reply with done and stop",
|
||||||
background: true,
|
background: true,
|
||||||
},
|
},
|
||||||
@@ -362,8 +362,8 @@ describe("agent MCP end-to-end (offline)", () => {
|
|||||||
args: {
|
args: {
|
||||||
cwd: repoRoot,
|
cwd: repoRoot,
|
||||||
title: "MCP worktree setup terminals",
|
title: "MCP worktree setup terminals",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialMode: "bypassPermissions",
|
mode: "bypassPermissions",
|
||||||
initialPrompt: "say done and stop",
|
initialPrompt: "say done and stop",
|
||||||
worktreeName: "mcp-worktree-setup-test",
|
worktreeName: "mcp-worktree-setup-test",
|
||||||
baseBranch: "main",
|
baseBranch: "main",
|
||||||
|
|||||||
@@ -121,9 +121,9 @@ describe("MCP parity end-to-end", () => {
|
|||||||
const payload = await callToolStructured(topLevelClient, "create_agent", {
|
const payload = await callToolStructured(topLevelClient, "create_agent", {
|
||||||
cwd,
|
cwd,
|
||||||
title: "Parity agent",
|
title: "Parity agent",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialPrompt: "say done and stop",
|
initialPrompt: "say done and stop",
|
||||||
initialMode: "bypassPermissions",
|
mode: "bypassPermissions",
|
||||||
background: true,
|
background: true,
|
||||||
...args,
|
...args,
|
||||||
});
|
});
|
||||||
@@ -133,7 +133,7 @@ describe("MCP parity end-to-end", () => {
|
|||||||
async function createChildAgent(args?: Partial<StructuredContent>): Promise<string> {
|
async function createChildAgent(args?: Partial<StructuredContent>): Promise<string> {
|
||||||
const payload = await callToolStructured(agentScopedClient, "create_agent", {
|
const payload = await callToolStructured(agentScopedClient, "create_agent", {
|
||||||
title: "Parity child",
|
title: "Parity child",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialPrompt: "say done and stop",
|
initialPrompt: "say done and stop",
|
||||||
background: true,
|
background: true,
|
||||||
...args,
|
...args,
|
||||||
@@ -207,9 +207,9 @@ describe("MCP parity end-to-end", () => {
|
|||||||
const parentPayload = await callToolStructured(topLevelClient, "create_agent", {
|
const parentPayload = await callToolStructured(topLevelClient, "create_agent", {
|
||||||
cwd: parentAgentCwd,
|
cwd: parentAgentCwd,
|
||||||
title: "MCP parity parent",
|
title: "MCP parity parent",
|
||||||
agentType: "claude",
|
provider: "claude",
|
||||||
initialPrompt: "say done and stop",
|
initialPrompt: "say done and stop",
|
||||||
initialMode: "bypassPermissions",
|
mode: "bypassPermissions",
|
||||||
background: true,
|
background: true,
|
||||||
});
|
});
|
||||||
parentAgentId = parentPayload.agentId as string;
|
parentAgentId = parentPayload.agentId as string;
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
|
|
||||||
const missingTitle = await tool.inputSchema.safeParseAsync({
|
const missingTitle = await tool.inputSchema.safeParseAsync({
|
||||||
cwd: existingCwd,
|
cwd: existingCwd,
|
||||||
initialMode: "default",
|
mode: "default",
|
||||||
initialPrompt: "test",
|
initialPrompt: "test",
|
||||||
});
|
});
|
||||||
expect(missingTitle.success).toBe(false);
|
expect(missingTitle.success).toBe(false);
|
||||||
@@ -73,7 +73,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
|
|
||||||
const tooLong = await tool.inputSchema.safeParseAsync({
|
const tooLong = await tool.inputSchema.safeParseAsync({
|
||||||
cwd: existingCwd,
|
cwd: existingCwd,
|
||||||
initialMode: "default",
|
mode: "default",
|
||||||
title: "x".repeat(61),
|
title: "x".repeat(61),
|
||||||
initialPrompt: "test",
|
initialPrompt: "test",
|
||||||
});
|
});
|
||||||
@@ -82,7 +82,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
|
|
||||||
const ok = await tool.inputSchema.safeParseAsync({
|
const ok = await tool.inputSchema.safeParseAsync({
|
||||||
cwd: existingCwd,
|
cwd: existingCwd,
|
||||||
initialMode: "default",
|
mode: "default",
|
||||||
title: "Short title",
|
title: "Short title",
|
||||||
initialPrompt: "test",
|
initialPrompt: "test",
|
||||||
});
|
});
|
||||||
@@ -95,7 +95,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
const tool = (server as any)._registeredTools["create_agent"];
|
const tool = (server as any)._registeredTools["create_agent"];
|
||||||
const parsed = await tool.inputSchema.safeParseAsync({
|
const parsed = await tool.inputSchema.safeParseAsync({
|
||||||
cwd: existingCwd,
|
cwd: existingCwd,
|
||||||
initialMode: "default",
|
mode: "default",
|
||||||
title: "Short title",
|
title: "Short title",
|
||||||
});
|
});
|
||||||
expect(parsed.success).toBe(false);
|
expect(parsed.success).toBe(false);
|
||||||
@@ -194,7 +194,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
await tool.callback({
|
await tool.callback({
|
||||||
cwd: existingCwd,
|
cwd: existingCwd,
|
||||||
title: "Config test",
|
title: "Config test",
|
||||||
initialMode: "default",
|
mode: "default",
|
||||||
initialPrompt: "Do work",
|
initialPrompt: "Do work",
|
||||||
model: "claude-sonnet-4-20250514",
|
model: "claude-sonnet-4-20250514",
|
||||||
thinking: "think-hard",
|
thinking: "think-hard",
|
||||||
@@ -248,7 +248,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
await tool.callback({
|
await tool.callback({
|
||||||
cwd: "subdir",
|
cwd: "subdir",
|
||||||
title: "Child",
|
title: "Child",
|
||||||
agentType: "codex",
|
provider: "codex",
|
||||||
initialPrompt: "Do work",
|
initialPrompt: "Do work",
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -287,7 +287,7 @@ describe("create_agent MCP tool", () => {
|
|||||||
await tool.callback({
|
await tool.callback({
|
||||||
cwd: existingCwd,
|
cwd: existingCwd,
|
||||||
title: "Injected config test",
|
title: "Injected config test",
|
||||||
initialMode: "default",
|
mode: "default",
|
||||||
initialPrompt: "Do work",
|
initialPrompt: "Do work",
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -284,7 +284,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
.min(1, "Title is required")
|
.min(1, "Title is required")
|
||||||
.max(60, "Title must be 60 characters or fewer")
|
.max(60, "Title must be 60 characters or fewer")
|
||||||
.describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
|
.describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
|
||||||
agentType: AgentProviderEnum.optional().describe(
|
provider: AgentProviderEnum.optional().describe(
|
||||||
"Optional agent implementation to spawn. Defaults to 'claude'.",
|
"Optional agent implementation to spawn. Defaults to 'claude'.",
|
||||||
),
|
),
|
||||||
model: z.string().optional().describe("Model to use (e.g. claude-sonnet-4-20250514)"),
|
model: z.string().optional().describe("Model to use (e.g. claude-sonnet-4-20250514)"),
|
||||||
@@ -321,7 +321,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
.min(1, "Title is required")
|
.min(1, "Title is required")
|
||||||
.max(60, "Title must be 60 characters or fewer")
|
.max(60, "Title must be 60 characters or fewer")
|
||||||
.describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
|
.describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
|
||||||
agentType: AgentProviderEnum.optional().describe(
|
provider: AgentProviderEnum.optional().describe(
|
||||||
"Optional agent implementation to spawn. Defaults to 'claude'.",
|
"Optional agent implementation to spawn. Defaults to 'claude'.",
|
||||||
),
|
),
|
||||||
model: z.string().optional().describe("Model to use (e.g. claude-sonnet-4-20250514)"),
|
model: z.string().optional().describe("Model to use (e.g. claude-sonnet-4-20250514)"),
|
||||||
@@ -332,7 +332,10 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
.trim()
|
.trim()
|
||||||
.min(1, "initialPrompt is required")
|
.min(1, "initialPrompt is required")
|
||||||
.describe("Required first task to run immediately after creation."),
|
.describe("Required first task to run immediately after creation."),
|
||||||
initialMode: z.string().describe("Required session mode to configure before the first run."),
|
mode: z
|
||||||
|
.string()
|
||||||
|
.optional()
|
||||||
|
.describe("Optional session mode to configure before the first run."),
|
||||||
worktreeName: z
|
worktreeName: z
|
||||||
.string()
|
.string()
|
||||||
.optional()
|
.optional()
|
||||||
@@ -359,10 +362,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
|
|
||||||
const createAgentInputSchema = callerAgentId ? agentToAgentInputSchema : topLevelInputSchema;
|
const createAgentInputSchema = callerAgentId ? agentToAgentInputSchema : topLevelInputSchema;
|
||||||
const agentToAgentCreateAgentArgsSchema = z.object(agentToAgentInputSchema);
|
const agentToAgentCreateAgentArgsSchema = z.object(agentToAgentInputSchema);
|
||||||
const topLevelCreateAgentArgsSchema = z.object({
|
const topLevelCreateAgentArgsSchema = z.object(topLevelInputSchema);
|
||||||
...topLevelInputSchema,
|
|
||||||
initialMode: topLevelInputSchema.initialMode.optional(),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (options.voiceOnly || options.enableVoiceTools || callerContext?.enableVoiceTools) {
|
if (options.voiceOnly || options.enableVoiceTools || callerContext?.enableVoiceTools) {
|
||||||
server.registerTool(
|
server.registerTool(
|
||||||
@@ -447,7 +447,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
|
|
||||||
if (callerAgentId) {
|
if (callerAgentId) {
|
||||||
const callerArgs = agentToAgentCreateAgentArgsSchema.parse(args);
|
const callerArgs = agentToAgentCreateAgentArgsSchema.parse(args);
|
||||||
provider = callerArgs.agentType ?? "claude";
|
provider = callerArgs.provider ?? "claude";
|
||||||
initialPrompt = callerArgs.initialPrompt;
|
initialPrompt = callerArgs.initialPrompt;
|
||||||
background = callerArgs.background ?? false;
|
background = callerArgs.background ?? false;
|
||||||
normalizedTitle = callerArgs.title.trim();
|
normalizedTitle = callerArgs.title.trim();
|
||||||
@@ -472,7 +472,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const topLevelArgs = topLevelCreateAgentArgsSchema.parse(args);
|
const topLevelArgs = topLevelCreateAgentArgsSchema.parse(args);
|
||||||
provider = topLevelArgs.agentType ?? "claude";
|
provider = topLevelArgs.provider ?? "claude";
|
||||||
initialPrompt = topLevelArgs.initialPrompt;
|
initialPrompt = topLevelArgs.initialPrompt;
|
||||||
background = topLevelArgs.background ?? false;
|
background = topLevelArgs.background ?? false;
|
||||||
normalizedTitle = topLevelArgs.title.trim();
|
normalizedTitle = topLevelArgs.title.trim();
|
||||||
@@ -480,7 +480,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
thinking = topLevelArgs.thinking;
|
thinking = topLevelArgs.thinking;
|
||||||
labels = topLevelArgs.labels;
|
labels = topLevelArgs.labels;
|
||||||
notifyOnFinish = topLevelArgs.notifyOnFinish ?? false;
|
notifyOnFinish = topLevelArgs.notifyOnFinish ?? false;
|
||||||
const { cwd, initialMode, worktreeName, baseBranch } = topLevelArgs;
|
const { cwd, mode, worktreeName, baseBranch } = topLevelArgs;
|
||||||
|
|
||||||
resolvedCwd = expandUserPath(cwd);
|
resolvedCwd = expandUserPath(cwd);
|
||||||
|
|
||||||
@@ -499,7 +499,7 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
|
|||||||
worktreeConfig = worktree;
|
worktreeConfig = worktree;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolvedMode = initialMode;
|
resolvedMode = mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
const childAgentDefaultLabels = callerContext?.childAgentDefaultLabels;
|
const childAgentDefaultLabels = callerContext?.childAgentDefaultLabels;
|
||||||
|
|||||||
@@ -1006,10 +1006,10 @@ async function getAheadOfOrigin(cwd: string, currentBranch: string): Promise<num
|
|||||||
return Number.isNaN(count) ? null : count;
|
return Number.isNaN(count) ? null : count;
|
||||||
} catch {
|
} catch {
|
||||||
try {
|
try {
|
||||||
const { stdout } = await execAsync(
|
const { stdout } = await execAsync(`git rev-list --count ${currentBranch}`, {
|
||||||
`git rev-list --count ${currentBranch}`,
|
cwd,
|
||||||
{ cwd, env: READ_ONLY_GIT_ENV },
|
env: READ_ONLY_GIT_ENV,
|
||||||
);
|
});
|
||||||
const count = Number.parseInt(stdout.trim(), 10);
|
const count = Number.parseInt(stdout.trim(), 10);
|
||||||
return Number.isNaN(count) ? null : count;
|
return Number.isNaN(count) ? null : count;
|
||||||
} catch {
|
} catch {
|
||||||
|
|||||||
Reference in New Issue
Block a user