@cloudbase/agent-server 0.0.12 → 0.0.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +253 -0
- package/dist/index.d.ts +74 -5
- package/dist/index.js +123 -21
- package/package.json +2 -2
package/README.md
ADDED
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# @cloudbase/agent-server
|
|
2
|
+
|
|
3
|
+
将 AG-UI 兼容的 Agent 部署为 HTTP 服务。
|
|
4
|
+
|
|
5
|
+
## 什么是 AG-UI?
|
|
6
|
+
|
|
7
|
+
[AG-UI](https://ag-ui.com/) 是一个开放、轻量级、基于事件的协议,用于标准化 AI Agent 与用户界面的交互。它让 Agent 可以:
|
|
8
|
+
|
|
9
|
+
- 实时流式对话
|
|
10
|
+
- 双向状态同步
|
|
11
|
+
- 前端工具集成(Client Tools)
|
|
12
|
+
- 人机协作(Human-in-the-loop)
|
|
13
|
+
|
|
14
|
+
## 这个包解决什么问题?
|
|
15
|
+
|
|
16
|
+
- **快速部署 Agent 为 HTTP 服务**:一行代码将 Agent 部署为支持 AG-UI 协议的 HTTP 服务
|
|
17
|
+
- **多端点支持**:自动创建 `/send-message`、`/healthz` 等端点
|
|
18
|
+
- **云函数兼容**:自动适配腾讯云开发 HTTP 云函数环境
|
|
19
|
+
|
|
20
|
+
### 架构图
|
|
21
|
+
|
|
22
|
+
```mermaid
|
|
23
|
+
flowchart LR
|
|
24
|
+
Client[AG-UI 客户端] -->|AG-UI 协议| Server["@cloudbase/agent-server"]
|
|
25
|
+
Server --> Adapter[Adapter<br/>LangGraph / LangChain]
|
|
26
|
+
Adapter --> Agent[Agent 框架]
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## 配合使用
|
|
30
|
+
|
|
31
|
+
| 包名 | 作用 |
|
|
32
|
+
|------|------|
|
|
33
|
+
| `@cloudbase/agent-adapter-langgraph` | LangGraph 工作流适配器 |
|
|
34
|
+
| `@cloudbase/agent-adapter-langchain` | LangChain Agent 适配器 |
|
|
35
|
+
| `express` | HTTP 服务框架 |
|
|
36
|
+
|
|
37
|
+
## 安装
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pnpm add @cloudbase/agent-server express
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## 快速开始
|
|
44
|
+
|
|
45
|
+
### 方式一:使用 run(最简单)
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
import { run } from "@cloudbase/agent-server";
|
|
49
|
+
import { LanggraphAgent } from "@cloudbase/agent-adapter-langgraph";
|
|
50
|
+
import { workflow } from "./workflow.js"; // 你的 LangGraph 工作流
|
|
51
|
+
|
|
52
|
+
run({
|
|
53
|
+
createAgent: () => ({
|
|
54
|
+
agent: new LanggraphAgent({ workflow }),
|
|
55
|
+
}),
|
|
56
|
+
port: 9000,
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### 方式二:使用 createExpressServer
|
|
61
|
+
|
|
62
|
+
创建一个配置好的 Express 应用:
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { createExpressServer } from "@cloudbase/agent-server";
|
|
66
|
+
import { LanggraphAgent } from "@cloudbase/agent-adapter-langgraph";
|
|
67
|
+
import { workflow } from "./workflow.js";
|
|
68
|
+
|
|
69
|
+
const app = createExpressServer({
|
|
70
|
+
createAgent: () => ({
|
|
71
|
+
agent: new LanggraphAgent({ workflow }),
|
|
72
|
+
}),
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
app.listen(9000, () => console.log("Listening on 9000!"));
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 方式三:使用 createExpressRoutes
|
|
79
|
+
|
|
80
|
+
将路由挂载到现有的 Express 应用:
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
import { createExpressRoutes } from "@cloudbase/agent-server";
|
|
84
|
+
import { LanggraphAgent } from "@cloudbase/agent-adapter-langgraph";
|
|
85
|
+
import { workflow } from "./workflow.js";
|
|
86
|
+
import express from "express";
|
|
87
|
+
|
|
88
|
+
const app = express();
|
|
89
|
+
|
|
90
|
+
createExpressRoutes({
|
|
91
|
+
createAgent: () => ({
|
|
92
|
+
agent: new LanggraphAgent({ workflow }),
|
|
93
|
+
}),
|
|
94
|
+
express: app,
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
app.listen(9000, () => console.log("Listening on 9000!"));
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## API 参考
|
|
101
|
+
|
|
102
|
+
### run
|
|
103
|
+
|
|
104
|
+
创建并启动 HTTP 服务。
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
run({
|
|
108
|
+
createAgent,
|
|
109
|
+
port: 9000,
|
|
110
|
+
});
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
**参数:**
|
|
114
|
+
|
|
115
|
+
| 参数 | 类型 | 说明 |
|
|
116
|
+
|------|------|------|
|
|
117
|
+
| `createAgent` | `AgentCreator` | Agent 创建函数,见下方说明 |
|
|
118
|
+
| `port` | `number \| string` | 监听端口 |
|
|
119
|
+
| `basePath` | `string` | 可选,路由基础路径,默认为 `/`,云函数环境默认为 `/v1/aibot/bots/:agentId/` |
|
|
120
|
+
| `cors` | `boolean \| CorsOptions` | 可选,CORS 配置,默认启用 |
|
|
121
|
+
| `logger` | `Logger` | 可选,日志实例,用于记录服务端日志 |
|
|
122
|
+
|
|
123
|
+
### createExpressServer
|
|
124
|
+
|
|
125
|
+
创建一个配置好的 Express 应用。
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
const app = createExpressServer({
|
|
129
|
+
createAgent,
|
|
130
|
+
cors: true, // 可选,默认启用 CORS
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
**参数:**
|
|
135
|
+
|
|
136
|
+
| 参数 | 类型 | 说明 |
|
|
137
|
+
|------|------|------|
|
|
138
|
+
| `createAgent` | `AgentCreator` | Agent 创建函数,见下方说明 |
|
|
139
|
+
| `basePath` | `string` | 可选,路由基础路径 |
|
|
140
|
+
| `cors` | `boolean \| CorsOptions` | 可选,CORS 配置,默认启用 |
|
|
141
|
+
| `logger` | `Logger` | 可选,日志实例,用于记录服务端日志 |
|
|
142
|
+
|
|
143
|
+
### createExpressRoutes
|
|
144
|
+
|
|
145
|
+
将 AG-UI 路由挂载到现有的 Express 应用。
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
createExpressRoutes({
|
|
149
|
+
createAgent,
|
|
150
|
+
express: app,
|
|
151
|
+
basePath, // 可选
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**参数:**
|
|
156
|
+
|
|
157
|
+
| 参数 | 类型 | 说明 |
|
|
158
|
+
|------|------|------|
|
|
159
|
+
| `createAgent` | `AgentCreator` | Agent 创建函数,见下方说明 |
|
|
160
|
+
| `express` | `Express` | Express 应用实例 |
|
|
161
|
+
| `basePath` | `string` | 可选,路由基础路径,默认为 `/`,云函数环境默认为 `/v1/aibot/bots/:agentId/` |
|
|
162
|
+
| `logger` | `Logger` | 可选,日志实例,用于记录服务端日志 |
|
|
163
|
+
|
|
164
|
+
## 自动创建的端点
|
|
165
|
+
|
|
166
|
+
| 端点 | 说明 |
|
|
167
|
+
|------|------|
|
|
168
|
+
| `{basePath}send-message` | AG-UI 消息发送端点 |
|
|
169
|
+
| `{basePath}healthz` | 健康检查端点 |
|
|
170
|
+
|
|
171
|
+
## createAgent 参数
|
|
172
|
+
|
|
173
|
+
`createAgent` 返回一个对象:
|
|
174
|
+
- `agent`:符合 [AG-UI 协议](https://docs.ag-ui.com) 的 Agent
|
|
175
|
+
- `cleanup`:可选,请求结束后的清理函数
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
type AgentCreator = (context?: {
|
|
179
|
+
request: Request; // 当前 HTTP 请求(Web Standard Request)
|
|
180
|
+
logger?: Logger; // 日志实例(带 requestId 上下文)
|
|
181
|
+
requestId?: string; // 请求追踪 ID
|
|
182
|
+
}) => AgentCreatorResult | Promise<AgentCreatorResult>; // 支持异步
|
|
183
|
+
|
|
184
|
+
type AgentCreatorResult = {
|
|
185
|
+
agent: AbstractAgent | { toAGUIAgent(): AbstractAgent }; // AG-UI 兼容的 Agent
|
|
186
|
+
cleanup?: () => void; // 可选,清理函数
|
|
187
|
+
};
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
使用适配器将你的 Agent 框架转换为 AG-UI 兼容的 Agent:
|
|
191
|
+
|
|
192
|
+
| 适配器 | 包名 | 说明 |
|
|
193
|
+
|--------|------|------|
|
|
194
|
+
| `LanggraphAgent` | `@cloudbase/agent-adapter-langgraph` | LangGraph 工作流适配器 |
|
|
195
|
+
| `LangchainAgent` | `@cloudbase/agent-adapter-langchain` | LangChain Agent 适配器 |
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
import { LanggraphAgent } from "@cloudbase/agent-adapter-langgraph";
|
|
199
|
+
|
|
200
|
+
createAgent: () => ({
|
|
201
|
+
agent: new LanggraphAgent({ workflow }),
|
|
202
|
+
})
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**高级用法:** `createAgent` 可以接收请求上下文,也支持异步:
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
createAgent: async (context) => {
|
|
209
|
+
console.log("Request ID:", context.requestId);
|
|
210
|
+
return { agent: new LanggraphAgent({ workflow }) };
|
|
211
|
+
}
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Logger
|
|
215
|
+
|
|
216
|
+
`logger` 参数用于记录服务端日志。需要实现以下接口:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
interface Logger {
|
|
220
|
+
info?(message: string): void;
|
|
221
|
+
info?(obj: object, message?: string): void;
|
|
222
|
+
debug?(message: string): void;
|
|
223
|
+
debug?(obj: object, message?: string): void;
|
|
224
|
+
warn?(message: string): void;
|
|
225
|
+
warn?(obj: object, message?: string): void;
|
|
226
|
+
error?(message: string): void;
|
|
227
|
+
error?(obj: object, message?: string): void;
|
|
228
|
+
trace?(message: string): void;
|
|
229
|
+
trace?(obj: object, message?: string): void;
|
|
230
|
+
child?(bindings: object): Logger; // 创建带上下文的子 logger
|
|
231
|
+
}
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
**示例:**
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
// 开发环境:使用 console
|
|
238
|
+
run({ createAgent, logger: console, port: 9000 });
|
|
239
|
+
|
|
240
|
+
// 生产环境:使用 pino
|
|
241
|
+
import pino from "pino";
|
|
242
|
+
run({ createAgent, logger: pino({ level: "info" }), port: 9000 });
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## 文档
|
|
246
|
+
|
|
247
|
+
📚 完整文档请参阅 [云开发 Agent 开发指南](https://docs.cloudbase.net/ai/agent-development/)
|
|
248
|
+
|
|
249
|
+
## 相关资源
|
|
250
|
+
|
|
251
|
+
- [AG-UI 协议](https://docs.cloudbase.net/ai/agent-development/ag-ui-protocol)
|
|
252
|
+
- [框架开发指南](https://docs.cloudbase.net/ai/agent-development/frameworks/)
|
|
253
|
+
- [部署指南](https://docs.cloudbase.net/ai/agent-development/deploy/)
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,8 @@ import expressLib, { Express } from 'express';
|
|
|
4
4
|
import * as _ag_ui_client from '@ag-ui/client';
|
|
5
5
|
import { AbstractAgent, RunAgentInput } from '@ag-ui/client';
|
|
6
6
|
import cors from 'cors';
|
|
7
|
-
import { SendMessageInput } from '@cloudbase/agent-shared';
|
|
7
|
+
import { Logger, SendMessageInput } from '@cloudbase/agent-shared';
|
|
8
|
+
export { LogFn, Logger, createConsoleLogger, noopLogger } from '@cloudbase/agent-shared';
|
|
8
9
|
import { Repeater } from '@repeaterjs/repeater';
|
|
9
10
|
import * as _whatwg_node_server from '@whatwg-node/server';
|
|
10
11
|
import { OpenAI } from 'openai';
|
|
@@ -16,6 +17,10 @@ import { OpenAI } from 'openai';
|
|
|
16
17
|
interface AgentCreatorContext {
|
|
17
18
|
/** The incoming HTTP request (Web Standard Request) */
|
|
18
19
|
request: Request;
|
|
20
|
+
/** Logger instance for this request (with requestId context). Only available when using AGUI routes. */
|
|
21
|
+
logger?: Logger;
|
|
22
|
+
/** Unique request ID for tracing. Only available when using AGUI routes. */
|
|
23
|
+
requestId?: string;
|
|
19
24
|
}
|
|
20
25
|
type AgentCreatorRet = {
|
|
21
26
|
agent: AbstractAgent | {
|
|
@@ -34,6 +39,20 @@ interface ICreateServer {
|
|
|
34
39
|
cors?: boolean | cors.CorsOptions;
|
|
35
40
|
useAGUI?: boolean;
|
|
36
41
|
aguiOptions?: AGUIOptions;
|
|
42
|
+
/**
|
|
43
|
+
* Logger instance for structured logging.
|
|
44
|
+
*
|
|
45
|
+
* @default noopLogger (silent - no output)
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* // Development: see all logs
|
|
49
|
+
* createExpressServer({ createAgent, logger: console });
|
|
50
|
+
*
|
|
51
|
+
* // Production: structured JSON logs
|
|
52
|
+
* import pino from 'pino';
|
|
53
|
+
* createExpressServer({ createAgent, logger: pino({ level: 'info' }) });
|
|
54
|
+
*/
|
|
55
|
+
logger?: Logger;
|
|
37
56
|
}
|
|
38
57
|
interface IRun extends ICreateServer {
|
|
39
58
|
port?: number | string;
|
|
@@ -43,7 +62,7 @@ interface ICreateExpressRoutes extends Omit<ICreateServer, "cors"> {
|
|
|
43
62
|
}
|
|
44
63
|
declare function run(props: IRun): void;
|
|
45
64
|
declare function createExpressServer(props: ICreateServer): Express;
|
|
46
|
-
declare function createExpressRoutes({ createAgent, basePath: _basePath, express, useAGUI: _useAGUI, aguiOptions, }: ICreateExpressRoutes): expressLib.Express;
|
|
65
|
+
declare function createExpressRoutes({ createAgent, basePath: _basePath, express, useAGUI: _useAGUI, aguiOptions, logger: _logger, }: ICreateExpressRoutes): expressLib.Express;
|
|
47
66
|
interface AGUIOptions {
|
|
48
67
|
runtimeOptions?: Partial<CopilotRuntimeOptions>;
|
|
49
68
|
endpointOptions?: Partial<CreateCopilotRuntimeServerOptions>;
|
|
@@ -86,10 +105,21 @@ declare function handler$1(input: RunAgentInput, agent: AbstractAgent): Repeater
|
|
|
86
105
|
rawEvent?: any;
|
|
87
106
|
}, any, unknown>;
|
|
88
107
|
|
|
89
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Options for createServerAdapter
|
|
110
|
+
*/
|
|
111
|
+
interface CreateServerAdapterOptions {
|
|
112
|
+
/**
|
|
113
|
+
* Logger instance for structured logging.
|
|
114
|
+
* @default noopLogger (silent)
|
|
115
|
+
*/
|
|
116
|
+
logger?: Logger;
|
|
117
|
+
}
|
|
118
|
+
declare function createServerAdapter$1(createAgent: AgentCreator, options?: CreateServerAdapterOptions): _whatwg_node_server.ServerAdapter<{}, _whatwg_node_server.ServerAdapterBaseObject<{}, (request: Request) => Promise<Response>>>;
|
|
90
119
|
|
|
120
|
+
type index$3_CreateServerAdapterOptions = CreateServerAdapterOptions;
|
|
91
121
|
declare namespace index$3 {
|
|
92
|
-
export { createServerAdapter$1 as createServerAdapter, handler$1 as handler };
|
|
122
|
+
export { type index$3_CreateServerAdapterOptions as CreateServerAdapterOptions, createServerAdapter$1 as createServerAdapter, handler$1 as handler };
|
|
93
123
|
}
|
|
94
124
|
|
|
95
125
|
declare const serverAdapter: _whatwg_node_server.ServerAdapter<{}, _whatwg_node_server.ServerAdapterBaseObject<{}, () => Response>>;
|
|
@@ -119,4 +149,43 @@ declare namespace index {
|
|
|
119
149
|
export { index$2 as healthz, index$1 as openai, index$4 as sendMessage, index$3 as sendMessageAGUI };
|
|
120
150
|
}
|
|
121
151
|
|
|
122
|
-
|
|
152
|
+
/**
|
|
153
|
+
* Generates a unique request ID for tracing.
|
|
154
|
+
*
|
|
155
|
+
* The request ID is used to:
|
|
156
|
+
* 1. Correlate all logs from a single request
|
|
157
|
+
* 2. Include in error responses for debugging
|
|
158
|
+
* 3. Trace requests across distributed systems
|
|
159
|
+
*
|
|
160
|
+
* @param prefix - Optional prefix for the request ID (default: 'req')
|
|
161
|
+
* @returns A unique request ID string
|
|
162
|
+
*
|
|
163
|
+
* @example
|
|
164
|
+
* generateRequestId() // => 'req-a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
165
|
+
* generateRequestId('agui') // => 'agui-a1b2c3d4-e5f6-7890-abcd-ef1234567890'
|
|
166
|
+
*/
|
|
167
|
+
declare function generateRequestId(prefix?: string): string;
|
|
168
|
+
/**
|
|
169
|
+
* Extracts request ID from incoming request headers.
|
|
170
|
+
* Supports common request ID header conventions.
|
|
171
|
+
*
|
|
172
|
+
* Header priority (first found wins):
|
|
173
|
+
* 1. x-request-id
|
|
174
|
+
* 2. x-correlation-id
|
|
175
|
+
* 3. x-trace-id
|
|
176
|
+
*
|
|
177
|
+
* @param headers - Request headers (Headers object or plain object)
|
|
178
|
+
* @returns The request ID from headers, or undefined if not found
|
|
179
|
+
*/
|
|
180
|
+
declare function extractRequestId(headers: Headers | Record<string, string | string[] | undefined>): string | undefined;
|
|
181
|
+
/**
|
|
182
|
+
* Gets or generates a request ID.
|
|
183
|
+
* First tries to extract from headers, then generates a new one.
|
|
184
|
+
*
|
|
185
|
+
* @param headers - Request headers
|
|
186
|
+
* @param prefix - Prefix for generated IDs (default: 'req')
|
|
187
|
+
* @returns Request ID (either extracted or generated)
|
|
188
|
+
*/
|
|
189
|
+
declare function getOrGenerateRequestId(headers: Headers | Record<string, string | string[] | undefined>, prefix?: string): string;
|
|
190
|
+
|
|
191
|
+
export { type AgentCreator, type AgentCreatorContext, index as agui, createExpressRoutes, createExpressServer, extractRequestId, generateRequestId, getOrGenerateRequestId, run };
|
package/dist/index.js
CHANGED
|
@@ -30,8 +30,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
var index_exports = {};
|
|
31
31
|
__export(index_exports, {
|
|
32
32
|
agui: () => agui_exports,
|
|
33
|
+
createConsoleLogger: () => import_agent_shared2.createConsoleLogger,
|
|
33
34
|
createExpressRoutes: () => createExpressRoutes,
|
|
34
35
|
createExpressServer: () => createExpressServer,
|
|
36
|
+
extractRequestId: () => extractRequestId,
|
|
37
|
+
generateRequestId: () => generateRequestId,
|
|
38
|
+
getOrGenerateRequestId: () => getOrGenerateRequestId,
|
|
39
|
+
noopLogger: () => import_agent_shared2.noopLogger,
|
|
35
40
|
run: () => run
|
|
36
41
|
});
|
|
37
42
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -231,9 +236,46 @@ function handler2(input, agent) {
|
|
|
231
236
|
// src/agui/sendMessageAGUI/server.ts
|
|
232
237
|
var import_server3 = require("@whatwg-node/server");
|
|
233
238
|
var import_client2 = require("@ag-ui/client");
|
|
239
|
+
var import_uuid3 = require("uuid");
|
|
240
|
+
|
|
241
|
+
// src/logger/index.ts
|
|
242
|
+
var import_agent_shared2 = require("@cloudbase/agent-shared");
|
|
243
|
+
|
|
244
|
+
// src/logger/request-id.ts
|
|
234
245
|
var import_uuid2 = require("uuid");
|
|
235
|
-
function
|
|
246
|
+
function generateRequestId(prefix = "req") {
|
|
247
|
+
return `${prefix}-${(0, import_uuid2.v4)()}`;
|
|
248
|
+
}
|
|
249
|
+
function extractRequestId(headers) {
|
|
250
|
+
const headerNames = ["x-request-id", "x-correlation-id", "x-trace-id"];
|
|
251
|
+
for (const name of headerNames) {
|
|
252
|
+
let value;
|
|
253
|
+
if (headers instanceof Headers) {
|
|
254
|
+
value = headers.get(name) || void 0;
|
|
255
|
+
} else {
|
|
256
|
+
const raw = headers[name];
|
|
257
|
+
value = Array.isArray(raw) ? raw[0] : raw;
|
|
258
|
+
}
|
|
259
|
+
if (value) {
|
|
260
|
+
return value;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return void 0;
|
|
264
|
+
}
|
|
265
|
+
function getOrGenerateRequestId(headers, prefix = "req") {
|
|
266
|
+
return extractRequestId(headers) || generateRequestId(prefix);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// src/agui/sendMessageAGUI/server.ts
|
|
270
|
+
function createServerAdapter2(createAgent, options) {
|
|
271
|
+
var _a;
|
|
272
|
+
const { logger: parentLogger = import_agent_shared2.noopLogger } = options ?? {};
|
|
273
|
+
const adapterLogger = ((_a = parentLogger.child) == null ? void 0 : _a.call(parentLogger, { component: "sendMessageAGUI" })) ?? parentLogger;
|
|
236
274
|
return (0, import_server3.createServerAdapter)(async (request) => {
|
|
275
|
+
var _a2, _b, _c, _d, _e, _f, _g, _h;
|
|
276
|
+
const requestId = getOrGenerateRequestId(request.headers, "agui");
|
|
277
|
+
const logger = ((_a2 = adapterLogger.child) == null ? void 0 : _a2.call(adapterLogger, { requestId })) ?? adapterLogger;
|
|
278
|
+
(_b = logger.info) == null ? void 0 : _b.call(logger, "Request received");
|
|
237
279
|
const inputRes = await safeAsync(async () => {
|
|
238
280
|
const rawInput = await request.json();
|
|
239
281
|
const inputWithDefaults = {
|
|
@@ -242,16 +284,21 @@ function createServerAdapter2(createAgent) {
|
|
|
242
284
|
state: {},
|
|
243
285
|
forwardedProps: {},
|
|
244
286
|
...rawInput,
|
|
245
|
-
runId: typeof rawInput.runId === "string" && rawInput.runId ? rawInput.runId : (0,
|
|
287
|
+
runId: typeof rawInput.runId === "string" && rawInput.runId ? rawInput.runId : (0, import_uuid3.v4)()
|
|
246
288
|
};
|
|
247
289
|
return import_client2.RunAgentInputSchema.parse(inputWithDefaults);
|
|
248
290
|
});
|
|
249
291
|
if ("error" in inputRes) {
|
|
250
292
|
const { error } = inputRes;
|
|
251
|
-
|
|
293
|
+
(_c = logger.warn) == null ? void 0 : _c.call(
|
|
294
|
+
logger,
|
|
295
|
+
{ err: error instanceof Error ? error.message : String(error) },
|
|
296
|
+
"Input validation failed"
|
|
297
|
+
);
|
|
252
298
|
return new Response(
|
|
253
299
|
JSON.stringify({
|
|
254
|
-
error: error instanceof Error ? error.message : String(error)
|
|
300
|
+
error: error instanceof Error ? error.message : String(error),
|
|
301
|
+
requestId
|
|
255
302
|
}),
|
|
256
303
|
{
|
|
257
304
|
status: 400,
|
|
@@ -259,8 +306,25 @@ function createServerAdapter2(createAgent) {
|
|
|
259
306
|
}
|
|
260
307
|
);
|
|
261
308
|
}
|
|
309
|
+
const input = inputRes.result;
|
|
310
|
+
const lastUserMessage = input.messages.filter((m) => m.role === "user").pop();
|
|
311
|
+
(_f = logger.debug) == null ? void 0 : _f.call(
|
|
312
|
+
logger,
|
|
313
|
+
{
|
|
314
|
+
runId: input.runId,
|
|
315
|
+
threadId: input.threadId,
|
|
316
|
+
messageCount: input.messages.length,
|
|
317
|
+
toolCount: ((_d = input.tools) == null ? void 0 : _d.length) ?? 0,
|
|
318
|
+
tools: (_e = input.tools) == null ? void 0 : _e.map((t) => t.name),
|
|
319
|
+
lastUserMessage: typeof (lastUserMessage == null ? void 0 : lastUserMessage.content) === "string" ? lastUserMessage.content.slice(0, 200) : void 0
|
|
320
|
+
},
|
|
321
|
+
"Input validated"
|
|
322
|
+
);
|
|
323
|
+
(_g = logger.trace) == null ? void 0 : _g.call(logger, { input }, "Full request input");
|
|
262
324
|
const createAgentRes = await safeAsync(async () => {
|
|
263
|
-
const res = await Promise.resolve(
|
|
325
|
+
const res = await Promise.resolve(
|
|
326
|
+
createAgent({ request, logger, requestId })
|
|
327
|
+
);
|
|
264
328
|
return {
|
|
265
329
|
cleanup: res.cleanup,
|
|
266
330
|
agent: "toAGUIAgent" in res.agent ? res.agent.toAGUIAgent() : res.agent
|
|
@@ -268,10 +332,11 @@ function createServerAdapter2(createAgent) {
|
|
|
268
332
|
});
|
|
269
333
|
if ("error" in createAgentRes) {
|
|
270
334
|
const { error } = createAgentRes;
|
|
271
|
-
|
|
335
|
+
(_h = logger.error) == null ? void 0 : _h.call(logger, { err: error }, "Agent creation failed");
|
|
272
336
|
return new Response(
|
|
273
337
|
JSON.stringify({
|
|
274
|
-
error: error instanceof Error ? error.message : String(error)
|
|
338
|
+
error: error instanceof Error ? error.message : String(error),
|
|
339
|
+
requestId
|
|
275
340
|
}),
|
|
276
341
|
{
|
|
277
342
|
status: 500,
|
|
@@ -283,31 +348,41 @@ function createServerAdapter2(createAgent) {
|
|
|
283
348
|
let heartbeat;
|
|
284
349
|
let cleanupCalled = false;
|
|
285
350
|
const safeCleanup = () => {
|
|
286
|
-
var
|
|
351
|
+
var _a3, _b2, _c2;
|
|
287
352
|
if (!cleanupCalled) {
|
|
288
353
|
cleanupCalled = true;
|
|
289
354
|
try {
|
|
290
|
-
(
|
|
355
|
+
(_b2 = (_a3 = createAgentRes.result).cleanup) == null ? void 0 : _b2.call(_a3);
|
|
291
356
|
} catch (e) {
|
|
292
|
-
|
|
357
|
+
(_c2 = logger.error) == null ? void 0 : _c2.call(logger, { err: e }, "Cleanup error");
|
|
293
358
|
}
|
|
294
359
|
}
|
|
295
360
|
};
|
|
296
361
|
const stream = new ReadableStream({
|
|
297
362
|
async start(controller) {
|
|
363
|
+
var _a3, _b2, _c2, _d2;
|
|
298
364
|
const encoder = new TextEncoder();
|
|
299
365
|
heartbeat = setInterval(() => {
|
|
300
366
|
controller.enqueue(encoder.encode(":ping\n\n"));
|
|
301
367
|
}, 15 * 1e3);
|
|
368
|
+
let eventCount = 0;
|
|
302
369
|
try {
|
|
303
370
|
for await (const event of events) {
|
|
371
|
+
eventCount++;
|
|
372
|
+
(_a3 = logger.debug) == null ? void 0 : _a3.call(
|
|
373
|
+
logger,
|
|
374
|
+
{ eventType: event.type, eventCount },
|
|
375
|
+
"Emitting SSE event"
|
|
376
|
+
);
|
|
377
|
+
(_b2 = logger.trace) == null ? void 0 : _b2.call(logger, { aguiEvent: event }, "SSE event content");
|
|
304
378
|
const sseChunk = `data: ${JSON.stringify(event)}
|
|
305
379
|
|
|
306
380
|
`;
|
|
307
381
|
controller.enqueue(encoder.encode(sseChunk));
|
|
308
382
|
}
|
|
383
|
+
(_c2 = logger.info) == null ? void 0 : _c2.call(logger, { eventCount }, "Request completed");
|
|
309
384
|
} catch (error) {
|
|
310
|
-
|
|
385
|
+
(_d2 = logger.error) == null ? void 0 : _d2.call(logger, { err: error }, "Stream error");
|
|
311
386
|
const errorEvent = {
|
|
312
387
|
type: import_client2.EventType.RUN_ERROR,
|
|
313
388
|
message: error instanceof Error ? error.message : String(error)
|
|
@@ -324,6 +399,8 @@ function createServerAdapter2(createAgent) {
|
|
|
324
399
|
}
|
|
325
400
|
},
|
|
326
401
|
cancel() {
|
|
402
|
+
var _a3;
|
|
403
|
+
(_a3 = logger.info) == null ? void 0 : _a3.call(logger, "Request cancelled by client");
|
|
327
404
|
if (heartbeat) clearInterval(heartbeat);
|
|
328
405
|
safeCleanup();
|
|
329
406
|
}
|
|
@@ -362,7 +439,7 @@ __export(openai_exports, {
|
|
|
362
439
|
});
|
|
363
440
|
|
|
364
441
|
// src/agui/openai/handler.ts
|
|
365
|
-
var
|
|
442
|
+
var import_uuid4 = require("uuid");
|
|
366
443
|
var import_repeater3 = require("@repeaterjs/repeater");
|
|
367
444
|
function handler3(input, agent) {
|
|
368
445
|
var _a;
|
|
@@ -374,12 +451,12 @@ function handler3(input, agent) {
|
|
|
374
451
|
description: tool.function.description,
|
|
375
452
|
parameters: tool.function.parameters
|
|
376
453
|
})),
|
|
377
|
-
conversationId: (0,
|
|
454
|
+
conversationId: (0, import_uuid4.v4)()
|
|
378
455
|
},
|
|
379
456
|
agent
|
|
380
457
|
);
|
|
381
458
|
return new import_repeater3.Repeater(async (push, stop) => {
|
|
382
|
-
const id = (0,
|
|
459
|
+
const id = (0, import_uuid4.v4)();
|
|
383
460
|
let tools = [];
|
|
384
461
|
let lastWithToolCall = false;
|
|
385
462
|
let maxIndex = 0;
|
|
@@ -576,16 +653,22 @@ function createExpressRoutes({
|
|
|
576
653
|
basePath: _basePath,
|
|
577
654
|
express,
|
|
578
655
|
useAGUI: _useAGUI,
|
|
579
|
-
aguiOptions
|
|
656
|
+
aguiOptions,
|
|
657
|
+
logger: _logger
|
|
580
658
|
}) {
|
|
659
|
+
var _a, _b, _c;
|
|
581
660
|
const useAGUI = _useAGUI ?? true;
|
|
661
|
+
const logger = _logger ?? import_agent_shared2.noopLogger;
|
|
582
662
|
const basePath = _basePath ?? (process.env.TENCENTCLOUD_RUNENV === "SCF" ? "/v1/aibot/bots/:agentId/" : "/");
|
|
583
|
-
const
|
|
663
|
+
const serverLogger = ((_a = logger.child) == null ? void 0 : _a.call(logger, { component: "server" })) ?? logger;
|
|
664
|
+
(_b = serverLogger.debug) == null ? void 0 : _b.call(serverLogger, { basePath, useAGUI }, "Initializing server routes");
|
|
665
|
+
const sendMessageServerAdapter = useAGUI ? sendMessageAGUI_exports.createServerAdapter(createAgent, { logger: serverLogger }) : sendMessage_exports.createServerAdapter(createAgent);
|
|
584
666
|
if (useAGUI) {
|
|
585
667
|
createAGUIRoute({
|
|
586
668
|
basePath,
|
|
587
669
|
express,
|
|
588
670
|
createAgent,
|
|
671
|
+
logger: serverLogger,
|
|
589
672
|
...aguiOptions || {}
|
|
590
673
|
});
|
|
591
674
|
}
|
|
@@ -594,6 +677,7 @@ function createExpressRoutes({
|
|
|
594
677
|
express.use(`${basePath}send-message`, sendMessageServerAdapter);
|
|
595
678
|
express.use(`${basePath}healthz`, healthzServerAdapter);
|
|
596
679
|
express.use(`${basePath}chat/completions`, openaiServerAdapter);
|
|
680
|
+
(_c = serverLogger.info) == null ? void 0 : _c.call(serverLogger, { basePath }, "Server routes initialized");
|
|
597
681
|
return express;
|
|
598
682
|
}
|
|
599
683
|
var AGUIRpcHandlerPromise = null;
|
|
@@ -602,11 +686,13 @@ function getAGUIRpcHandler({
|
|
|
602
686
|
runtimeOptions,
|
|
603
687
|
basePath,
|
|
604
688
|
endpointOptions,
|
|
605
|
-
request
|
|
689
|
+
request,
|
|
690
|
+
logger,
|
|
691
|
+
requestId
|
|
606
692
|
}) {
|
|
607
693
|
if (AGUIRpcHandlerPromise) return AGUIRpcHandlerPromise;
|
|
608
694
|
AGUIRpcHandlerPromise = (async () => {
|
|
609
|
-
const { agent } = await createAgent({ request });
|
|
695
|
+
const { agent } = await createAgent({ request, logger, requestId });
|
|
610
696
|
const templateAgent = "toAGUIAgent" in agent ? agent.toAGUIAgent() : agent;
|
|
611
697
|
templateAgent.clone = agentCloneFn;
|
|
612
698
|
const runtime = new import_runtime.CopilotRuntime({
|
|
@@ -629,12 +715,21 @@ function createAGUIRoute({
|
|
|
629
715
|
basePath,
|
|
630
716
|
createAgent,
|
|
631
717
|
runtimeOptions,
|
|
632
|
-
endpointOptions
|
|
718
|
+
endpointOptions,
|
|
719
|
+
logger
|
|
633
720
|
}) {
|
|
721
|
+
var _a;
|
|
722
|
+
const routeLogger = ((_a = logger.child) == null ? void 0 : _a.call(logger, { component: "agui-route" })) ?? logger;
|
|
634
723
|
express.post(`${basePath}agui`, import_express.default.json(), async (req, res) => {
|
|
724
|
+
var _a2, _b;
|
|
635
725
|
const webRequest = (0, import_server8.normalizeNodeRequest)(req, DefaultFetchAPI);
|
|
726
|
+
const requestId = getOrGenerateRequestId(webRequest.headers, "agui");
|
|
727
|
+
const requestLogger = ((_a2 = routeLogger.child) == null ? void 0 : _a2.call(routeLogger, { requestId })) ?? routeLogger;
|
|
728
|
+
(_b = requestLogger.info) == null ? void 0 : _b.call(requestLogger, { path: `${basePath}agui` }, "Request received");
|
|
636
729
|
const { agent: rawAgent, cleanup } = await createAgent({
|
|
637
|
-
request: webRequest
|
|
730
|
+
request: webRequest,
|
|
731
|
+
logger: requestLogger,
|
|
732
|
+
requestId
|
|
638
733
|
});
|
|
639
734
|
const preparedAgent = "toAGUIAgent" in rawAgent ? rawAgent.toAGUIAgent() : rawAgent;
|
|
640
735
|
preparedAgent.clone = agentCloneFn;
|
|
@@ -643,7 +738,9 @@ function createAGUIRoute({
|
|
|
643
738
|
basePath,
|
|
644
739
|
runtimeOptions,
|
|
645
740
|
endpointOptions,
|
|
646
|
-
request: webRequest
|
|
741
|
+
request: webRequest,
|
|
742
|
+
logger: requestLogger,
|
|
743
|
+
requestId
|
|
647
744
|
});
|
|
648
745
|
preparedAgentStorage.run(preparedAgent, () => {
|
|
649
746
|
rpcHandler(req, res);
|
|
@@ -659,7 +756,12 @@ function isCorsOptions(cors2) {
|
|
|
659
756
|
// Annotate the CommonJS export names for ESM import in node:
|
|
660
757
|
0 && (module.exports = {
|
|
661
758
|
agui,
|
|
759
|
+
createConsoleLogger,
|
|
662
760
|
createExpressRoutes,
|
|
663
761
|
createExpressServer,
|
|
762
|
+
extractRequestId,
|
|
763
|
+
generateRequestId,
|
|
764
|
+
getOrGenerateRequestId,
|
|
765
|
+
noopLogger,
|
|
664
766
|
run
|
|
665
767
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudbase/agent-server",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.13",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist/",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"openai": "6.3.0",
|
|
22
22
|
"uuid": "^10.0.0",
|
|
23
23
|
"zod": "^4.1.12",
|
|
24
|
-
"@cloudbase/agent-shared": "^0.0.
|
|
24
|
+
"@cloudbase/agent-shared": "^0.0.13"
|
|
25
25
|
},
|
|
26
26
|
"devDependencies": {
|
|
27
27
|
"@types/cors": "^2.8.19",
|