feat: add create_order, list_orders and update_order_status chat tools
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01V57jSQPqwkGG8BuAXg59X5
This commit is contained in:
parent
c10fd61c54
commit
c0185bbbf7
|
|
@ -776,6 +776,52 @@ MEMORY_TOOLS = [
|
|||
},
|
||||
]
|
||||
|
||||
ORDER_TOOLS = [
|
||||
{
|
||||
"name": "create_order",
|
||||
"description": "Create a new customer order, stored as a card in the 'Offen' (open) column of the Bestellungen Deck board.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"customer": {"type": "string", "description": "Customer or ordering party name"},
|
||||
"description": {"type": "string", "description": "What was ordered"},
|
||||
"due_date": {"type": "string", "description": "Optional due date in ISO 8601, e.g. 2026-09-20"},
|
||||
},
|
||||
"required": ["customer", "description"],
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "list_orders",
|
||||
"description": "List orders from the Bestellungen Deck board, optionally filtered by status.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "Filter by column: 'Offen', 'In Arbeit' or 'Erledigt'. Omit to list all.",
|
||||
"enum": ["Offen", "In Arbeit", "Erledigt"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"name": "update_order_status",
|
||||
"description": "Move an order to a different status column (e.g. mark it 'In Arbeit' or 'Erledigt'). Call list_orders first if you don't already know the order's id.",
|
||||
"input_schema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"order_id": {"type": "integer", "description": "The order's id, from list_orders or create_order"},
|
||||
"status": {
|
||||
"type": "string",
|
||||
"description": "New status column",
|
||||
"enum": ["Offen", "In Arbeit", "Erledigt"],
|
||||
},
|
||||
},
|
||||
"required": ["order_id", "status"],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
CALENDAR_ASSISTANT_INSTRUCTIONS = (
|
||||
"Du hast Zugriff auf den Kalender 'FFW-Onza-Alle' ueber die Tools "
|
||||
"list_calendar_events, create_calendar_event, update_calendar_event und "
|
||||
|
|
@ -808,6 +854,17 @@ MEMORY_ASSISTANT_INSTRUCTIONS = (
|
|||
"und frage nach, welcher gemeint ist, statt den falschen zu loeschen."
|
||||
)
|
||||
|
||||
ORDER_ASSISTANT_INSTRUCTIONS = (
|
||||
"Du hast ausserdem Zugriff auf Bestellungen ueber die Tools "
|
||||
"create_order, list_orders und update_order_status - sie leben als "
|
||||
"Karten im Nextcloud-Deck-Board 'Bestellungen' mit den Spalten Offen, "
|
||||
"In Arbeit und Erledigt. Du kannst alle drei Tools direkt aufrufen, "
|
||||
"sobald du die noetigen Angaben hast - keine Rueckfrage noetig, da "
|
||||
"nichts davon zerstoerend ist (es gibt kein Loeschen). Fuer "
|
||||
"update_order_status brauchst du die order_id - ruf dafuer zuerst "
|
||||
"list_orders auf, falls du sie noch nicht aus dem Gespraech kennst."
|
||||
)
|
||||
|
||||
|
||||
async def execute_tool(name: str, tool_input: dict) -> str:
|
||||
if name == "list_calendar_events":
|
||||
|
|
@ -845,6 +902,17 @@ async def execute_tool(name: str, tool_input: dict) -> str:
|
|||
if name == "forget_fact":
|
||||
result = await forget_fact(tool_input["query"])
|
||||
return json.dumps(result)
|
||||
if name == "create_order":
|
||||
result = await create_order(
|
||||
tool_input["customer"], tool_input["description"], tool_input.get("due_date")
|
||||
)
|
||||
return json.dumps(result)
|
||||
if name == "list_orders":
|
||||
result = await list_orders(tool_input.get("status"))
|
||||
return json.dumps(result)
|
||||
if name == "update_order_status":
|
||||
result = await update_order_status(tool_input["order_id"], tool_input["status"])
|
||||
return json.dumps(result)
|
||||
raise ValueError(f"Unknown tool: {name}")
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -263,3 +263,20 @@ async def test_update_order_status_raises_when_card_not_found():
|
|||
):
|
||||
with pytest.raises(ValueError):
|
||||
await main.update_order_status(999, "Erledigt")
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_execute_tool_dispatches_order_tools():
|
||||
with patch.object(main, "create_order", new=AsyncMock(return_value={"id": 1, "customer": "X"})):
|
||||
result = await main.execute_tool(
|
||||
"create_order", {"customer": "X", "description": "Y"}
|
||||
)
|
||||
assert json.loads(result) == {"id": 1, "customer": "X"}
|
||||
|
||||
with patch.object(main, "list_orders", new=AsyncMock(return_value=[{"id": 1}])):
|
||||
result = await main.execute_tool("list_orders", {})
|
||||
assert json.loads(result) == [{"id": 1}]
|
||||
|
||||
with patch.object(main, "update_order_status", new=AsyncMock(return_value={"id": 1, "status": "Erledigt"})):
|
||||
result = await main.execute_tool("update_order_status", {"order_id": 1, "status": "Erledigt"})
|
||||
assert json.loads(result) == {"id": 1, "status": "Erledigt"}
|
||||
|
|
|
|||
Loading…
Reference in New Issue