recv mcp tool: default max to a small batch of 5 (wire default stays 1)
This commit is contained in:
parent
f310b1ce5a
commit
d46d3c261b
3 changed files with 31 additions and 23 deletions
|
|
@ -119,9 +119,13 @@ in `hive-c0re::dashboard_events::DashboardEvent`.
|
||||||
|
|
||||||
`AgentRequest::Recv` is the only path that delivers messages to an
|
`AgentRequest::Recv` is the only path that delivers messages to an
|
||||||
agent. Always returns a list (`Messages { messages }`) — empty when
|
agent. Always returns a list (`Messages { messages }`) — empty when
|
||||||
nothing's pending, single-pop when `max = None` (default 1, the
|
nothing's pending, single-pop when `max = None` (wire default 1),
|
||||||
single-message behaviour), batched up to `max` when caller asks for
|
batched up to `max` when the caller asks for more (server-side cap
|
||||||
more (server-side cap is 32; values above clamp silently).
|
is 32; values above clamp silently). The wire default MUST stay 1:
|
||||||
|
the harness turn loop sends `max: None` and consumes only the first
|
||||||
|
message, so a bigger server-side default would silently drop the
|
||||||
|
rest of a popped batch. The agent-facing `recv` MCP tool defaults to
|
||||||
|
`max = 5` at the tool layer instead (a small batch per call).
|
||||||
`wait_seconds` long-polls for the first message; once one arrives —
|
`wait_seconds` long-polls for the first message; once one arrives —
|
||||||
or one is already pending — the call drains up to `max` in total
|
or one is already pending — the call drains up to `max` in total
|
||||||
before returning, so a single `Recv` call coalesces a burst.
|
before returning, so a single `Recv` call coalesces a burst.
|
||||||
|
|
|
||||||
|
|
@ -519,7 +519,7 @@ ttl_seconds?, to?)`, `answer(id, answer)`, `ack_until(up_to)`.
|
||||||
that carve-out is structural, keyed on parent relationship, not name).
|
that carve-out is structural, keyed on parent relationship, not name).
|
||||||
- `recv` — drain inbox. Without `wait_seconds` (or `0`) returns
|
- `recv` — drain inbox. Without `wait_seconds` (or `0`) returns
|
||||||
immediately. Positive value parks the turn up to that many seconds
|
immediately. Positive value parks the turn up to that many seconds
|
||||||
(cap 180) — incoming messages wake instantly. `max` (default 1, cap
|
(cap 180) — incoming messages wake instantly. `max` (tool default 5, cap
|
||||||
32) drains up to N rows; `wait_seconds` applies to the first, then
|
32) drains up to N rows; `wait_seconds` applies to the first, then
|
||||||
drains up to `max` total. Each returned row is prefixed with
|
drains up to `max` total. Each returned row is prefixed with
|
||||||
`[msg #<id>]` (broker row id; note the highest id seen, then pass
|
`[msg #<id>]` (broker row id; note the highest id seen, then pass
|
||||||
|
|
|
||||||
|
|
@ -611,13 +611,12 @@ pub struct RecvArgs {
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub wait_seconds: Option<u64>,
|
pub wait_seconds: Option<u64>,
|
||||||
/// Maximum number of messages to pop in this round-trip. Default
|
/// Maximum number of messages to pop in this round-trip. Default
|
||||||
/// (None) is 1 (single-message behaviour — exactly what you want
|
/// (None) is 5 — a small batch, so a burst of related messages
|
||||||
/// when you're called to drive a turn off the first wake). Pass
|
/// lands in one call without an extra round-trip. Pass `max: 1`
|
||||||
/// a higher value (capped at 32 server-side) when you've been
|
/// for strict single-message behaviour, or a higher value (capped
|
||||||
/// told the inbox has more queued (the wake prompt mentions
|
/// at 32 server-side) when the wake prompt mentions a bigger
|
||||||
/// pending count) and want to drain everything in one tool call.
|
/// pending count. Once the long-poll wakes up, the call drains up
|
||||||
/// Once the long-poll wakes up, the call drains up to `max` in
|
/// to `max` in total before returning.
|
||||||
/// total before returning — no extra round-trip needed.
|
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub max: Option<u32>,
|
pub max: Option<u32>,
|
||||||
}
|
}
|
||||||
|
|
@ -800,17 +799,18 @@ impl AgentServer {
|
||||||
#[tool(
|
#[tool(
|
||||||
description = "Pop messages from this agent's inbox. Returns one or more messages, or \
|
description = "Pop messages from this agent's inbox. Returns one or more messages, or \
|
||||||
an empty marker if nothing is waiting. \n\n\
|
an empty marker if nothing is waiting. \n\n\
|
||||||
**Single-message default**: with no args (or `max: 1`) you get the next message — \
|
**Small-batch default**: with no args you get up to 5 messages — a burst of \
|
||||||
same behaviour the harness uses to drive a turn. Without `wait_seconds` (or with 0) \
|
related messages lands in one call. Pass `max: 1` for strict single-message \
|
||||||
the call returns immediately — a cheap 'anything pending?' peek. Pass a positive \
|
behaviour. Without `wait_seconds` (or with 0) the call returns immediately — a \
|
||||||
`wait_seconds` (capped at 180) to park the turn waiting for new work — incoming \
|
cheap 'anything pending?' peek. Pass a positive `wait_seconds` (capped at 180) to \
|
||||||
messages wake you instantly, otherwise the call returns empty at the timeout. \
|
park the turn waiting for new work — incoming messages wake you instantly, \
|
||||||
That's strictly better than a fixed shell `sleep`. \n\n\
|
otherwise the call returns empty at the timeout. That's strictly better than a \
|
||||||
**Batch drain**: pass `max: N` (capped at 32) to drain up to N messages in one \
|
fixed shell `sleep`. \n\n\
|
||||||
round-trip. Use this when the wake prompt told you the inbox has more queued, or \
|
**Bigger drains**: pass `max: N` (capped at 32) when the wake prompt says the \
|
||||||
any time you expect a burst — one tool call beats N consecutive single recvs. \
|
inbox has more queued than the default batch — one tool call beats N consecutive \
|
||||||
`wait_seconds` still applies to the FIRST message; once one arrives the call drains \
|
recvs. `wait_seconds` still applies to the FIRST message; once one arrives the \
|
||||||
up to `max` in total. Empty result reported the same way regardless of `max`. \n\n\
|
call drains up to `max` in total. Empty result reported the same way regardless \
|
||||||
|
of `max`. \n\n\
|
||||||
Typical pattern: when you have nothing else useful to do, call \
|
Typical pattern: when you have nothing else useful to do, call \
|
||||||
`recv(wait_seconds: 180)` to park until something arrives."
|
`recv(wait_seconds: 180)` to park until something arrives."
|
||||||
)]
|
)]
|
||||||
|
|
@ -818,10 +818,14 @@ impl AgentServer {
|
||||||
let log = format!("{args:?}");
|
let log = format!("{args:?}");
|
||||||
run_tool_envelope("recv", log, async move {
|
run_tool_envelope("recv", log, async move {
|
||||||
let waited = args.wait_seconds.is_some_and(|w| w > 0);
|
let waited = args.wait_seconds.is_some_and(|w| w > 0);
|
||||||
|
// Tool-layer default of a small batch (5). The wire default
|
||||||
|
// stays 1: the harness turn loop also sends `max: None` and
|
||||||
|
// consumes only the first message, so bumping the server-side
|
||||||
|
// default would silently drop the rest of a popped batch.
|
||||||
let (resp, retries) = self
|
let (resp, retries) = self
|
||||||
.dispatch(hive_sh4re::Request::Recv {
|
.dispatch(hive_sh4re::Request::Recv {
|
||||||
wait_seconds: args.wait_seconds,
|
wait_seconds: args.wait_seconds,
|
||||||
max: args.max,
|
max: args.max.or(Some(5)),
|
||||||
})
|
})
|
||||||
.await;
|
.await;
|
||||||
annotate_retries(format_recv(resp, waited), retries)
|
annotate_retries(format_recv(resp, waited), retries)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue