Merge 0857a5e423 into 4583f88626
This commit is contained in:
commit
91d790da6f
@ -30,6 +30,9 @@ Cost note: each sub-agent has its **own** context and token usage. For heavy or
|
|||||||
tasks, set a cheaper model for sub-agents and keep your main agent on a higher-quality model.
|
tasks, set a cheaper model for sub-agents and keep your main agent on a higher-quality model.
|
||||||
You can configure this via `agents.defaults.subagents.model` or per-agent overrides.
|
You can configure this via `agents.defaults.subagents.model` or per-agent overrides.
|
||||||
|
|
||||||
|
Thinking level: sub-agents inherit the caller's thinking level by default. Override globally
|
||||||
|
via `agents.defaults.subagents.thinking` or per-spawn via the `thinking` tool param.
|
||||||
|
|
||||||
## Tool
|
## Tool
|
||||||
|
|
||||||
Use `sessions_spawn`:
|
Use `sessions_spawn`:
|
||||||
@ -102,7 +105,9 @@ Override via config:
|
|||||||
agents: {
|
agents: {
|
||||||
defaults: {
|
defaults: {
|
||||||
subagents: {
|
subagents: {
|
||||||
maxConcurrent: 1
|
maxConcurrent: 1,
|
||||||
|
model: "anthropic/claude-haiku-4",
|
||||||
|
thinking: "low"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -195,4 +195,79 @@ describe("moltbot-tools: subagents", () => {
|
|||||||
model: "minimax/MiniMax-M2.1",
|
model: "minimax/MiniMax-M2.1",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("sessions_spawn applies default subagent thinking from defaults config", async () => {
|
||||||
|
resetSubagentRegistryForTests();
|
||||||
|
callGatewayMock.mockReset();
|
||||||
|
configOverride = {
|
||||||
|
session: { mainKey: "main", scope: "per-sender" },
|
||||||
|
agents: { defaults: { subagents: { thinking: "medium" } } },
|
||||||
|
};
|
||||||
|
const calls: Array<{ method?: string; params?: unknown }> = [];
|
||||||
|
|
||||||
|
callGatewayMock.mockImplementation(async (opts: unknown) => {
|
||||||
|
const request = opts as { method?: string; params?: unknown };
|
||||||
|
calls.push(request);
|
||||||
|
if (request.method === "agent") {
|
||||||
|
return { runId: "run-default-thinking", status: "accepted" };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const tool = createMoltbotTools({
|
||||||
|
agentSessionKey: "agent:main:main",
|
||||||
|
agentChannel: "discord",
|
||||||
|
}).find((candidate) => candidate.name === "sessions_spawn");
|
||||||
|
if (!tool) throw new Error("missing sessions_spawn tool");
|
||||||
|
|
||||||
|
const result = await tool.execute("call-default-thinking", {
|
||||||
|
task: "do thing",
|
||||||
|
});
|
||||||
|
expect(result.details).toMatchObject({
|
||||||
|
status: "accepted",
|
||||||
|
});
|
||||||
|
|
||||||
|
const agentCall = calls.find((call) => call.method === "agent");
|
||||||
|
expect(agentCall?.params).toMatchObject({
|
||||||
|
thinking: "medium",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sessions_spawn tool param thinking overrides config default", async () => {
|
||||||
|
resetSubagentRegistryForTests();
|
||||||
|
callGatewayMock.mockReset();
|
||||||
|
configOverride = {
|
||||||
|
session: { mainKey: "main", scope: "per-sender" },
|
||||||
|
agents: { defaults: { subagents: { thinking: "low" } } },
|
||||||
|
};
|
||||||
|
const calls: Array<{ method?: string; params?: unknown }> = [];
|
||||||
|
|
||||||
|
callGatewayMock.mockImplementation(async (opts: unknown) => {
|
||||||
|
const request = opts as { method?: string; params?: unknown };
|
||||||
|
calls.push(request);
|
||||||
|
if (request.method === "agent") {
|
||||||
|
return { runId: "run-override-thinking", status: "accepted" };
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
|
||||||
|
const tool = createMoltbotTools({
|
||||||
|
agentSessionKey: "agent:main:main",
|
||||||
|
agentChannel: "discord",
|
||||||
|
}).find((candidate) => candidate.name === "sessions_spawn");
|
||||||
|
if (!tool) throw new Error("missing sessions_spawn tool");
|
||||||
|
|
||||||
|
const result = await tool.execute("call-override-thinking", {
|
||||||
|
task: "do thing",
|
||||||
|
thinking: "high",
|
||||||
|
});
|
||||||
|
expect(result.details).toMatchObject({
|
||||||
|
status: "accepted",
|
||||||
|
});
|
||||||
|
|
||||||
|
const agentCall = calls.find((call) => call.method === "agent");
|
||||||
|
expect(agentCall?.params).toMatchObject({
|
||||||
|
thinking: "high",
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -176,6 +176,10 @@ export function createSessionsSpawnTool(opts?: {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
thinkingOverride = normalized;
|
thinkingOverride = normalized;
|
||||||
|
} else {
|
||||||
|
// Fall back to config defaults if no explicit override
|
||||||
|
thinkingOverride =
|
||||||
|
targetAgentConfig?.subagents?.thinking ?? cfg.agents?.defaults?.subagents?.thinking;
|
||||||
}
|
}
|
||||||
if (resolvedModel) {
|
if (resolvedModel) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@ -204,6 +204,8 @@ export type AgentDefaultsConfig = {
|
|||||||
archiveAfterMinutes?: number;
|
archiveAfterMinutes?: number;
|
||||||
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
||||||
model?: string | { primary?: string; fallbacks?: string[] };
|
model?: string | { primary?: string; fallbacks?: string[] };
|
||||||
|
/** Default thinking level for spawned sub-agents. */
|
||||||
|
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||||
};
|
};
|
||||||
/** Optional sandbox settings for non-main sessions. */
|
/** Optional sandbox settings for non-main sessions. */
|
||||||
sandbox?: {
|
sandbox?: {
|
||||||
|
|||||||
@ -36,6 +36,8 @@ export type AgentConfig = {
|
|||||||
allowAgents?: string[];
|
allowAgents?: string[];
|
||||||
/** Per-agent default model for spawned sub-agents (string or {primary,fallbacks}). */
|
/** Per-agent default model for spawned sub-agents (string or {primary,fallbacks}). */
|
||||||
model?: string | { primary?: string; fallbacks?: string[] };
|
model?: string | { primary?: string; fallbacks?: string[] };
|
||||||
|
/** Per-agent default thinking level for spawned sub-agents. */
|
||||||
|
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||||
};
|
};
|
||||||
sandbox?: {
|
sandbox?: {
|
||||||
mode?: "off" | "non-main" | "all";
|
mode?: "off" | "non-main" | "all";
|
||||||
|
|||||||
@ -435,6 +435,8 @@ export type ToolsConfig = {
|
|||||||
subagents?: {
|
subagents?: {
|
||||||
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
||||||
model?: string | { primary?: string; fallbacks?: string[] };
|
model?: string | { primary?: string; fallbacks?: string[] };
|
||||||
|
/** Default thinking level for spawned sub-agents. */
|
||||||
|
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||||
tools?: {
|
tools?: {
|
||||||
allow?: string[];
|
allow?: string[];
|
||||||
deny?: string[];
|
deny?: string[];
|
||||||
|
|||||||
@ -150,6 +150,16 @@ export const AgentDefaultsSchema = z
|
|||||||
.strict(),
|
.strict(),
|
||||||
])
|
])
|
||||||
.optional(),
|
.optional(),
|
||||||
|
thinking: z
|
||||||
|
.union([
|
||||||
|
z.literal("off"),
|
||||||
|
z.literal("minimal"),
|
||||||
|
z.literal("low"),
|
||||||
|
z.literal("medium"),
|
||||||
|
z.literal("high"),
|
||||||
|
z.literal("xhigh"),
|
||||||
|
])
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|||||||
@ -525,6 +525,27 @@ export const ToolsSchema = z
|
|||||||
subagents: z
|
subagents: z
|
||||||
.object({
|
.object({
|
||||||
tools: ToolPolicySchema,
|
tools: ToolPolicySchema,
|
||||||
|
model: z
|
||||||
|
.union([
|
||||||
|
z.string(),
|
||||||
|
z
|
||||||
|
.object({
|
||||||
|
primary: z.string().optional(),
|
||||||
|
fallbacks: z.array(z.string()).optional(),
|
||||||
|
})
|
||||||
|
.strict(),
|
||||||
|
])
|
||||||
|
.optional(),
|
||||||
|
thinking: z
|
||||||
|
.union([
|
||||||
|
z.literal("off"),
|
||||||
|
z.literal("minimal"),
|
||||||
|
z.literal("low"),
|
||||||
|
z.literal("medium"),
|
||||||
|
z.literal("high"),
|
||||||
|
z.literal("xhigh"),
|
||||||
|
])
|
||||||
|
.optional(),
|
||||||
})
|
})
|
||||||
.strict()
|
.strict()
|
||||||
.optional(),
|
.optional(),
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user