Update Agent Documentation and MCP Tool Configuration
- Revised the API access endpoint in the agent documentation to reflect the new structure. - Expanded examples for agent hooks, database queries, and MCP tools, providing clearer guidance for users. - Updated MCP tool configuration to use 'label' instead of 'name' and refined transport types for better clarity. - Introduced input schema definitions for process transport tools, enhancing the documentation on tool mapping and error handling.
This commit is contained in:
parent
bdfe7e83e8
commit
ef00880960
3 changed files with 464 additions and 41 deletions
103
agent/README.md
103
agent/README.md
|
|
@ -78,7 +78,87 @@ yao agent test -i "Hello, how are you?"
|
|||
yao start
|
||||
```
|
||||
|
||||
Access via API: `POST /api/__yao/agent`
|
||||
Access via API: `POST /v1/chat/completions`
|
||||
|
||||
## Examples
|
||||
|
||||
### Hook: Route to Specialist
|
||||
|
||||
```typescript
|
||||
// src/index.ts
|
||||
function Create(ctx: agent.Context, messages: agent.Message[]): agent.Create {
|
||||
const last = messages[messages.length - 1]?.content || "";
|
||||
if (last.includes("refund")) {
|
||||
return { delegate: { agent_id: "refund-specialist", messages } };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
```
|
||||
|
||||
### Database Query
|
||||
|
||||
```json
|
||||
// package.yao - Enable auto DB search
|
||||
{ "db": { "models": ["orders", "products"] } }
|
||||
```
|
||||
|
||||
```bash
|
||||
# Test: Agent auto-generates QueryDSL and searches database
|
||||
yao agent test -i "Find orders over $1000 from last month"
|
||||
```
|
||||
|
||||
### MCP Tools (Process Transport)
|
||||
|
||||
```json
|
||||
// mcps/tools.mcp.yao - Define MCP server with Yao Processes
|
||||
{
|
||||
"label": "Tools",
|
||||
"transport": "process",
|
||||
"tools": {
|
||||
"search_orders": "models.order.Paginate",
|
||||
"create_order": "models.order.Create"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
// mcps/mapping/tools/schemes/search_orders.in.yao - Input schema
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"keyword": { "type": "string" },
|
||||
"page": { "type": "integer" }
|
||||
},
|
||||
"x-process-args": [":arguments"]
|
||||
}
|
||||
```
|
||||
|
||||
```json
|
||||
// package.yao
|
||||
{ "mcp": { "servers": [{ "server_id": "tools" }] } }
|
||||
```
|
||||
|
||||
### Sidebar Page (Display Data)
|
||||
|
||||
Pages render in the right sidebar during conversation to display structured data:
|
||||
|
||||
```html
|
||||
<!-- pages/result/result.html - Display query results -->
|
||||
<div class="result-panel">
|
||||
<h3>{{ title }}</h3>
|
||||
<table s:if="{{ rows.length > 0 }}">
|
||||
<tr s:for="{{ rows }}" s:for-item="row">
|
||||
<td>{{ row.name }}</td>
|
||||
<td>{{ row.value }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
```
|
||||
|
||||
```bash
|
||||
yao sui build agent # Build pages
|
||||
# Rendered via ctx.Send({ type: "page", props: { page: "result", data: {...} } })
|
||||
```
|
||||
|
||||
## Documentation
|
||||
|
||||
|
|
@ -88,6 +168,7 @@ Access via API: `POST /api/__yao/agent`
|
|||
- [Context API](docs/context-api.md) - Messaging, memory, trace, MCP
|
||||
- [MCP Integration](docs/mcp.md) - Tool servers and resources
|
||||
- [Search](docs/search.md) - Web, knowledge base, and database search
|
||||
- [Pages](docs/pages.md) - Web UI for agents (SUI framework)
|
||||
- [Internationalization](docs/i18n.md) - Multi-language support
|
||||
- [Testing](docs/testing.md) - Agent testing framework
|
||||
|
||||
|
|
@ -136,13 +217,19 @@ flowchart LR
|
|||
|
||||
## API Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
| ------------------------------- | ------ | ------------------- |
|
||||
| `/api/__yao/agent` | POST | Chat with assistant |
|
||||
| `/api/__yao/agent/history` | GET | Get chat history |
|
||||
| `/api/__yao/agent/chats` | GET | List chat sessions |
|
||||
| `/api/__yao/agent/assistants` | GET | List assistants |
|
||||
| `/api/__yao/agent/upload/:type` | POST | Upload files |
|
||||
OpenAPI endpoints (base URL: `/v1`):
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
| -------------------------------------- | ------ | --------------------- |
|
||||
| `/v1/chat/completions` | POST | Chat with assistant |
|
||||
| `/v1/chat/sessions` | GET | List chat sessions |
|
||||
| `/v1/chat/sessions/:chat_id` | GET | Get chat session |
|
||||
| `/v1/chat/sessions/:chat_id/messages` | GET | Get messages |
|
||||
| `/v1/agent/assistants` | GET | List assistants |
|
||||
| `/v1/agent/assistants/:id` | GET | Get assistant details |
|
||||
| `/v1/file/:uploaderID` | POST | Upload files |
|
||||
| `/v1/file/:uploaderID/:fileID` | GET | Get file info |
|
||||
| `/v1/file/:uploaderID/:fileID/content` | GET | Download file |
|
||||
|
||||
## License
|
||||
|
||||
|
|
|
|||
|
|
@ -8,40 +8,43 @@ Create `mcps/tools.mcp.yao` in the assistant directory:
|
|||
|
||||
```json
|
||||
{
|
||||
"name": "Tools",
|
||||
"label": "Tools",
|
||||
"description": "Custom tools for the assistant",
|
||||
"transport": "process",
|
||||
"process": {
|
||||
"command": "node",
|
||||
"args": ["server.js"]
|
||||
"tools": {
|
||||
"search": "scripts.tools.Search",
|
||||
"create": "models.data.Create"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Transport Types
|
||||
|
||||
**Process (Local)**
|
||||
**Process (Yao Internal)**
|
||||
|
||||
Map Yao Processes directly to MCP tools:
|
||||
|
||||
```json
|
||||
{
|
||||
"transport": "process",
|
||||
"process": {
|
||||
"command": "python",
|
||||
"args": ["mcp_server.py"],
|
||||
"env": { "API_KEY": "$ENV.API_KEY" }
|
||||
"tools": {
|
||||
"search": "models.data.Paginate",
|
||||
"create": "models.data.Create"
|
||||
},
|
||||
"resources": {
|
||||
"detail": "models.data.Find"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**HTTP**
|
||||
**STDIO (Local Server)**
|
||||
|
||||
```json
|
||||
{
|
||||
"transport": "http",
|
||||
"http": {
|
||||
"url": "https://mcp.example.com",
|
||||
"headers": { "Authorization": "Bearer $ENV.TOKEN" }
|
||||
}
|
||||
"transport": "stdio",
|
||||
"command": "python",
|
||||
"arguments": ["mcp_server.py"],
|
||||
"env": { "API_KEY": "$ENV.API_KEY" }
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -50,9 +53,8 @@ Create `mcps/tools.mcp.yao` in the assistant directory:
|
|||
```json
|
||||
{
|
||||
"transport": "sse",
|
||||
"sse": {
|
||||
"url": "https://mcp.example.com/events"
|
||||
}
|
||||
"url": "https://mcp.example.com/events",
|
||||
"authorization_token": "$ENV.TOKEN"
|
||||
}
|
||||
```
|
||||
|
||||
|
|
@ -159,27 +161,37 @@ const prompts = ctx.mcp.ListPrompts("server-id");
|
|||
const prompt = ctx.mcp.GetPrompt("server-id", "system", { role: "helper" });
|
||||
```
|
||||
|
||||
## Tool Mapping
|
||||
## Tool Schema Mapping
|
||||
|
||||
Map MCP tools to Yao processes:
|
||||
Define input schemas for process transport tools:
|
||||
|
||||
```
|
||||
mcps/
|
||||
└── mapping/
|
||||
└── tools/
|
||||
├── search.yao
|
||||
└── calculate.yao
|
||||
└── <server-id>/
|
||||
└── schemes/
|
||||
├── search.in.yao # Input schema
|
||||
└── search.out.yao # Output schema (optional)
|
||||
```
|
||||
|
||||
**mapping/tools/search.yao**
|
||||
**mapping/tools/schemes/search.in.yao**
|
||||
|
||||
```json
|
||||
{
|
||||
"process": "scripts.search.Execute",
|
||||
"args": ["{{input}}"]
|
||||
"type": "object",
|
||||
"description": "Search data",
|
||||
"properties": {
|
||||
"keyword": { "type": "string" },
|
||||
"page": { "type": "integer" }
|
||||
},
|
||||
"x-process-args": [":arguments"]
|
||||
}
|
||||
```
|
||||
|
||||
The `x-process-args` maps MCP arguments to Yao Process parameters:
|
||||
- `":arguments"` - Pass entire arguments object
|
||||
- `"$args.field"` - Extract specific field
|
||||
|
||||
## Error Handling
|
||||
|
||||
```typescript
|
||||
|
|
@ -208,12 +220,12 @@ function Next(ctx: agent.Context, payload: agent.Payload): agent.Next {
|
|||
|
||||
```json
|
||||
{
|
||||
"name": "Calculator",
|
||||
"label": "Calculator",
|
||||
"description": "Math operations",
|
||||
"transport": "process",
|
||||
"process": {
|
||||
"command": "node",
|
||||
"args": ["calc-server.js"]
|
||||
"tools": {
|
||||
"add": "scripts.math.Add",
|
||||
"multiply": "scripts.math.Multiply"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -226,7 +238,7 @@ function Next(ctx: agent.Context, payload: agent.Payload): agent.Next {
|
|||
"connector": "gpt-4o",
|
||||
"mcp": {
|
||||
"servers": [
|
||||
{ "server_id": "agents.assistant.calculator", "tools": ["add", "multiply"] }
|
||||
{ "server_id": "calculator", "tools": ["add", "multiply"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
@ -242,7 +254,7 @@ function Create(ctx: agent.Context, messages: agent.Message[]): agent.Create {
|
|||
// Enable calculator
|
||||
return {
|
||||
messages,
|
||||
mcp_servers: [{ server_id: "agents.assistant.calculator" }]
|
||||
mcp_servers: [{ server_id: "calculator" }]
|
||||
};
|
||||
}
|
||||
return { messages };
|
||||
|
|
@ -252,7 +264,7 @@ function Next(ctx: agent.Context, payload: agent.Payload): agent.Next {
|
|||
const { tools } = payload;
|
||||
|
||||
if (tools?.length > 0) {
|
||||
const calcResult = tools.find(t => t.server.includes("calculator"));
|
||||
const calcResult = tools.find(t => t.server === "calculator");
|
||||
if (calcResult?.result) {
|
||||
return {
|
||||
data: {
|
||||
|
|
|
|||
324
agent/docs/pages.md
Normal file
324
agent/docs/pages.md
Normal file
|
|
@ -0,0 +1,324 @@
|
|||
# Agent Pages
|
||||
|
||||
Agent Pages provide a built-in SUI (Simple User Interface) framework for building web interfaces for AI agents. Pages are automatically loaded from the `/agent/template/` directory for global templates and `/assistants/<name>/pages/` for individual assistant pages.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
<app>/
|
||||
├── agent/
|
||||
│ └── template/ # Global template directory
|
||||
│ ├── __document.html # Document template
|
||||
│ ├── __data.json # Global data
|
||||
│ ├── __assets/ # Global assets
|
||||
│ │ ├── css/
|
||||
│ │ ├── js/
|
||||
│ │ └── images/
|
||||
│ ├── pages/ # Global pages (login, error, etc.)
|
||||
│ │ └── login/
|
||||
│ │ └── login.html
|
||||
│ └── __locales/ # Internationalization
|
||||
│
|
||||
└── assistants/
|
||||
└── my-assistant/
|
||||
├── package.yao
|
||||
└── pages/ # Assistant-specific pages
|
||||
├── index/
|
||||
│ ├── index.html
|
||||
│ ├── index.css
|
||||
│ ├── index.ts
|
||||
│ └── index.backend.ts
|
||||
└── __assets/ # Optional assistant assets
|
||||
```
|
||||
|
||||
## Route Mapping
|
||||
|
||||
| File Path | Public URL |
|
||||
|-----------|------------|
|
||||
| `/agent/template/pages/login/login.html` | `/agents/login` |
|
||||
| `/assistants/demo/pages/index/index.html` | `/agents/demo/index` |
|
||||
| `/assistants/demo/pages/chat/chat.html` | `/agents/demo/chat` |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Create Document Template
|
||||
|
||||
**`/agent/template/__document.html`**:
|
||||
|
||||
```html
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>{{ $global.title }}</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" href="/agents/assets/images/favicon.png">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">{{ __page }}</div>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
|
||||
### 2. Create Global Data
|
||||
|
||||
**`/agent/template/__data.json`**:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "AI Agent",
|
||||
"version": "1.0.0"
|
||||
}
|
||||
```
|
||||
|
||||
### 3. Create a Page
|
||||
|
||||
**`/assistants/my-assistant/pages/index/index.html`**:
|
||||
|
||||
```html
|
||||
<div id="chat-page" class="page">
|
||||
<h1>{{ title }}</h1>
|
||||
<div class="messages" s:for="{{ messages }}" s:for-item="msg">
|
||||
<div class="message {{ msg.role }}">{{ msg.content }}</div>
|
||||
</div>
|
||||
<input type="text" s:on-keypress="handleInput" placeholder="Type a message...">
|
||||
</div>
|
||||
```
|
||||
|
||||
**`/assistants/my-assistant/pages/index/index.json`**:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Chat",
|
||||
"messages": []
|
||||
}
|
||||
```
|
||||
|
||||
**`/assistants/my-assistant/pages/index/index.css`**:
|
||||
|
||||
```css
|
||||
.page {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
padding: 24px;
|
||||
}
|
||||
|
||||
.messages {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.message.user {
|
||||
align-self: flex-end;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.message.assistant {
|
||||
align-self: flex-start;
|
||||
background: #f0f0f0;
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Add Backend Script
|
||||
|
||||
**`/assistants/my-assistant/pages/index/index.backend.ts`**:
|
||||
|
||||
```typescript
|
||||
function BeforeRender(request: Request): Record<string, any> {
|
||||
const chatId = request.query.chat_id;
|
||||
return {
|
||||
messages: chatId ? Process("scripts.chat.GetHistory", chatId) : [],
|
||||
user: request.authorized?.user_id
|
||||
};
|
||||
}
|
||||
|
||||
function ApiGetData(request: Request): any {
|
||||
const { id } = request.payload;
|
||||
return Process("models.data.Find", id, {});
|
||||
}
|
||||
```
|
||||
|
||||
### 5. Add Frontend Script
|
||||
|
||||
**`/assistants/my-assistant/pages/index/index.ts`**:
|
||||
|
||||
```typescript
|
||||
function index(component: HTMLElement) {
|
||||
this.root = component;
|
||||
this.store = new __sui_store(component);
|
||||
|
||||
this.handleClick = async (event: Event) => {
|
||||
const data = await this.backend.ApiGetData({ id: 1 });
|
||||
console.log(data);
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
### 6. Build and Run
|
||||
|
||||
```bash
|
||||
# Build pages
|
||||
yao sui build agent
|
||||
|
||||
# Or watch for changes
|
||||
yao sui watch agent
|
||||
|
||||
# Start server
|
||||
yao start
|
||||
```
|
||||
|
||||
Access at: `http://localhost:5099/agents/my-assistant/index`
|
||||
|
||||
## Template Syntax
|
||||
|
||||
### Data Binding
|
||||
|
||||
```html
|
||||
<!-- Simple binding -->
|
||||
<h1>{{ title }}</h1>
|
||||
|
||||
<!-- Object properties -->
|
||||
<p>{{ user.name }}</p>
|
||||
|
||||
<!-- With default value -->
|
||||
<p>{{ description || "No description" }}</p>
|
||||
```
|
||||
|
||||
### Conditionals
|
||||
|
||||
```html
|
||||
<div s:if="{{ isLoggedIn }}">Welcome, {{ user.name }}!</div>
|
||||
<div s:elif="{{ isGuest }}">Welcome, Guest!</div>
|
||||
<div s:else>Please log in</div>
|
||||
```
|
||||
|
||||
### Loops
|
||||
|
||||
```html
|
||||
<ul>
|
||||
<li s:for="{{ items }}" s:for-item="item" s:for-index="i">
|
||||
{{ i + 1 }}. {{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
```
|
||||
|
||||
### Events
|
||||
|
||||
```html
|
||||
<button s:on-click="handleClick">Click Me</button>
|
||||
<input s:on-change="handleChange" s:on-keypress="handleKeypress">
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
Pages can use other pages as components:
|
||||
|
||||
```html
|
||||
<import s:as="Header" s:from="/shared/header" />
|
||||
<import s:as="Footer" s:from="/shared/footer" />
|
||||
|
||||
<div class="page">
|
||||
<Header title="My Page" />
|
||||
<main>Content</main>
|
||||
<Footer />
|
||||
</div>
|
||||
```
|
||||
|
||||
## Built-in Variables
|
||||
|
||||
| Variable | Description |
|
||||
|----------|-------------|
|
||||
| `$global` | Global data from `__data.json` |
|
||||
| `$query` | URL query parameters |
|
||||
| `$param` | URL path parameters |
|
||||
| `$payload` | POST request body |
|
||||
| `$cookie` | Cookie values |
|
||||
| `$url` | Current URL info |
|
||||
| `$theme` | Current theme |
|
||||
| `$locale` | Current locale |
|
||||
| `$auth` | OAuth authorization info (if authenticated) |
|
||||
|
||||
## Page Configuration
|
||||
|
||||
Create `<page>.config` for page settings:
|
||||
|
||||
```json
|
||||
{
|
||||
"title": "Page Title",
|
||||
"guard": "bearer-jwt",
|
||||
"cache": 3600,
|
||||
"data": {
|
||||
"key": "value"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Asset Paths
|
||||
|
||||
- **Global assets**: `/agents/assets/...` → `/agent/template/__assets/...`
|
||||
- **Assistant assets**: `/agents/<id>/assets/...` → `/assistants/<id>/pages/__assets/...`
|
||||
|
||||
## Build Output
|
||||
|
||||
```
|
||||
<app>/public/agents/
|
||||
├── assets/
|
||||
│ ├── libsui.min.js # SUI frontend SDK
|
||||
│ ├── css/ # Global CSS
|
||||
│ ├── js/ # Global JS
|
||||
│ └── images/ # Global images
|
||||
│
|
||||
├── login.sui # Global page
|
||||
├── login.cfg
|
||||
│
|
||||
└── my-assistant/
|
||||
├── index.sui # Assistant page
|
||||
└── index.cfg
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
Pages default to public access. To require authentication:
|
||||
|
||||
**`/assistants/my-assistant/pages/dashboard/dashboard.config`**:
|
||||
|
||||
```json
|
||||
{
|
||||
"guard": "bearer-jwt"
|
||||
}
|
||||
```
|
||||
|
||||
Available guards:
|
||||
|
||||
| Guard | Description |
|
||||
|-------|-------------|
|
||||
| `-` | No authentication (default) |
|
||||
| `bearer-jwt` | JWT token in Authorization header |
|
||||
| `cookie-jwt` | JWT token in cookie |
|
||||
| `oauth` | OAuth 2.0 authentication |
|
||||
|
||||
## Frontend API
|
||||
|
||||
The SUI frontend SDK provides:
|
||||
|
||||
```typescript
|
||||
// Backend calls
|
||||
const data = await this.backend.ApiMethodName(payload);
|
||||
|
||||
// State management
|
||||
this.store.Set("key", value);
|
||||
const value = this.store.Get("key");
|
||||
|
||||
// OpenAPI client (if using oauth guard)
|
||||
const response = await OpenAPI.Get("/api/endpoint");
|
||||
await OpenAPI.Post("/api/endpoint", data);
|
||||
```
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [SUI Template Syntax](../../sui/docs/template-syntax.md)
|
||||
- [SUI Data Binding](../../sui/docs/data-binding.md)
|
||||
- [SUI Components](../../sui/docs/components.md)
|
||||
- [SUI Frontend API](../../sui/docs/frontend-api.md)
|
||||
Loading…
Add table
Reference in a new issue