Skip to main content

AI Assistant

Overview

Cascadia includes an LLM-powered AI chatbot that helps users navigate, query, and modify PLM data through natural language. The assistant understands the PLM schema, respects user permissions, and can perform both read-only queries and write operations on the user's behalf.

The AI assistant is built on TanStack AI, providing provider-agnostic LLM integration with streaming responses, type-safe tool definitions, and seamless integration with the Hono API server.

Key capabilities:

  • Search for parts, documents, change orders, requirements, and tasks
  • Inspect item details, BOMs, and where-used relationships
  • Analyze change impact with risk assessment
  • Create and update items, manage relationships, transition workflow states
  • Create Engineering Change Orders (ECOs) with automatic branch setup
  • Launch collaborative design sessions from the chat
  • Navigate users to item pages with clickable buttons

All actions are permission-bounded and audit-logged.


Chat Panel UI

The AI assistant appears as a slide-out panel on the right side of the screen.

Opening the Panel

A tab-shaped button sits on the right edge of the viewport, vertically centered. Clicking it slides the chat panel into view. The button disappears while the panel is open.

  • Component: ChatPanelButton (src/components/ai/ChatPanelButton.tsx)
  • State management: ChatPanelProvider context (src/lib/ai/chat-context.tsx)
  • Keyboard shortcut: None by default (toggle via the button)

Panel Layout

The panel has four sections:

  1. Header -- Title ("Cascadia Chat"), loading indicator, and action buttons (History, New Conversation, Close)
  2. Messages area -- Scrollable message list with auto-scroll on new content
  3. Error display -- Inline error banner when requests fail
  4. Input area -- Auto-resizing textarea with Send and Search buttons

Resizing

The panel is resizable by dragging the left edge. Width is persisted to localStorage and restored on next visit.

PropertyValue
Default width400px
Minimum width300px
Maximum width700px

Message Rendering

  • User messages: Displayed as plain text in a cyan bubble, right-aligned
  • Assistant messages: Rendered as Markdown using react-markdown with remark-gfm, left-aligned in a slate bubble. Supports headings, lists, tables, code blocks, links, and blockquotes.
  • Tool calls: Shown as small monospace labels below the message text (e.g., search_items, get_bom). A "Running..." indicator appears while the tool is executing.
  • Navigation offers: Rendered as clickable buttons below the message (e.g., "View P-1001"). Internal links navigate within the app; external links open in a new tab.
  • Design workspace offers: Rendered as a "Open Design Workspace" button that navigates to the collaborative design workspace.
  • System messages: Hidden from the UI.
  • Streaming: A pulsing cursor animation appears at the end of the assistant's message while content is still streaming.

Two Input Modes

The ChatInput component provides two ways to send messages:

ModeTriggerBehavior
ChatEnter key or Send buttonFull conversational mode with all tools (read + write)
SearchCtrl+Enter or Search buttonLightweight search mode -- uses a concise prompt and only search/navigation tools

Session Persistence

Chat conversations are saved to the database so users can resume them later.

Database Schema

Three tables support AI chat persistence (defined in src/lib/db/schema/ai.ts):

ai_chat_sessions -- One row per conversation.

ColumnTypeDescription
idUUIDPrimary key
user_idUUIDSession owner (FK to users)
program_idUUIDOptional program context
design_idUUIDOptional design context
titleVARCHAR(255)Auto-generated from first user message
created_atTIMESTAMPWhen the session started
updated_atTIMESTAMPLast message timestamp

ai_chat_messages -- Message history within a session.

ColumnTypeDescription
idUUIDPrimary key
session_idUUIDParent session (FK, CASCADE delete)
roleVARCHAR(20)system, user, assistant, or tool
contentTEXTMessage content
tool_callsJSONBTool calls made by the assistant
tool_call_idVARCHAR(100)Tool response reference
tool_nameVARCHAR(100)Which tool was called
created_atTIMESTAMPMessage timestamp

Session Lifecycle

  1. Auto-creation: A session is created on the first message if none exists. The UI calls POST /api/ai/sessions before sending the first message.
  2. Title generation: The SessionService auto-generates a title from the first user message. It extracts the first sentence (up to 50 characters) or truncates at a word boundary.
  3. Message persistence: Each user message is saved before sending to the LLM. The assistant's response is saved after the stream completes.
  4. History loading: When switching sessions, the UI fetches message history via GET /api/ai/sessions/:id/messages and reconstructs the message list.
  5. Ownership: Sessions are scoped to the creating user. The verifySessionOwnership check prevents accessing other users' sessions.
  6. Cleanup: SessionService.cleanupOldSessions() retains the 50 most recent sessions per user. Messages cascade-delete with their session.

