fix: chat agent auth, auto-submit/dispatch, no confirmation prompts
- All httpx tool calls use real user_id instead of uuid(int=0) for service token — fixes 401 Unauthorized on dispatch/override - create_order auto-submits and auto-dispatches in one step - System prompt updated: execute immediately without asking for confirmation, respond in user's language - Product search returns CAD dimensions (dim_x/y/z_mm) - query_database tool description includes cad_files schema Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -29,7 +29,7 @@ You can:
|
|||||||
- Check material mapping status
|
- Check material mapping status
|
||||||
- Query the database for statistics
|
- Query the database for statistics
|
||||||
|
|
||||||
Always be concise and helpful. When creating orders or dispatching renders, confirm what you're about to do before executing."""
|
Always be concise and helpful. Execute actions immediately without asking for confirmation — the user expects you to act, not ask. If creating an order, also submit and dispatch it automatically. Combine multiple steps into one action when possible. Respond in the same language the user writes in."""
|
||||||
|
|
||||||
# ── Tool definitions (OpenAI function-calling schema) ────────────────────────
|
# ── Tool definitions (OpenAI function-calling schema) ────────────────────────
|
||||||
|
|
||||||
@@ -276,17 +276,17 @@ async def _execute_tool(
|
|||||||
elif name == "create_order":
|
elif name == "create_order":
|
||||||
return await _tool_create_order(db, tenant_id, user_id, **arguments)
|
return await _tool_create_order(db, tenant_id, user_id, **arguments)
|
||||||
elif name == "dispatch_renders":
|
elif name == "dispatch_renders":
|
||||||
return await _tool_dispatch_renders(db, tenant_id, **arguments)
|
return await _tool_dispatch_renders(db, tenant_id, user_id, **arguments)
|
||||||
elif name == "get_order_status":
|
elif name == "get_order_status":
|
||||||
return await _tool_get_order_status(db, tenant_id, **arguments)
|
return await _tool_get_order_status(db, tenant_id, **arguments)
|
||||||
elif name == "set_material_override":
|
elif name == "set_material_override":
|
||||||
return await _tool_set_material_override(db, tenant_id, **arguments)
|
return await _tool_set_material_override(db, tenant_id, user_id, **arguments)
|
||||||
elif name == "set_render_overrides":
|
elif name == "set_render_overrides":
|
||||||
return await _tool_set_render_overrides(db, tenant_id, **arguments)
|
return await _tool_set_render_overrides(db, tenant_id, user_id, **arguments)
|
||||||
elif name == "get_render_stats":
|
elif name == "get_render_stats":
|
||||||
return await _tool_get_render_stats(db, tenant_id)
|
return await _tool_get_render_stats(db, tenant_id)
|
||||||
elif name == "check_materials":
|
elif name == "check_materials":
|
||||||
return await _tool_check_materials(db, tenant_id, **arguments)
|
return await _tool_check_materials(db, tenant_id, user_id, **arguments)
|
||||||
elif name == "query_database":
|
elif name == "query_database":
|
||||||
return await _tool_query_database(db, tenant_id, **arguments)
|
return await _tool_query_database(db, tenant_id, **arguments)
|
||||||
else:
|
else:
|
||||||
@@ -400,17 +400,45 @@ async def _tool_create_order(
|
|||||||
)
|
)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
data = resp.json()
|
data = resp.json()
|
||||||
return json.dumps({
|
order_id = data["id"]
|
||||||
"order_id": data["id"],
|
order_number = data["order_number"]
|
||||||
"order_number": data["order_number"],
|
result_info = {
|
||||||
|
"order_id": order_id,
|
||||||
|
"order_number": order_number,
|
||||||
"status": data["status"],
|
"status": data["status"],
|
||||||
"line_count": data.get("line_count", len(lines)),
|
"line_count": data.get("line_count", len(lines)),
|
||||||
}, indent=2)
|
}
|
||||||
|
|
||||||
|
# Auto-submit the order
|
||||||
|
try:
|
||||||
|
submit_resp = await client.post(
|
||||||
|
f"/api/orders/{order_id}/submit",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
)
|
||||||
|
submit_resp.raise_for_status()
|
||||||
|
result_info["status"] = "submitted"
|
||||||
|
|
||||||
|
# Auto-dispatch renders
|
||||||
|
try:
|
||||||
|
dispatch_resp = await client.post(
|
||||||
|
f"/api/orders/{order_id}/dispatch-renders",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
)
|
||||||
|
dispatch_resp.raise_for_status()
|
||||||
|
dispatch_data = dispatch_resp.json()
|
||||||
|
result_info["status"] = "processing"
|
||||||
|
result_info["dispatched"] = dispatch_data.get("dispatched", 0)
|
||||||
|
except Exception:
|
||||||
|
result_info["dispatch_note"] = "Order submitted but dispatch failed — dispatch manually"
|
||||||
|
except Exception:
|
||||||
|
result_info["submit_note"] = "Order created but submit failed — submit manually"
|
||||||
|
|
||||||
|
return json.dumps(result_info, indent=2)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
return json.dumps({"error": f"Failed to create order: {exc}"})
|
return json.dumps({"error": f"Failed to create order: {exc}"})
|
||||||
|
|
||||||
|
|
||||||
async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, order_id: str = "") -> str:
|
async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "") -> str:
|
||||||
"""Dispatch renders via internal httpx call."""
|
"""Dispatch renders via internal httpx call."""
|
||||||
import httpx
|
import httpx
|
||||||
from app.utils.auth import create_access_token
|
from app.utils.auth import create_access_token
|
||||||
@@ -423,7 +451,7 @@ async def _tool_dispatch_renders(db: AsyncSession, tenant_id: str, order_id: str
|
|||||||
if not check.first():
|
if not check.first():
|
||||||
return json.dumps({"error": "Order not found or not in your tenant"})
|
return json.dumps({"error": "Order not found or not in your tenant"})
|
||||||
|
|
||||||
token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id)
|
token = create_access_token(user_id, "global_admin", tenant_id)
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=60) as client:
|
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=60) as client:
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
@@ -460,7 +488,7 @@ async def _tool_get_order_status(db: AsyncSession, tenant_id: str, order_id: str
|
|||||||
return json.dumps(dict(row), indent=2, default=str)
|
return json.dumps(dict(row), indent=2, default=str)
|
||||||
|
|
||||||
|
|
||||||
async def _tool_set_material_override(db: AsyncSession, tenant_id: str, order_id: str = "", material_name: str = "") -> str:
|
async def _tool_set_material_override(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "", material_name: str = "") -> str:
|
||||||
"""Set material override via internal httpx call."""
|
"""Set material override via internal httpx call."""
|
||||||
import httpx
|
import httpx
|
||||||
from app.utils.auth import create_access_token
|
from app.utils.auth import create_access_token
|
||||||
@@ -472,7 +500,7 @@ async def _tool_set_material_override(db: AsyncSession, tenant_id: str, order_id
|
|||||||
if not check.first():
|
if not check.first():
|
||||||
return json.dumps({"error": "Order not found or not in your tenant"})
|
return json.dumps({"error": "Order not found or not in your tenant"})
|
||||||
|
|
||||||
token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id)
|
token = create_access_token(user_id, "global_admin", tenant_id)
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
|
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
@@ -486,7 +514,7 @@ async def _tool_set_material_override(db: AsyncSession, tenant_id: str, order_id
|
|||||||
return json.dumps({"error": f"Failed to set material override: {exc}"})
|
return json.dumps({"error": f"Failed to set material override: {exc}"})
|
||||||
|
|
||||||
|
|
||||||
async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, order_id: str = "", render_overrides: dict | None = None) -> str:
|
async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "", render_overrides: dict | None = None) -> str:
|
||||||
"""Set render overrides via internal httpx call."""
|
"""Set render overrides via internal httpx call."""
|
||||||
import httpx
|
import httpx
|
||||||
from app.utils.auth import create_access_token
|
from app.utils.auth import create_access_token
|
||||||
@@ -498,7 +526,7 @@ async def _tool_set_render_overrides(db: AsyncSession, tenant_id: str, order_id:
|
|||||||
if not check.first():
|
if not check.first():
|
||||||
return json.dumps({"error": "Order not found or not in your tenant"})
|
return json.dumps({"error": "Order not found or not in your tenant"})
|
||||||
|
|
||||||
token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id)
|
token = create_access_token(user_id, "global_admin", tenant_id)
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
|
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
@@ -538,7 +566,7 @@ async def _tool_get_render_stats(db: AsyncSession, tenant_id: str) -> str:
|
|||||||
return json.dumps(dict(row) if row else {}, indent=2, default=str)
|
return json.dumps(dict(row) if row else {}, indent=2, default=str)
|
||||||
|
|
||||||
|
|
||||||
async def _tool_check_materials(db: AsyncSession, tenant_id: str, order_id: str = "") -> str:
|
async def _tool_check_materials(db: AsyncSession, tenant_id: str, user_id: str = "", order_id: str = "") -> str:
|
||||||
"""Check unmapped materials for an order — uses internal API call."""
|
"""Check unmapped materials for an order — uses internal API call."""
|
||||||
import httpx
|
import httpx
|
||||||
from app.utils.auth import create_access_token
|
from app.utils.auth import create_access_token
|
||||||
@@ -550,7 +578,7 @@ async def _tool_check_materials(db: AsyncSession, tenant_id: str, order_id: str
|
|||||||
if not check.first():
|
if not check.first():
|
||||||
return json.dumps({"error": "Order not found or not in your tenant"})
|
return json.dumps({"error": "Order not found or not in your tenant"})
|
||||||
|
|
||||||
token = create_access_token(str(uuid.UUID(int=0)), "global_admin", tenant_id)
|
token = create_access_token(user_id, "global_admin", tenant_id)
|
||||||
try:
|
try:
|
||||||
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
|
async with httpx.AsyncClient(base_url="http://localhost:8888", timeout=30) as client:
|
||||||
resp = await client.get(
|
resp = await client.get(
|
||||||
|
|||||||
Reference in New Issue
Block a user