Add equip/inventory commands, report results without AI
New commands: - "Doug, equip your sword" → equips item, reports "Equipped sword." - "Doug, what do you have?" → lists actual inventory items - "Doug, check your inventory" → same Key change: command results now report DIRECTLY to chat without going through AI. No more hallucinated responses about items Doug doesn't have. Commands execute → report real result. AI is ONLY used for conversation, not for task responses. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5a42c2b881
commit
e6d4c8d377
2 changed files with 113 additions and 3 deletions
|
|
@ -592,6 +592,12 @@ class DougBrain(QObject):
|
|||
self._tasks.complete()
|
||||
return
|
||||
|
||||
# Callbacks that need special response handling
|
||||
if task.callback in ("on_equip_result", "on_inventory_report"):
|
||||
# Execute then report result directly to chat (no AI)
|
||||
self._execute_action_with_report(task)
|
||||
return
|
||||
|
||||
# Skip placeholder actions
|
||||
if task.action == "status":
|
||||
self._tasks.complete()
|
||||
|
|
@ -648,6 +654,48 @@ class DougBrain(QObject):
|
|||
|
||||
self._ws.send_request(task.action, task.params, on_response)
|
||||
|
||||
def _execute_action_with_report(self, task: Task):
|
||||
"""Execute an action and report the result directly to chat (no AI)."""
|
||||
self._state = BrainState.EXECUTING_TASK
|
||||
self._action_sent_time = time.time()
|
||||
|
||||
if task.description and task.priority >= Priority.LOW:
|
||||
log.info(f"[{task.priority.name}] {task.description}")
|
||||
|
||||
def on_response(resp: ResponseMessage):
|
||||
self._state = BrainState.IDLE
|
||||
|
||||
if task.callback == "on_equip_result":
|
||||
if resp.status == "success":
|
||||
item = task.params.get("name", "item").replace("_", " ")
|
||||
self._ws.send_request("send_chat", {"message": f"Equipped {item}."})
|
||||
self._tasks.complete()
|
||||
else:
|
||||
error = resp.error or "I don't have that item."
|
||||
self._ws.send_request("send_chat", {"message": error})
|
||||
self._tasks.cancel()
|
||||
|
||||
elif task.callback == "on_inventory_report":
|
||||
if resp.status == "success":
|
||||
items = resp.data.get("items", [])
|
||||
if items:
|
||||
# List items concisely
|
||||
item_strs = [f"{i['count']}x {i['name'].replace('_',' ')}" for i in items[:8]]
|
||||
msg = "I have: " + ", ".join(item_strs)
|
||||
if len(items) > 8:
|
||||
msg += f" and {len(items) - 8} more items"
|
||||
self._ws.send_request("send_chat", {"message": msg})
|
||||
else:
|
||||
self._ws.send_request("send_chat", {"message": "My inventory is empty."})
|
||||
self._tasks.complete()
|
||||
else:
|
||||
self._ws.send_request("send_chat", {"message": "Can't check inventory right now."})
|
||||
self._tasks.cancel()
|
||||
else:
|
||||
self._tasks.complete()
|
||||
|
||||
self._ws.send_request(task.action, task.params, on_response)
|
||||
|
||||
# ── Helpers ──
|
||||
|
||||
def _handle_idle_chat(self, task: Task):
|
||||
|
|
|
|||
|
|
@ -69,7 +69,19 @@ class CommandParser:
|
|||
r"(?:give|hand|pass|toss)\s+(?:me|us)\s+(?:a\s+|an\s+|some\s+)?(.+)",
|
||||
]
|
||||
|
||||
# Social commands
|
||||
EQUIP_PATTERNS = [
|
||||
r"(?:equip|hold|use|grab|wield|switch to|pull out|get out)\s+(?:your\s+|the\s+|a\s+|my\s+)?(.+)",
|
||||
r"(?:put on|wear)\s+(?:your\s+|the\s+|a\s+)?(.+)",
|
||||
]
|
||||
|
||||
INVENTORY_PATTERNS = [
|
||||
r"what(?:'s| is| do you have)\s+in\s+(?:your\s+)?(?:inventory|bag|pocket|backpack)",
|
||||
r"what\s+(?:do you have|are you carrying|items do you have)",
|
||||
r"show\s+(?:me\s+)?(?:your\s+)?(?:inventory|items|stuff)",
|
||||
r"check\s+(?:your\s+)?(?:inventory|items|stuff)",
|
||||
]
|
||||
|
||||
# Social/combat commands
|
||||
ATTACK_PATTERNS = [
|
||||
r"(?:attack|fight|kill|hit)\s+(?:that|this|the)?\s*(.+)",
|
||||
]
|
||||
|
|
@ -115,6 +127,12 @@ class CommandParser:
|
|||
cmd = self._try_give(msg, sender)
|
||||
if cmd: return cmd
|
||||
|
||||
cmd = self._try_equip(msg, sender)
|
||||
if cmd: return cmd
|
||||
|
||||
cmd = self._try_inventory(msg, sender)
|
||||
if cmd: return cmd
|
||||
|
||||
cmd = self._try_attack(msg, sender)
|
||||
if cmd: return cmd
|
||||
|
||||
|
|
@ -236,6 +254,30 @@ class CommandParser:
|
|||
)
|
||||
return None
|
||||
|
||||
def _try_equip(self, msg: str, sender: str) -> Optional[ParsedCommand]:
|
||||
for pattern in self.EQUIP_PATTERNS:
|
||||
match = re.search(pattern, msg, re.IGNORECASE)
|
||||
if match:
|
||||
raw_item = match.group(1).strip() if match.lastindex else ""
|
||||
# Clean up item name
|
||||
filler = {"your", "the", "a", "my", "that"}
|
||||
words = [w for w in raw_item.split() if w.lower().rstrip(".,!?") not in filler]
|
||||
if not words:
|
||||
return None
|
||||
item = "_".join(w.lower().rstrip(".,!?") for w in words[:3])
|
||||
return ParsedCommand(
|
||||
action="equip",
|
||||
target=item,
|
||||
raw_message=msg,
|
||||
)
|
||||
return None
|
||||
|
||||
def _try_inventory(self, msg: str, sender: str) -> Optional[ParsedCommand]:
|
||||
for pattern in self.INVENTORY_PATTERNS:
|
||||
if re.search(pattern, msg, re.IGNORECASE):
|
||||
return ParsedCommand(action="check_inventory", raw_message=msg)
|
||||
return None
|
||||
|
||||
def _try_attack(self, msg: str, sender: str) -> Optional[ParsedCommand]:
|
||||
for pattern in self.ATTACK_PATTERNS:
|
||||
match = re.search(pattern, msg, re.IGNORECASE)
|
||||
|
|
@ -348,9 +390,29 @@ def command_to_task(cmd: ParsedCommand, behaviors) -> Optional[Task]:
|
|||
callback="on_look_around_report",
|
||||
)
|
||||
|
||||
elif cmd.action == "equip":
|
||||
return Task(
|
||||
name=f"equip_{cmd.target}",
|
||||
priority=Priority.HIGH,
|
||||
action="equip_item",
|
||||
params={"name": cmd.target, "destination": "hand"},
|
||||
description=f"Equipping {cmd.target.replace('_', ' ')}",
|
||||
timeout=10,
|
||||
callback="on_equip_result",
|
||||
)
|
||||
|
||||
elif cmd.action == "check_inventory":
|
||||
return Task(
|
||||
name="check_inventory",
|
||||
priority=Priority.HIGH,
|
||||
action="get_inventory",
|
||||
params={},
|
||||
description="Checking inventory",
|
||||
timeout=10,
|
||||
callback="on_inventory_report",
|
||||
)
|
||||
|
||||
elif cmd.action == "go_to":
|
||||
# For named destinations, we'd need a memory system
|
||||
# For now, try to interpret as a player name
|
||||
return Task(
|
||||
name=f"go_to_{cmd.target}",
|
||||
priority=Priority.HIGH,
|
||||
|
|
|
|||
Loading…
Reference in a new issue