Session History UI

Clicking the History button in the panel header opens a full-panel overlay listing all past conversations, sorted by most recently updated. Each entry shows the title and date. Users can select a session to resume it or delete sessions they no longer need.


Read-Only PLM Tools

Read tools let the AI query PLM data without modifying anything. They are used freely -- no confirmation is required.

search_items

Search for items by type, text query, lifecycle state, or design.

ParameterTypeDescription
itemTypeenumPart, Document, ChangeOrder, Requirement, Task (optional)
querystringText search across item number and name
statestringFilter by lifecycle state (e.g., Draft, Released)
designIdstringDesign ID or code to scope the search
limitnumberMax results (1-50, default 20)

Returns an array of matching items with id, itemNumber, name, revision, state, itemType, and designId.

get_item_details

Get complete details for a specific item by ID or item number.

ParameterTypeDescription
idstringItem UUID
itemNumberstringItem number (e.g., P-1001)
revisionstringRevision letter (optional, defaults to current)

Returns all item fields including type-specific data (e.g., material, cost for Parts).

get_bom

Get the Bill of Materials for a part.

ParameterTypeDescription
itemIdstringParent part UUID
depthnumberLevels to traverse (1-10, default 1)

Returns child components with quantity, findNumber, referenceDesignator, and nested children if depth > 1.

get_where_used

Reverse BOM query -- find all parent assemblies that use an item.

ParameterTypeDescription
itemIdstringItem UUID
maxDepthnumberMax levels up (1-15, default 15)

Returns parent assemblies with depth information and cross-design references.

analyze_change_impact

Analyze the impact of changing a specific item.

ParameterTypeDescription
itemIdstringItem UUID
includeDocumentsbooleanInclude related documents (default true)
includeRelatedChangesbooleanFind other active ECOs affecting same items (default true)

Returns affected assemblies, related documents, related change orders, and a risk assessment with severity levels (low, medium, high, critical).

offer_navigation

Offer a clickable navigation button to the user. Used after answering questions to provide quick access to the item being discussed.

ParameterTypeDescription
itemIdstringEntity UUID
itemNumberstringDisplay number (e.g., P-1001, ECO-0001)
itemTypeenumPart, Document, ChangeOrder, Requirement, Task, Design, Program
tabenumOptional tab to open (details, relationships, history, bom, affected-items)
labelstringCustom button label (defaults to View {itemNumber})

search_programs

Search programs by name, code, customer, or status. Results are scoped to programs the user has access to.

search_designs

Search designs by name, code, type, or program. Accepts program ID or code for filtering. Excludes archived designs by default.


Write Tools

Write tools modify PLM data. Every write operation goes through a confirmation flow before executing.

create_item

Create a new Part, Document, Requirement, or Task.

ParameterTypeDescription
itemTypeenumPart, Document, Requirement, Task
namestringItem name
designIdstringDesign ID or code (required for Part/Document/Requirement)
changeOrderIdstringECO for post-release designs
partTypeenumManufacture, Purchase, Software, Phantom (Parts only)
materialstringMaterial specification (Parts only)
priorityenumlow, medium, high, critical (Tasks only)
requirementTypeenumFunctional, Performance, Interface, Constraint, Other (Requirements only)

If the target design has released items and no changeOrderId is provided, the tool suggests creating an ECO first rather than failing silently.

update_item

Update an existing item's properties (name, description, material, cost, weight, etc.). Released items on main branch require an ECO checkout first.

create_relationship

Create BOM, Document, or Affects relationships between items. Validates relationship type compatibility (e.g., BOM requires Part-to-Part). Includes validation against circular references.

transition_item_state

Transition items or ECOs through workflow states. For ECOs, uses ChangeOrderService.transitionWorkflow() which handles the full ECO lifecycle including branch merging on approval. For regular items, updates the state directly.

create_change_order

Create a new Engineering Change Order. Supports ECO, ECN, Deviation, and MCO change types. On creation:

  1. Creates the change order item in Draft state
  2. Auto-starts the workflow
  3. Adds specified designs (creating ECO branches)
  4. Adds specified affected items with appropriate change actions (revise for Released items, release for Draft items)

initiate_collaborative_design

Launch an interactive collaborative design workspace. Unlike other write tools, this does not require confirmation -- creating a design session is lightweight and non-destructive. Requires a programId (UUID or code). Returns a workspace URL that the UI renders as an "Open Design Workspace" button.


Confirmation Flow

Write operations use a two-step confirmation flow to prevent unintended modifications.

How It Works

User: "Create a new part called Motor Assembly"

1. AI calls create_item with confirmed: false
2. Tool returns { requiresConfirmation: true, confirmationMessage: "...", confirmationDetails: {...} }
3. AI renders a ConfirmationCard in the chat

User clicks "Confirm"

4. AI calls create_item again with confirmed: true
5. Tool executes the operation
6. AI reports the result (item number, success/failure)

ConfirmationCard Component

The ConfirmationCard (src/components/ai/ConfirmationCard.tsx) displays:

  • An alert icon color-coded by action type (cyan for create/update, amber for transition, red for delete)
  • The confirmation message explaining what will happen
  • Structured details: item type, item name, design name, ECO number, and additional info
  • Confirm and Cancel buttons

After responding, the card collapses to a static badge showing "Confirmed" (green) or "Cancelled" (grey).

ECO Suggestion Flow

When a write operation targets a released design without an ECO, the tool does not fail. Instead it returns a suggestCreateEco flag with a message like:

"The design 'Widget Assembly Prototype' has released items and requires an ECO to add new items. Would you like me to create an ECO first?"

The AI then offers to create the ECO before retrying the original operation.


Provider Support

The AI assistant supports multiple LLM providers through TanStack AI adapters.

Supported Providers

ProviderStatusDefault ModelAdapter
Anthropic (Claude)Supportedclaude-sonnet-4-6@tanstack/ai-anthropic
OpenAI (GPT)Supportedgpt-4.1@tanstack/ai-openai
Google (Gemini)Plannedgemini-2.0-flashNot yet implemented
Ollama (local)Plannedllama3.2Not yet implemented

Provider Selection

The getAdapter() function in src/lib/ai/adapters.ts creates the appropriate TanStack AI adapter based on the provider configuration. It accepts a provider type, model name, API key, and optional base URL.

OpenAI's adapter supports a custom baseURL parameter, which enables use with OpenAI-compatible APIs (Azure OpenAI, local proxies, etc.).


Admin Configuration

AI settings can be configured at two levels: globally or per-program.

Configuration Priority

When the chat endpoint processes a request, it resolves the provider configuration in this order:

  1. Program-specific settings -- If the session has a programId and that program has AI settings in ai_settings, use them
  2. Global settings -- If no program-specific settings exist, use the global row (where programId is NULL)
  3. Environment variables -- Fall back to OPENAI_API_KEY or ANTHROPIC_API_KEY

This allows different programs to use different providers or models.

Environment Variables

VariableDescription
OPENAI_API_KEYOpenAI API key (fallback if no DB settings)
OPENAI_MODELOverride default OpenAI model
OPENAI_BASE_URLCustom OpenAI-compatible endpoint
ANTHROPIC_API_KEYAnthropic API key (fallback if no DB settings)
ANTHROPIC_MODELOverride default Anthropic model

Settings API

The settings API (/api/ai/settings) manages provider configuration stored in the ai_settings table.

EndpointMethodPermissionDescription
/api/ai/settings?programId=...GETAuthenticatedGet settings for a scope
/api/ai/settingsPOSTai_settings:createCreate settings
/api/ai/settingsPUTai_settings:updateUpdate settings

Security: API keys stored in the database are encrypted at rest using the @/lib/crypto/encryption module. The GET endpoint masks API keys in responses (returns *** instead of the actual key). Keys with known provider prefixes (sk-, key-) are detected as plaintext and skipped during decryption.

Enabling/Disabling AI

Each settings row has an enabled boolean flag. When disabled, the chat endpoint returns a 503 response with a FEATURE_DISABLED error code. The isAIEnabled() function checks settings in the same priority order as provider config resolution.


Tool Definitions

Tools are defined using TanStack AI's toolDefinition() function with Zod schemas for both input and output validation. This provides type safety across the entire stack -- the LLM receives the schema, handlers validate against it, and TypeScript catches mismatches at compile time.

Definition Structure

Each tool definition includes:

  • name -- Unique identifier (e.g., search_items)
  • description -- Natural language description the LLM uses to decide when to call the tool
  • inputSchema -- Zod schema defining the parameters
  • outputSchema -- Zod schema defining the return type

Tool Registration

Tools are assembled in src/lib/ai/tools/index.ts:

  • createServerTools(context) -- Returns all 14 tools (8 read + 5 write + 1 design engine) bound to a user context
  • createSearchTools(context) -- Returns 5 lightweight tools (search_items, get_item_details, offer_navigation, search_programs, search_designs) for search mode

The context object carries userId, sessionId, programId, and designId through to every handler.

Complete Tool Reference

#ToolCategoryPermissionDescription
1search_itemsReadparts:readSearch items by type, query, state, design
2get_item_detailsReadparts:readGet full item details by ID or item number
3get_bomReadparts:readGet BOM children for a part
4get_where_usedReadparts:readFind parent assemblies using an item
5analyze_change_impactReadparts:readAnalyze change impact with risk assessment
6offer_navigationReadNoneGenerate navigation URL for UI button
7search_programsReadprograms:readSearch programs by name, code, customer
8search_designsReaddesigns:readSearch designs by name, code, program
9create_itemWriteparts:createCreate Part, Document, Requirement, or Task
10update_itemWriteparts:updateUpdate item properties
11create_relationshipWriteparts:updateCreate BOM, Document, or Affects relationship
12transition_item_stateWritechange_orders:updateTransition workflow state
13create_change_orderWritechange_orders:createCreate ECO with branches and affected items
14initiate_collaborative_designDesignparts:createLaunch collaborative design workspace

Architecture

System Layers

Frontend (Browser)
ChatPanel + useChat hook (@tanstack/ai-react)
fetchServerSentEvents('/api/ai/chat')
|
| SSE Stream
v
API Layer (Server)
POST /api/ai/chat
- Authenticates user
- Loads/creates session
- Loads provider config
- Builds system prompt via KnowledgeService
- Calls chat() with adapter + tools
- Returns SSE stream via toServerSentEventsResponse()
|
v
Service Layer
KnowledgeService -- Schema introspection, system prompt generation
SessionService -- Session + message persistence
Adapters -- Provider-specific TanStack AI adapters
Tool Handlers -- Permission-checked tool implementations
|
v
Database
ai_chat_sessions -- Conversation persistence
ai_chat_messages -- Message history
ai_settings -- Provider configuration
ai_usage_logs -- Audit trail for tool usage

Request Flow

  1. The user types a message in the ChatInput component
  2. ChatPanel creates a session if needed (POST /api/ai/sessions)
  3. useChat from @tanstack/ai-react sends the message via fetchServerSentEvents to POST /api/ai/chat
  4. The API handler: a. Verifies authentication and session ownership b. Checks if AI is enabled for the program scope c. Loads provider configuration (program-specific, global, or env vars) d. Calls KnowledgeService.generateSchemaContext() to reflect on the ItemTypeRegistry and build schema-aware context e. Builds a system prompt with user context, item type definitions, versioning model, and tool documentation f. Loads message history from the database g. Saves the user message h. Creates tools bound to the user's permission context via createServerTools() i. Calls chat() from @tanstack/ai with the adapter, messages, and tools j. Wraps the response stream in a toServerSentEventsResponse() with session ID header
  5. The response streams back as Server-Sent Events (SSE)
  6. useChat on the client processes chunks and updates the message list in real time
  7. After the stream completes, the assistant's full response is saved to ai_chat_messages

KnowledgeService

The KnowledgeService (src/lib/ai/KnowledgeService.ts) makes the AI schema-aware by:

  1. Reflecting on ItemTypeRegistry -- Enumerates all registered item types (Part, Document, ChangeOrder, etc.) with their fields, states, relationships, and permissions
  2. Extracting field definitions -- Converts Zod schemas to JSON Schema format, then extracts field names, types, descriptions, and required flags
  3. Building the system prompt -- Produces a structured prompt that tells the AI about available item types, the ECO-as-Branch versioning model, the user's identity and roles, and detailed instructions for each tool
  4. Search mode prompt -- A separate, concise prompt for search mode that instructs the AI to search immediately and return structured results

The system prompt includes the current program and design context, so the AI understands what scope the user is working in.

Permission Enforcement

Every tool handler is wrapped with withPermissionAndAudit() (for read tools) or withWritePermissionAndAudit() (for write tools) from src/lib/ai/tools/permission-wrapper.ts. These wrappers:

  1. Check permissions via permissionService.canUser() before executing the handler
  2. Throw on denial with a descriptive error message the AI can relay to the user
  3. Log to audit table -- Every tool invocation (success or failure) is recorded in ai_usage_logs with the tool name, parameters, result, error (if any), and duration

Audit Trail

The ai_usage_logs table records every tool invocation:

ColumnDescription
tool_nameWhich tool was called
tool_paramsInput parameters (JSONB)
tool_resultOutput result (JSONB, null on error)
errorError message if the tool failed
duration_msExecution time
user_idWho triggered the action
session_idWhich chat session
input_tokens / output_tokensToken usage (when available)
provider / modelWhich LLM was used

For write operations, the _meta field within tool_params includes additional audit data: actionType, affectedItemIds, wasConfirmed, and a transactionId.

Streaming

Responses use Server-Sent Events (SSE) for real-time streaming:

  1. chat() from @tanstack/ai returns an async iterable of chunks
  2. The API route wraps this in a transformedStream generator that accumulates the full response text
  3. toServerSentEventsResponse() converts the iterable into an SSE Response with text/event-stream content type
  4. On the client, fetchServerSentEvents (from @tanstack/ai-react) reconnects to the SSE endpoint and feeds chunks into useChat's message state
  5. The onFinish callback fires when the stream ends, triggering a session list refresh

The API sets X-Session-Id and X-Request-Id headers on the SSE response for traceability.


API Reference

EndpointMethodAuthDescription
/api/ai/chatPOSTAuthenticatedSend a chat message, receive SSE stream
/api/ai/sessionsGETAuthenticatedList user's sessions
/api/ai/sessionsPOSTAuthenticatedCreate a new session
/api/ai/sessions/:idGETAuthenticated (owner)Get session details
/api/ai/sessions/:idDELETEAuthenticated (owner)Delete session and messages
/api/ai/sessions/:id/messagesGETAuthenticated (owner)Get message history
/api/ai/settingsGETAuthenticatedGet AI settings
/api/ai/settingsPOSTai_settings:createCreate AI settings
/api/ai/settingsPUTai_settings:updateUpdate AI settings

Key Source Files

FilePurpose
src/lib/ai/adapters.tsProvider adapter factory and config loading
src/lib/ai/SessionService.tsSession and message persistence
src/lib/ai/KnowledgeService.tsSchema introspection and system prompt generation
src/lib/ai/chat-context.tsxReact context for panel state management
src/lib/ai/tools/definitions.tsRead-only tool definitions (Zod schemas)
src/lib/ai/tools/write-definitions.tsWrite tool definitions with confirmation schemas
src/lib/ai/tools/handlers.tsRead-only tool handler implementations
src/lib/ai/tools/write-handlers.tsWrite tool handler implementations
src/lib/ai/tools/permission-wrapper.tsPermission checking and audit logging wrapper
src/lib/ai/tools/design-engine-definitions.tsCollaborative design tool definition
src/lib/ai/tools/design-engine-handlers.tsCollaborative design tool handler
src/lib/ai/tools/index.tsTool assembly and exports
src/lib/db/schema/ai.tsDatabase schema for sessions, messages, settings, usage logs
src/components/ai/ChatPanel.tsxMain chat sidebar component
src/components/ai/ChatMessage.tsxMessage rendering with Markdown and tool results
src/components/ai/ChatInput.tsxInput component with Send/Search modes
src/components/ai/ChatPanelButton.tsxEdge button to open the panel
src/components/ai/ConfirmationCard.tsxConfirmation UI for write operations
src/routes/api/ai/chat.tsChat API endpoint
src/routes/api/ai/sessions.tsSession list and creation endpoints
src/routes/api/ai/sessions/$id.tsSession detail and deletion endpoints
src/routes/api/ai/sessions/$id/messages.tsMessage history endpoint
src/routes/api/ai/settings.tsAI settings CRUD endpoints