diff --git a/backend/app/services/chat_service.py b/backend/app/services/chat_service.py index 7ddf520..3d7cf2e 100644 --- a/backend/app/services/chat_service.py +++ b/backend/app/services/chat_service.py @@ -682,8 +682,60 @@ async def chat_with_agent( # Build context-aware system prompt system_content = SYSTEM_PROMPT - if context_type and context_id: - system_content += f"\n\nCurrent context: {context_type} {context_id}" + + # Load entity details for the current page context + if context_type == "order" and context_id: + try: + ctx_result = await db.execute( + text(""" + SELECT o.order_number, o.status, o.notes, o.created_at, + COUNT(ol.id) AS line_count, + COUNT(ol.id) FILTER (WHERE ol.render_status = 'completed') AS completed, + COUNT(ol.id) FILTER (WHERE ol.render_status = 'processing') AS processing, + COUNT(ol.id) FILTER (WHERE ol.render_status = 'failed') AS failed, + COUNT(ol.id) FILTER (WHERE ol.render_status = 'pending') AS pending + FROM orders o + LEFT JOIN order_lines ol ON ol.order_id = o.id + WHERE o.id = :ctx_id AND o.tenant_id = :tid + GROUP BY o.id + """), + {"ctx_id": context_id, "tid": tenant_id}, + ) + row = ctx_result.mappings().first() + if row: + system_content += ( + f"\n\nThe user is currently viewing order {row['order_number']} " + f"(ID: {context_id}, status: {row['status']}, " + f"{row['line_count']} lines: {row['completed']} completed, " + f"{row['processing']} processing, {row['failed']} failed, " + f"{row['pending']} pending). " + f"When the user says 'this order' or 'current order', they mean {row['order_number']} ({context_id})." + ) + except Exception: + system_content += f"\n\nThe user is viewing order {context_id}." + elif context_type == "product" and context_id: + try: + ctx_result = await db.execute( + text(""" + SELECT p.name, p.pim_id, p.category_key, p.baureihe, + CASE WHEN p.cad_file_id IS NOT NULL THEN true ELSE false END AS has_step + FROM products p + WHERE p.id = :ctx_id AND p.tenant_id = :tid + """), + {"ctx_id": context_id, "tid": tenant_id}, + ) + row = ctx_result.mappings().first() + if row: + system_content += ( + f"\n\nThe user is currently viewing product '{row['name']}' " + f"(ID: {context_id}, PIM-ID: {row['pim_id']}, " + f"category: {row['category_key']}, " + f"has STEP: {row['has_step']}). " + f"When the user says 'this product' or 'current product', they mean '{row['name']}' ({context_id})." + ) + except Exception: + system_content += f"\n\nThe user is viewing product {context_id}." + system_content += f"\n\nThe user's tenant_id is '{tenant_id}'. Always filter queries by this tenant_id." messages: list[dict] = [{"role": "system", "content": system_content}] diff --git a/frontend/src/components/layout/Layout.tsx b/frontend/src/components/layout/Layout.tsx index b5d40e4..ab52e18 100644 --- a/frontend/src/components/layout/Layout.tsx +++ b/frontend/src/components/layout/Layout.tsx @@ -1,4 +1,4 @@ -import { Outlet, NavLink, useNavigate, Link } from 'react-router-dom' +import { Outlet, NavLink, useNavigate, Link, useLocation } from 'react-router-dom' import { LayoutDashboard, Package, Settings, LogOut, FlaskConical, Activity, Library, Plus, SlidersHorizontal, Building2, GitBranch, Image, BellRing, Receipt, Server, Upload, Menu, X, MessageSquare } from 'lucide-react' import { useAuthStore, isAdmin as checkIsAdmin, isPrivileged as checkIsPrivileged } from '../../store/auth' import { clsx } from 'clsx' @@ -36,9 +36,20 @@ const adminOnlyNav = [ export default function Layout() { const { user, logout } = useAuthStore() const navigate = useNavigate() + const location = useLocation() const [sidebarOpen, setSidebarOpen] = useState(false) const [chatOpen, setChatOpen] = useState(false) + // Extract page context from URL for the chat agent + const chatContext = (() => { + const path = location.pathname + const orderMatch = path.match(/^\/orders\/([0-9a-f-]{36})/) + if (orderMatch) return { type: 'order', id: orderMatch[1] } + const productMatch = path.match(/^\/products\/([0-9a-f-]{36})/) + if (productMatch) return { type: 'product', id: productMatch[1] } + return { type: undefined, id: undefined } + })() + const { data: activity } = useQuery({ queryKey: ['worker-activity'], queryFn: getWorkerActivity, @@ -260,7 +271,7 @@ export default function Layout() { )} {/* Chat panel */} - {chatOpen && setChatOpen(false)} />} + {chatOpen && setChatOpen(false)} contextType={chatContext.type} contextId={chatContext.id} />} ) }