fix: Task tool subagent spawn and isolated block labels (#561)

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Charles Packer
2026-01-15 22:39:53 -08:00
committed by GitHub
parent 4e8f99497c
commit c9fab34706
5 changed files with 50 additions and 6 deletions

View File

@@ -3,7 +3,7 @@ name: recall
description: Search conversation history to recall past discussions, decisions, and context
tools: Skill, Bash, Read, BashOutput
model: haiku
memoryBlocks: human, persona
memoryBlocks: human, persona, skills, loaded_skills
mode: stateless
---

View File

@@ -308,7 +308,7 @@ function buildSubagentArgs(
userPrompt: string,
): string[] {
const args: string[] = [
"--new",
"--new-agent",
"--system",
type,
"--model",

View File

@@ -290,7 +290,7 @@ export const SubagentGroupDisplay = memo(() => {
const hasErrors = agents.some((a) => a.status === "error");
return (
<Box flexDirection="column">
<Box flexDirection="column" marginTop={1}>
<GroupHeader
count={agents.length}
allCompleted={allCompleted}

View File

@@ -471,6 +471,16 @@ export async function handleHeadlessCommand(
// Determine which conversation to use
let conversationId: string;
// Only isolate blocks that actually exist on this agent
// If initBlocks is undefined, agent has default blocks (all ISOLATED_BLOCK_LABELS exist)
// If initBlocks is defined, only isolate blocks that are in both lists
const isolatedBlockLabels: string[] =
initBlocks === undefined
? [...ISOLATED_BLOCK_LABELS]
: ISOLATED_BLOCK_LABELS.filter((label) =>
initBlocks.includes(label as string),
);
if (specifiedConversationId) {
// User specified a conversation to resume
try {
@@ -496,7 +506,7 @@ export async function handleHeadlessCommand(
// Conversation no longer exists, create new
const conversation = await client.conversations.create({
agent_id: agent.id,
isolated_block_labels: [...ISOLATED_BLOCK_LABELS],
isolated_block_labels: isolatedBlockLabels,
});
conversationId = conversation.id;
}
@@ -504,7 +514,7 @@ export async function handleHeadlessCommand(
// No matching session, create new conversation
const conversation = await client.conversations.create({
agent_id: agent.id,
isolated_block_labels: [...ISOLATED_BLOCK_LABELS],
isolated_block_labels: isolatedBlockLabels,
});
conversationId = conversation.id;
}
@@ -513,7 +523,7 @@ export async function handleHeadlessCommand(
// This ensures isolated message history per CLI invocation
const conversation = await client.conversations.create({
agent_id: agent.id,
isolated_block_labels: [...ISOLATED_BLOCK_LABELS],
isolated_block_labels: isolatedBlockLabels,
});
conversationId = conversation.id;
}

View File

@@ -453,4 +453,38 @@ describe("input-format stream-json", () => {
},
{ timeout: 200000 },
);
test(
"Task tool with explore subagent works",
async () => {
// Prescriptive prompt to ensure Task tool is used
const objects = (await runBidirectional(
[
JSON.stringify({
type: "user",
message: {
role: "user",
content:
"You MUST use the Task tool with subagent_type='explore' to find TypeScript files (*.ts) in the src directory. " +
"Return only the subagent's report, nothing else.",
},
}),
],
[],
300000, // 5 min timeout - subagent spawn + execution can be slow
)) as WireMessage[];
// Should have a successful result
const result = objects.find(
(o): o is ResultMessage => o.type === "result",
);
expect(result).toBeDefined();
expect(result?.subtype).toBe("success");
// Should have auto_approval events (Task tool was auto-approved via --yolo)
const autoApprovals = objects.filter((o) => o.type === "auto_approval");
expect(autoApprovals.length).toBeGreaterThan(0);
},
{ timeout: 320000 },
);
});