mirror of
https://github.com/rowboatlabs/rowboat.git
synced 2026-07-12 21:02:17 +02:00
Add reasoning effort for spawned agents
This commit is contained in:
parent
7765bec96e
commit
36ce35a058
4 changed files with 36 additions and 4 deletions
|
|
@ -9,6 +9,7 @@ import {
|
|||
isTurnUsageMessage,
|
||||
getToolDisplayName,
|
||||
getToolErrorText,
|
||||
REASONING_EFFORT_LABELS,
|
||||
toToolState,
|
||||
normalizeToolOutput,
|
||||
} from '@/lib/chat-conversation'
|
||||
|
|
@ -38,7 +39,7 @@ export function CompactConversation({ items }: { items: ConversationItem[] }) {
|
|||
}
|
||||
if (isTurnUsageMessage(item)) {
|
||||
return (
|
||||
<div key={item.id} className="flex justify-start px-1">
|
||||
<div key={item.id} className="flex items-center justify-start gap-1 px-1">
|
||||
<TokenUsageMenu
|
||||
usage={item.usage}
|
||||
scope="turn"
|
||||
|
|
@ -46,6 +47,11 @@ export function CompactConversation({ items }: { items: ConversationItem[] }) {
|
|||
className="size-5 border-transparent bg-transparent hover:bg-transparent"
|
||||
align="start"
|
||||
/>
|
||||
{item.reasoningEffort && (
|
||||
<span className="text-xs text-muted-foreground/70">
|
||||
{REASONING_EFFORT_LABELS[item.reasoningEffort]}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -140,6 +140,19 @@ describe("runSpawnedAgent", () => {
|
|||
expect(started[0].maxModelCalls).toBe(5);
|
||||
});
|
||||
|
||||
it("passes reasoning effort through to the child headless turn", async () => {
|
||||
const { services, started } = fakeServices({});
|
||||
await runSpawnedAgent(
|
||||
{
|
||||
task: "compare these options carefully",
|
||||
instructions: "You analyze tradeoffs.",
|
||||
reasoning_effort: "high",
|
||||
},
|
||||
{ parentTurnId: "parent-1", signal, services },
|
||||
);
|
||||
expect(started[0].reasoningEffort).toBe("high");
|
||||
});
|
||||
|
||||
it("rejects agent_id and instructions together", async () => {
|
||||
const { services } = fakeServices({});
|
||||
const result = await runSpawnedAgent(
|
||||
|
|
|
|||
|
|
@ -59,12 +59,20 @@ export const SpawnAgentInput = z.object({
|
|||
.describe(
|
||||
`Model-call budget for the sub-agent (default and cap: ${DEFAULT_MAX_MODEL_CALLS}).`,
|
||||
),
|
||||
reasoning_effort: z
|
||||
.enum(["low", "medium", "high"])
|
||||
.optional()
|
||||
.describe(
|
||||
"Optional reasoning-effort override for the sub-agent turn. Omit for auto/provider default. Use `low` for routine extraction or summarization, `medium` for multi-step synthesis, and `high` only when the child task truly needs deeper reasoning.",
|
||||
),
|
||||
});
|
||||
|
||||
export const SPAWN_AGENT_DESCRIPTION =
|
||||
"Launch a sub-agent that works on a task in its own isolated, headless turn and returns its final answer. " +
|
||||
"Issue several spawn-agent calls in ONE response to run sub-agents in parallel — use this to fan out independent research, analysis, or file work. " +
|
||||
"Use it deliberately for independent, heavy, or parallelizable work; avoid spawning for quick single-step lookups. " +
|
||||
"Issue several spawn-agent calls in ONE response only when the subtasks are genuinely independent and worth running in parallel. " +
|
||||
"Provide either `agent_id` (a stored agent) or `instructions` (construct a specialist on the fly, optionally with `name` and `tools`). " +
|
||||
"Optionally set `reasoning_effort` for the child turn; leave it unset for auto/provider default, and reserve `high` for tasks that clearly need deeper reasoning. " +
|
||||
"The sub-agent cannot ask the user questions and cannot spawn further sub-agents; give it a complete, self-contained task.";
|
||||
|
||||
export interface SpawnedAgentCallbacks {
|
||||
|
|
@ -170,6 +178,9 @@ export async function runSpawnedAgent(
|
|||
agent,
|
||||
message: input.task,
|
||||
maxModelCalls,
|
||||
...(input.reasoning_effort === undefined
|
||||
? {}
|
||||
: { reasoningEffort: input.reasoning_effort }),
|
||||
signal: opts.signal,
|
||||
});
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -149,9 +149,11 @@ ${codeModeEnabled
|
|||
|
||||
**Background Tasks (Self-Running Work):** Rowboat runs *background tasks* — persistent instructions fired on a schedule and/or on incoming emails / calendar events; the flagship surface for *anything recurring*. Load the \`background-task\` skill and act without asking on cadence words ("every morning / daily / each Monday…"), "keep a running summary / digest of…", "watch / monitor…", "whenever a relevant email comes in, X…", "track / follow X". Load it and offer after answering when a one-off question is about decaying or recurring info ("catch me up on X", "morning briefing" — heuristic: if you reach for \`web-search\` to answer a recurring question, a bg-task should be refreshing it).
|
||||
|
||||
**Sub-Agents (parallel & heavy work):** The \`spawn-agent\` tool runs a sub-agent in its own isolated, headless thread and returns only its final answer — the sub-agent's tool calls, page fetches, and file reads never enter this conversation. Use it to keep this context clean: a sub-agent can read twenty notes or six web pages and hand you back one paragraph. Issue several spawn-agent calls in ONE response to run them in parallel.
|
||||
**Sub-Agents (parallel & heavy work):** The \`spawn-agent\` tool runs a sub-agent in its own isolated, headless thread and returns only its final answer — the sub-agent's tool calls, page fetches, and file reads never enter this conversation. Use it sparingly and deliberately when the work is independent, long-running, or context-heavy enough to justify a separate turn. A sub-agent can read twenty notes or six web pages and hand you back one paragraph. Issue several spawn-agent calls in ONE response only when the subtasks are genuinely independent and useful to run in parallel.
|
||||
|
||||
*Strong signals (spawn without asking):* the request decomposes into independent lookups ("prep me on these 3 attendees", "compare these vendors") — one sub-agent each; the task needs reading MANY files, notes, pages, or a long document but the user wants a summary ("what do we know about Acme", "summarize this 40-page PDF"); open-ended web research where you don't know the sources upfront. **Research-shaped requests ("catch me up on X", "dig into Y", meeting prep) should route through sub-agents by default** — you act as the synthesizer, weaving their findings together with what you know from memory.
|
||||
*Strong signals (spawn without asking):* the request decomposes into independent lookups ("prep me on these 3 attendees", "compare these vendors") — one sub-agent each; the task needs reading MANY files, notes, pages, or a long document but the user wants a summary ("what do we know about Acme", "summarize this 40-page PDF"); open-ended web research where you don't know the sources upfront. For research-shaped requests ("catch me up on X", "dig into Y", meeting prep), use sub-agents when there are multiple sources or branches to investigate, then act as the synthesizer and weave their findings together with what you know from memory.
|
||||
|
||||
*Reasoning effort:* \`spawn-agent\` accepts \`reasoning_effort\` for the child turn. Usually omit it and let the provider default apply. Use \`low\` for routine extraction, search, or simple summaries; \`medium\` for multi-step comparison or synthesis; \`high\` only for hard analysis, ambiguous tradeoffs, planning, or tasks where a wrong conclusion would be costly.
|
||||
|
||||
*Do NOT spawn for:* single quick lookups (one file read, one search — just do it); tasks where the user wants to see the intermediate detail, not a distillation; anything needing user input mid-way (sub-agents run headless and cannot ask questions); driving the app UI or the embedded browser (those are shared surfaces you control, not sub-agents). Remember each sub-agent starts with ZERO context — its \`task\` must be fully self-contained (names, dates, constraints, expected output format).
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue