Overview

The Services module wraps REST API endpoints (14 core services) and integrates them with React Query for automatic caching, deduplication, and optimistic updates. Each service method returns a React Query query/mutation definition, not raw promises. This ensures consistent data flow across all pages.

🔗 Service Modules

Agent Service

src/services/agent-service.ts

  • CRUD: createAgent, updateAgent, deleteAgent
  • Agent Canvas Canvas & Execution — Canvas & Execution" class="xref">Graph DSL: serializeGraph, deserializeGraph
  • List agents with pagination
  • Publish/draft versions
  • Endpoint: /api/v1/agents

Chat Service

src/services/chat-service.ts

  • Create chat session
  • Send message (with streaming)
  • Fetch chat history
  • Update title/archive
  • Endpoint: /api/v1/chats

Knowledge Service

src/services/knowledge-service.ts

  • Upload document file
  • List chunks (paginated)
  • Delete chunk
  • Re-index chunks
  • Endpoints: /api/v1/knowledge, /v1/kb

Search Service

src/services/search-service.ts

  • Semantic search query
  • Filter by doc type, date
  • Paginate results (100/page)
  • Highlight snippet matches
  • Endpoint: /api/v1/search

User Service

src/services/user-service.ts

  • Get current user profile
  • Update profile (name, avatar)
  • Change password
  • Manage API keys
  • Endpoint: /api/v1/user

Admin Service

src/services/admin-service.ts

  • List users, manage roles
  • System health/quotas
  • Audit logs
  • Backup/restore settings
  • Endpoint: /api/v1/admin

📂 Service Layer Architecture

src/services/
├── agent-service.ts      # Agent CRUD + DSL
├── chat-service.ts       # Chat & streaming
├── knowledge-service.ts  # File upload + KB mgmt
├── search-service.ts     # Vector search
├── user-service.ts       # User profile
├── admin-service.ts      # Admin API
└── api-client.ts         # Base HTTP client

🔄 React Query Integration

Pattern: Each service method returns a query/mutation definition that can be used with useQuery/useMutation.

Query Example

// In service: agent-service.ts
export const agentQueries = {
    list: (page: number) => ({
        queryKey: ['agents', page],
        queryFn: () => http.get('/api/v1/agents', { params: { page } })
    })
};

// In component: useAgentRequest hook
export const useAgentList = (page: number) => {
    const query = agentQueries.list(page);
    return useQuery({
        ...query,
        staleTime: 5 * 60 * 1000  // 5 min
    });
};

// Usage in component
const { data, isLoading, error } = useAgentList(1);

Mutation Example

// In service: agent-service.ts
export const agentMutations = {
    create: {
        mutationFn: (data: CreateAgentDTO) => 
            http.post('/api/v1/agents', data),
        onSuccess: () => {
            queryClient.invalidateQueries(['agents']);
        }
    }
};

// Usage in component
const mutation = useMutation(agentMutations.create);
mutation.mutate({ name: 'New Agent' });

⚡ Optimizations

Error Handling

Centralized error interceptor: HTTP client catches 4xx/5xx and formats errors.

// In api-client.ts
http.interceptors.response.use(
    res => res.data,
    error => {
        const msg = error.response?.data?.error || error.message;
        toast.error(msg);
        return Promise.reject(error);
    }
);

Authentication & Headers

All requests automatically include JWT token from localStorage.

// In api-client.ts
http.interceptors.request.use(config => {
    const token = localStorage.getItem('auth_token');
    if (token) {
        config.headers.Authorization = `Bearer ${token}`;
    }
    return config;
});

Proxy Routing (Dev Only)

Vite dev server proxies API calls to backend (see vite.config.ts):

proxy: {
    '/api/v1/agents': { target: 'http://localhost:9380' },
    '/api/v1/admin': { target: 'http://localhost:9383' },
    '/v1/kb': { target: 'http://localhost:9384' }
}

Common Issues & Solutions

Issue Cause Solution
Query data is undefined Still loading or cache miss Check isLoading flag before rendering
Mutation not invalidating Wrong queryKey Use queryClient.invalidateQueries({ queryKey: ['agents'] })
Request hangs (CORS error) Dev server proxy not configured Add proxy to vite.config.ts

Next Steps

Services Module/{{SUBMOD_NAME}}/ — {{SUBMOD_TITLE}}

{{SUBMOD_PURPOSE}}

{{SUBMOD_DESC}}

N
Classes
N
Files
~N k
Lines
N
Key Metric

📚 What is this & why does it exist?

{{SUBMOD_WHAT_WHY}} — Replace with 2-4 plain-English sentences explaining what this sub-module does and why it exists. No jargon. Target audience: someone who hasn't read the code.

💡 Real-world analogy

{{SUBMOD_ANALOGY}} — Replace with a vivid, concrete metaphor mapping this sub-module's core concept to everyday life (restaurant, airport, library, highway, etc.). 3-5 sentences.

🤔 Why Is It Designed This Way?

{{DESIGN_RATIONALE}} — 150+ words explaining the design choices: what pattern does this follow and why? What constraints shaped the implementation? What trade-offs were made and what was sacrificed?

Design ChoiceWhat Was ChosenWhat Was RejectedWhy
Example: data layoutArray of structsStruct of arraysRandom access pattern dominates; cache locality for single items matters more than SIMD sweeps

Contents

Architecture

flowchart TD
  A["Component A"] --> B["Component B"]
  B --> C["Component C"]
  C --> D["Component D"]

Key Classes

Class / FunctionFilePurpose
ClassNamefile.hBrief description

Data Structures

TypeNameDescription
enumEnumNameBrief description

Interactions

DirectionPartnerInterfaceDescription
→Other ModulemethodName()Brief description

Configuration

Knob / ParameterDefaultDescription
param_namevalueWhat it controls

Directory Map

Source tree for {{SUBMOD_NAME}}
submod_name/
├── file_a.ext                 ← Role: brief annotation
├── file_b.ext                 ← Role: brief annotation
├── file_c.ext                 ← Role: brief annotation
└── index.ext                  ← Role: entry point

📑 Annotated Code Walkthrough

The most important code in this sub-module, annotated with WHY each piece exists:

{{KEY_FUNCTION_NAME}}

// Replace with actual code from the source
void key_function() {
    // ← WHY: Explain the purpose of this line
    // ← WHY: What constraint or requirement drives this?
}

Line-by-line:

  • Line N: What this does and WHY — what would break if removed
  • Line M: The design choice here — why this approach over the obvious alternative

⚠️ Edge Cases & Boundaries

Edge CaseWhat HappensWhere in CodeRisk Level
Empty inputHow it's handledfunction_name:line🟢 Low
Concurrent accessHow it's handledfunction_name:line🔴 High

Deep-Dive Highlights

Core mechanisms from this sub-module have been extracted into dedicated focus pages for in-depth exploration. Each page covers one algorithm, protocol, or subsystem with diagrams, code walks, and configuration details.

Deep-Dive Pages

Topic A Name Focus

Short description of what this focus page covers.

Extracted topic page

Topic B Name Focus

Short description of what this focus page covers.

Extracted topic page

Code Examples

Example: Typical Usage

// Replace with actual code example
void example() {
    // ...
}