feat(agent): cross-char search_items tool + bump timeouts
Adds an MCP tool wrapping the inventory-service /search/items endpoint with include_all_characters=true, so questions like 'find me a bracelet with Legendary Acid Ward on any unequipped char' resolve in ONE tool call instead of looping get_inventory over 60+ chars (which timed out at 120s). - agent/tools.py: search_items_global wrapper - agent/mcp_overlord.py: register new tool with detailed schema doc - agent/claude_wrapper.py: include in --allowed-tools whitelist; bump timeout 120s -> 240s - nginx/overlord.conf: bump /api/agent/ proxy timeout 180s -> 300s - CLAUDE.md: brief Claude to USE search_items for cross-char searches
This commit is contained in:
parent
d3943e894c
commit
4ae18536be
5 changed files with 82 additions and 8 deletions
|
|
@ -297,6 +297,40 @@ async def get_inventory_search(
|
|||
return resp.json()
|
||||
|
||||
|
||||
async def search_items_global(filters: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Cross-character item search via the inventory service's /search/items.
|
||||
|
||||
Use this INSTEAD of looping per-character when the user asks "find an X
|
||||
on any of my chars" — one DB query vs. 60+ HTTP roundtrips.
|
||||
|
||||
Common filter keys (passed straight through as query params):
|
||||
include_all_characters: bool (set true to search every char)
|
||||
character: str (single char) | characters: "A,B,C"
|
||||
text: str (name/description substring)
|
||||
has_spell: "Legendary Acid Ward" — exact spell name
|
||||
spell_contains: "Legendary" — substring match
|
||||
legendary_cantrips: "Foo,Bar"
|
||||
equipment_status: "equipped" | "unequipped"
|
||||
equipment_slot: int (bitmask: 4=chest, 2048=bracelet, 4096=ring, ...)
|
||||
slot_names: "Bracelet,Ring"
|
||||
armor_only / jewelry_only / weapon_only: bool
|
||||
min_armor / max_armor / min_damage / max_damage: int
|
||||
...and many more — see /search/items endpoint docs.
|
||||
"""
|
||||
client = await _http()
|
||||
# Default to all-character search if caller didn't scope; otherwise the
|
||||
# endpoint refuses with a 400.
|
||||
params = dict(filters or {})
|
||||
if not any(
|
||||
k in params
|
||||
for k in ("character", "characters", "include_all_characters")
|
||||
):
|
||||
params["include_all_characters"] = True
|
||||
resp = await client.get("/search/items", params=params)
|
||||
resp.raise_for_status()
|
||||
return resp.json()
|
||||
|
||||
|
||||
async def get_combat_stats(character_name: str) -> dict[str, Any]:
|
||||
"""Lifetime + session combat stats for one character (per-element split,
|
||||
monster encounters, surge counts)."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue