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.
|
||||
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
|
||||
|
||||
Use `sessions_spawn`:
|
||||
@ -102,7 +105,9 @@ Override via config:
|
||||
agents: {
|
||||
defaults: {
|
||||
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",
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
} else {
|
||||
// Fall back to config defaults if no explicit override
|
||||
thinkingOverride =
|
||||
targetAgentConfig?.subagents?.thinking ?? cfg.agents?.defaults?.subagents?.thinking;
|
||||
}
|
||||
if (resolvedModel) {
|
||||
try {
|
||||
|
||||
@ -204,6 +204,8 @@ export type AgentDefaultsConfig = {
|
||||
archiveAfterMinutes?: number;
|
||||
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
||||
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. */
|
||||
sandbox?: {
|
||||
|
||||
@ -36,6 +36,8 @@ export type AgentConfig = {
|
||||
allowAgents?: string[];
|
||||
/** Per-agent default model for spawned sub-agents (string or {primary,fallbacks}). */
|
||||
model?: string | { primary?: string; fallbacks?: string[] };
|
||||
/** Per-agent default thinking level for spawned sub-agents. */
|
||||
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||
};
|
||||
sandbox?: {
|
||||
mode?: "off" | "non-main" | "all";
|
||||
|
||||
@ -435,6 +435,8 @@ export type ToolsConfig = {
|
||||
subagents?: {
|
||||
/** Default model selection for spawned sub-agents (string or {primary,fallbacks}). */
|
||||
model?: string | { primary?: string; fallbacks?: string[] };
|
||||
/** Default thinking level for spawned sub-agents. */
|
||||
thinking?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
||||
tools?: {
|
||||
allow?: string[];
|
||||
deny?: string[];
|
||||
|
||||
@ -150,6 +150,16 @@ export const AgentDefaultsSchema = z
|
||||
.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()
|
||||
.optional(),
|
||||
|
||||
@ -525,6 +525,27 @@ export const ToolsSchema = z
|
||||
subagents: z
|
||||
.object({
|
||||
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()
|
||||
.optional(),
|
||||
|
||||
Loading…
Reference in New Issue
Block a user