mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
refactor(server): improve self-identification instructions
- Made the timing clearer: "Immediately after your first message where you understand the task and decide to do multi-step work" - Added explicit "do not repeat" constraint to prevent over-calling - Made set_branch instruction dynamic based on whether cwd looks like a Paseo worktree (contains .paseo/worktrees) - When in a worktree, explicitly tell the agent to call set_branch - When not in a worktree, keep the cautious "only if certain" language
This commit is contained in:
@@ -48,7 +48,7 @@ function createTestDeps(): TestDeps {
|
||||
describe("create_agent MCP tool", () => {
|
||||
const logger = createTestLogger();
|
||||
|
||||
it("requires a concise title no longer than 40 characters", async () => {
|
||||
it("requires a concise title no longer than 60 characters", async () => {
|
||||
const { agentManager, agentRegistry } = createTestDeps();
|
||||
const server = await createAgentMcpServer({ agentManager, agentRegistry, logger });
|
||||
const tool = (server as any)._registeredTools["create_agent"];
|
||||
@@ -64,7 +64,7 @@ describe("create_agent MCP tool", () => {
|
||||
const tooLong = await tool.inputSchema.safeParseAsync({
|
||||
cwd: "/tmp/repo",
|
||||
initialMode: "default",
|
||||
title: "x".repeat(41),
|
||||
title: "x".repeat(61),
|
||||
});
|
||||
expect(tooLong.success).toBe(false);
|
||||
expect(tooLong.error.issues[0].path).toEqual(["title"]);
|
||||
|
||||
@@ -281,9 +281,9 @@ export async function createAgentMcpServer(
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Title is required")
|
||||
.max(40, "Title must be 40 characters or fewer")
|
||||
.max(60, "Title must be 60 characters or fewer")
|
||||
.describe(
|
||||
"Short descriptive title (<= 40 chars) summarizing the agent's focus. Use a single concise sentence that fits on mobile."
|
||||
"Short descriptive title (<= 60 chars) summarizing the agent's focus."
|
||||
),
|
||||
agentType: AgentProviderEnum.optional().describe(
|
||||
"Optional agent implementation to spawn. Defaults to 'claude'."
|
||||
@@ -313,9 +313,9 @@ export async function createAgentMcpServer(
|
||||
.string()
|
||||
.trim()
|
||||
.min(1, "Title is required")
|
||||
.max(40, "Title must be 40 characters or fewer")
|
||||
.max(60, "Title must be 60 characters or fewer")
|
||||
.describe(
|
||||
"Short descriptive title (<= 40 chars) summarizing the agent's focus. Use a single concise sentence that fits on mobile."
|
||||
"Short descriptive title (<= 60 chars) summarizing the agent's focus."
|
||||
),
|
||||
agentType: AgentProviderEnum.optional().describe(
|
||||
"Optional agent implementation to spawn. Defaults to 'claude'."
|
||||
@@ -906,8 +906,8 @@ export async function createAgentMcpServer(
|
||||
title: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(40)
|
||||
.describe("Short descriptive title (<= 40 chars)."),
|
||||
.max(60)
|
||||
.describe("Short descriptive title (<= 60 chars)."),
|
||||
},
|
||||
outputSchema: {
|
||||
success: z.boolean(),
|
||||
@@ -931,10 +931,10 @@ export async function createAgentMcpServer(
|
||||
if (!normalizedTitle) {
|
||||
throw new AgentMcpToolError("NOT_ALLOWED", "Title cannot be empty");
|
||||
}
|
||||
if (normalizedTitle.length > 40) {
|
||||
if (normalizedTitle.length > 60) {
|
||||
throw new AgentMcpToolError(
|
||||
"NOT_ALLOWED",
|
||||
"Title must be 40 characters or fewer"
|
||||
"Title must be 60 characters or fewer"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -804,7 +804,7 @@ class ClaudeAgentSession implements AgentSession {
|
||||
preset: "claude_code",
|
||||
append: [
|
||||
getOrchestratorModeInstructions(),
|
||||
this.currentMode === "plan" ? "" : getSelfIdentificationInstructions(),
|
||||
this.currentMode === "plan" ? "" : getSelfIdentificationInstructions({ cwd: this.config.cwd }),
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join("\n"),
|
||||
|
||||
@@ -2759,7 +2759,7 @@ function buildCodexMcpConfig(
|
||||
developerInstructions = history;
|
||||
}
|
||||
}
|
||||
const selfIdentificationInstructions = getSelfIdentificationInstructions();
|
||||
const selfIdentificationInstructions = getSelfIdentificationInstructions({ cwd: config.cwd });
|
||||
|
||||
// Build MCP servers configuration
|
||||
const mcpServers: Record<string, CodexMcpServerConfig> = {};
|
||||
|
||||
@@ -1,9 +1,30 @@
|
||||
export function getSelfIdentificationInstructions(): string {
|
||||
return [
|
||||
"Once you understand the task and are about to execute multi-step work (e.g., edits, tests, or repo changes), call set_title and set_branch exactly once to self-identify.",
|
||||
"Skip these calls in plan/read-only modes or when running a slash command.",
|
||||
"Do not call set_title or set_branch for short, fixed, or single-response requests (e.g., “say X exactly”, yes/no, one-liners).",
|
||||
"Only call set_branch when you are certain you are running inside a Paseo-owned worktree under .paseo/worktrees.",
|
||||
"If set_branch fails due to permissions or not being in a Paseo worktree, do not retry.",
|
||||
].join("\n");
|
||||
export interface SelfIdentificationContext {
|
||||
cwd?: string;
|
||||
}
|
||||
|
||||
function looksLikePaseoWorktree(cwd?: string): boolean {
|
||||
if (!cwd) return false;
|
||||
// Simple heuristic: if cwd contains .paseo/worktrees, it's likely a Paseo worktree
|
||||
return cwd.includes(".paseo/worktrees") || cwd.includes(".paseo\\worktrees");
|
||||
}
|
||||
|
||||
export function getSelfIdentificationInstructions(
|
||||
context?: SelfIdentificationContext
|
||||
): string {
|
||||
const inWorktree = looksLikePaseoWorktree(context?.cwd);
|
||||
|
||||
const lines = [
|
||||
"You are running under Paseo, an agent orchestration tool.",
|
||||
"Immediately after your first message where you understand the task and decide to do multi-step work, call set_title to self-identify. Call it exactly once per task—do not repeat.",
|
||||
"Skip set_title in plan/read-only modes or when running a slash command.",
|
||||
"Do not call set_title for short, fixed, or single-response requests (e.g., \"say X exactly\", yes/no, one-liners).",
|
||||
];
|
||||
|
||||
if (inWorktree) {
|
||||
lines.push(
|
||||
"You are running inside a Paseo-owned worktree. Call set_branch once (alongside set_title) to name your branch."
|
||||
);
|
||||
}
|
||||
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user