@cloudbase/agent-server 0.0.12 → 0.0.14

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/CHANGELOG.md CHANGED
@@ -1,5 +1,29 @@
1
1
  # @cloudbase/agent-server
2
2
 
3
+ ## 1.0.1-alpha.8
4
+
5
+ ### Patch Changes
6
+
7
+ - alpha release 0.1.2-alpha.1
8
+ - Update all public packages to version 0.1.2-alpha.1
9
+ - Trigger automated alpha release workflow
10
+ - Includes latest features and improvements
11
+
12
+ - Updated dependencies
13
+ - @cloudbase/agent-shared@1.0.1-alpha.8
14
+
15
+ ## 1.0.1-alpha.7
16
+
17
+ ### Patch Changes
18
+
19
+ - alpha release 0.1.2-alpha.1
20
+ - Update all public packages to version 0.1.2-alpha.1
21
+ - Trigger automated alpha release workflow
22
+ - Includes latest features and improvements
23
+
24
+ - Updated dependencies
25
+ - @cloudbase/agent-shared@1.0.1-alpha.7
26
+
3
27
  ## 1.0.1-alpha.6
4
28
 
5
29
  ### Patch Changes
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, isErrorWithCode, 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
- declare function createServerAdapter$1(createAgent: AgentCreator): _whatwg_node_server.ServerAdapter<{}, _whatwg_node_server.ServerAdapterBaseObject<{}, (request: Request) => Promise<Response>>>;
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,63 @@ 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
- export { type AgentCreator, type AgentCreatorContext, index as agui, createExpressRoutes, createExpressServer, run };
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
+ /**
192
+ * AG-Kit Error Handling
193
+ *
194
+ * Error handling follows these rules:
195
+ * 1. Pre-stream errors: Return JSON `{error: {code, message}, requestId}`
196
+ * 2. In-stream errors: Emit RunError event `{type: "RUN_ERROR", code, message}`
197
+ *
198
+ * Adapters can:
199
+ * - Directly emit RunError events into the stream
200
+ * - Throw errors with a `code` property (server extracts and converts to RunError)
201
+ * - Throw other errors (server uses fallback INTERNAL_ERROR code)
202
+ */
203
+ declare const ErrorCode: {
204
+ /** Invalid request format or parameters (400) */
205
+ readonly INVALID_REQUEST: "INVALID_REQUEST";
206
+ /** Internal server error (500) */
207
+ readonly INTERNAL_ERROR: "INTERNAL_ERROR";
208
+ };
209
+ type ErrorCodeType = (typeof ErrorCode)[keyof typeof ErrorCode];
210
+
211
+ export { type AgentCreator, type AgentCreatorContext, ErrorCode, type ErrorCodeType, index as agui, createExpressRoutes, createExpressServer, extractRequestId, generateRequestId, getOrGenerateRequestId, run };
package/dist/index.js CHANGED
@@ -29,9 +29,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
29
29
  // src/index.ts
30
30
  var index_exports = {};
31
31
  __export(index_exports, {
32
+ ErrorCode: () => ErrorCode,
32
33
  agui: () => agui_exports,
34
+ createConsoleLogger: () => import_agent_shared2.createConsoleLogger,
33
35
  createExpressRoutes: () => createExpressRoutes,
34
36
  createExpressServer: () => createExpressServer,
37
+ extractRequestId: () => extractRequestId,
38
+ generateRequestId: () => generateRequestId,
39
+ getOrGenerateRequestId: () => getOrGenerateRequestId,
40
+ isErrorWithCode: () => import_agent_shared3.isErrorWithCode,
41
+ noopLogger: () => import_agent_shared2.noopLogger,
35
42
  run: () => run
36
43
  });
37
44
  module.exports = __toCommonJS(index_exports);
@@ -231,9 +238,166 @@ function handler2(input, agent) {
231
238
  // src/agui/sendMessageAGUI/server.ts
232
239
  var import_server3 = require("@whatwg-node/server");
233
240
  var import_client2 = require("@ag-ui/client");
241
+ var import_uuid3 = require("uuid");
242
+
243
+ // src/logger/index.ts
244
+ var import_agent_shared2 = require("@cloudbase/agent-shared");
245
+
246
+ // src/logger/request-id.ts
234
247
  var import_uuid2 = require("uuid");
235
- function createServerAdapter2(createAgent) {
248
+ function generateRequestId(prefix = "req") {
249
+ return `${prefix}-${(0, import_uuid2.v4)()}`;
250
+ }
251
+ function extractRequestId(headers) {
252
+ const headerNames = ["x-request-id", "x-correlation-id", "x-trace-id"];
253
+ for (const name of headerNames) {
254
+ let value;
255
+ if (headers instanceof Headers) {
256
+ value = headers.get(name) || void 0;
257
+ } else {
258
+ const raw = headers[name];
259
+ value = Array.isArray(raw) ? raw[0] : raw;
260
+ }
261
+ if (value) {
262
+ return value;
263
+ }
264
+ }
265
+ return void 0;
266
+ }
267
+ function getOrGenerateRequestId(headers, prefix = "req") {
268
+ return extractRequestId(headers) || generateRequestId(prefix);
269
+ }
270
+
271
+ // src/agui/sendMessageAGUI/schemas.ts
272
+ var import_v4 = require("zod/v4");
273
+ var FunctionCallSchema = import_v4.z.object({
274
+ name: import_v4.z.string(),
275
+ arguments: import_v4.z.string()
276
+ });
277
+ var ToolCallSchema = import_v4.z.object({
278
+ id: import_v4.z.string(),
279
+ type: import_v4.z.literal("function"),
280
+ function: FunctionCallSchema
281
+ });
282
+ var ToolSchema = import_v4.z.object({
283
+ name: import_v4.z.string(),
284
+ description: import_v4.z.string(),
285
+ parameters: import_v4.z.any()
286
+ });
287
+ var TextInputContentSchema = import_v4.z.object({
288
+ type: import_v4.z.literal("text"),
289
+ text: import_v4.z.string()
290
+ });
291
+ var BinaryInputContentObjectSchema = import_v4.z.object({
292
+ type: import_v4.z.literal("binary"),
293
+ mimeType: import_v4.z.string(),
294
+ id: import_v4.z.string().optional(),
295
+ url: import_v4.z.string().optional(),
296
+ data: import_v4.z.string().optional(),
297
+ filename: import_v4.z.string().optional()
298
+ });
299
+ var ensureBinaryPayload = (value, ctx) => {
300
+ if (!value.id && !value.url && !value.data) {
301
+ ctx.addIssue({
302
+ code: import_v4.z.ZodIssueCode.custom,
303
+ message: "BinaryInputContent requires at least one of id, url, or data.",
304
+ path: ["id"]
305
+ });
306
+ }
307
+ };
308
+ var BinaryInputContentSchema = BinaryInputContentObjectSchema.superRefine((value, ctx) => {
309
+ ensureBinaryPayload(value, ctx);
310
+ });
311
+ var InputContentBaseSchema = import_v4.z.discriminatedUnion("type", [
312
+ TextInputContentSchema,
313
+ BinaryInputContentObjectSchema
314
+ ]);
315
+ var InputContentSchema = InputContentBaseSchema.superRefine(
316
+ (value, ctx) => {
317
+ if (value.type === "binary") {
318
+ ensureBinaryPayload(value, ctx);
319
+ }
320
+ }
321
+ );
322
+ var BaseMessageSchema = import_v4.z.object({
323
+ id: import_v4.z.string(),
324
+ role: import_v4.z.string(),
325
+ content: import_v4.z.string().optional(),
326
+ name: import_v4.z.string().optional()
327
+ });
328
+ var DeveloperMessageSchema = BaseMessageSchema.extend({
329
+ role: import_v4.z.literal("developer"),
330
+ content: import_v4.z.string()
331
+ });
332
+ var SystemMessageSchema = BaseMessageSchema.extend({
333
+ role: import_v4.z.literal("system"),
334
+ content: import_v4.z.string()
335
+ });
336
+ var AssistantMessageSchema = BaseMessageSchema.extend({
337
+ role: import_v4.z.literal("assistant"),
338
+ content: import_v4.z.string().optional(),
339
+ toolCalls: import_v4.z.array(ToolCallSchema).optional()
340
+ });
341
+ var UserMessageSchema = BaseMessageSchema.extend({
342
+ role: import_v4.z.literal("user"),
343
+ content: import_v4.z.union([import_v4.z.string(), import_v4.z.array(InputContentSchema)])
344
+ });
345
+ var ToolMessageSchema = import_v4.z.object({
346
+ id: import_v4.z.string(),
347
+ content: import_v4.z.string(),
348
+ role: import_v4.z.literal("tool"),
349
+ toolCallId: import_v4.z.string(),
350
+ error: import_v4.z.string().optional()
351
+ });
352
+ var ActivityMessageSchema = import_v4.z.object({
353
+ id: import_v4.z.string(),
354
+ role: import_v4.z.literal("activity"),
355
+ activityType: import_v4.z.string(),
356
+ content: import_v4.z.record(import_v4.z.string(), import_v4.z.any())
357
+ });
358
+ var MessageSchema = import_v4.z.discriminatedUnion("role", [
359
+ DeveloperMessageSchema,
360
+ SystemMessageSchema,
361
+ AssistantMessageSchema,
362
+ UserMessageSchema,
363
+ ToolMessageSchema,
364
+ ActivityMessageSchema
365
+ ]);
366
+ var ContextSchema = import_v4.z.object({
367
+ description: import_v4.z.string(),
368
+ value: import_v4.z.string()
369
+ });
370
+ var ServerRunAgentInputSchema = import_v4.z.object({
371
+ threadId: import_v4.z.string().optional(),
372
+ // Modified: optional instead of required
373
+ runId: import_v4.z.string(),
374
+ parentRunId: import_v4.z.string().optional(),
375
+ state: import_v4.z.any(),
376
+ messages: import_v4.z.array(MessageSchema),
377
+ tools: import_v4.z.array(ToolSchema),
378
+ context: import_v4.z.array(ContextSchema),
379
+ forwardedProps: import_v4.z.any()
380
+ });
381
+
382
+ // src/errors/index.ts
383
+ var import_agent_shared3 = require("@cloudbase/agent-shared");
384
+ var ErrorCode = {
385
+ /** Invalid request format or parameters (400) */
386
+ INVALID_REQUEST: "INVALID_REQUEST",
387
+ /** Internal server error (500) */
388
+ INTERNAL_ERROR: "INTERNAL_ERROR"
389
+ };
390
+
391
+ // src/agui/sendMessageAGUI/server.ts
392
+ function createServerAdapter2(createAgent, options) {
393
+ var _a;
394
+ const { logger: parentLogger = import_agent_shared2.noopLogger } = options ?? {};
395
+ const adapterLogger = ((_a = parentLogger.child) == null ? void 0 : _a.call(parentLogger, { component: "sendMessageAGUI" })) ?? parentLogger;
236
396
  return (0, import_server3.createServerAdapter)(async (request) => {
397
+ var _a2, _b, _c, _d, _e, _f, _g, _h;
398
+ const requestId = getOrGenerateRequestId(request.headers, "agui");
399
+ const logger = ((_a2 = adapterLogger.child) == null ? void 0 : _a2.call(adapterLogger, { requestId })) ?? adapterLogger;
400
+ (_b = logger.info) == null ? void 0 : _b.call(logger, "Request received");
237
401
  const inputRes = await safeAsync(async () => {
238
402
  const rawInput = await request.json();
239
403
  const inputWithDefaults = {
@@ -242,16 +406,24 @@ function createServerAdapter2(createAgent) {
242
406
  state: {},
243
407
  forwardedProps: {},
244
408
  ...rawInput,
245
- runId: typeof rawInput.runId === "string" && rawInput.runId ? rawInput.runId : (0, import_uuid2.v4)()
409
+ runId: typeof rawInput.runId === "string" && rawInput.runId ? rawInput.runId : (0, import_uuid3.v4)()
246
410
  };
247
- return import_client2.RunAgentInputSchema.parse(inputWithDefaults);
411
+ return ServerRunAgentInputSchema.parse(inputWithDefaults);
248
412
  });
249
413
  if ("error" in inputRes) {
250
414
  const { error } = inputRes;
251
- console.error("[AGUI Server] Pre-stream error:", error);
415
+ (_c = logger.warn) == null ? void 0 : _c.call(
416
+ logger,
417
+ { err: error instanceof Error ? error.message : String(error) },
418
+ "Input validation failed"
419
+ );
252
420
  return new Response(
253
421
  JSON.stringify({
254
- error: error instanceof Error ? error.message : String(error)
422
+ error: {
423
+ code: ErrorCode.INVALID_REQUEST,
424
+ message: error instanceof Error ? error.message : String(error)
425
+ },
426
+ requestId
255
427
  }),
256
428
  {
257
429
  status: 400,
@@ -259,8 +431,25 @@ function createServerAdapter2(createAgent) {
259
431
  }
260
432
  );
261
433
  }
434
+ const input = inputRes.result;
435
+ const lastUserMessage = input.messages.filter((m) => m.role === "user").pop();
436
+ (_f = logger.debug) == null ? void 0 : _f.call(
437
+ logger,
438
+ {
439
+ runId: input.runId,
440
+ threadId: input.threadId,
441
+ messageCount: input.messages.length,
442
+ toolCount: ((_d = input.tools) == null ? void 0 : _d.length) ?? 0,
443
+ tools: (_e = input.tools) == null ? void 0 : _e.map((t) => t.name),
444
+ lastUserMessage: typeof (lastUserMessage == null ? void 0 : lastUserMessage.content) === "string" ? lastUserMessage.content.slice(0, 200) : void 0
445
+ },
446
+ "Input validated"
447
+ );
448
+ (_g = logger.trace) == null ? void 0 : _g.call(logger, { input }, "Full request input");
262
449
  const createAgentRes = await safeAsync(async () => {
263
- const res = await Promise.resolve(createAgent({ request }));
450
+ const res = await Promise.resolve(
451
+ createAgent({ request, logger, requestId })
452
+ );
264
453
  return {
265
454
  cleanup: res.cleanup,
266
455
  agent: "toAGUIAgent" in res.agent ? res.agent.toAGUIAgent() : res.agent
@@ -268,10 +457,16 @@ function createServerAdapter2(createAgent) {
268
457
  });
269
458
  if ("error" in createAgentRes) {
270
459
  const { error } = createAgentRes;
271
- console.error("[AGUI Server] Pre-stream error:", error);
460
+ (_h = logger.error) == null ? void 0 : _h.call(logger, { err: error }, "Agent creation failed");
461
+ const errorCode = (0, import_agent_shared3.isErrorWithCode)(error) ? error.code : ErrorCode.INTERNAL_ERROR;
462
+ const errorMessage = error instanceof Error ? error.message : String(error);
272
463
  return new Response(
273
464
  JSON.stringify({
274
- error: error instanceof Error ? error.message : String(error)
465
+ error: {
466
+ code: errorCode,
467
+ message: errorMessage
468
+ },
469
+ requestId
275
470
  }),
276
471
  {
277
472
  status: 500,
@@ -279,38 +474,54 @@ function createServerAdapter2(createAgent) {
279
474
  }
280
475
  );
281
476
  }
282
- const events = handler2(inputRes.result, createAgentRes.result.agent);
477
+ const events = handler2(
478
+ inputRes.result,
479
+ createAgentRes.result.agent
480
+ );
283
481
  let heartbeat;
284
482
  let cleanupCalled = false;
285
483
  const safeCleanup = () => {
286
- var _a, _b;
484
+ var _a3, _b2, _c2;
287
485
  if (!cleanupCalled) {
288
486
  cleanupCalled = true;
289
487
  try {
290
- (_b = (_a = createAgentRes.result).cleanup) == null ? void 0 : _b.call(_a);
488
+ (_b2 = (_a3 = createAgentRes.result).cleanup) == null ? void 0 : _b2.call(_a3);
291
489
  } catch (e) {
292
- console.error(e);
490
+ (_c2 = logger.error) == null ? void 0 : _c2.call(logger, { err: e }, "Cleanup error");
293
491
  }
294
492
  }
295
493
  };
296
494
  const stream = new ReadableStream({
297
495
  async start(controller) {
496
+ var _a3, _b2, _c2, _d2;
298
497
  const encoder = new TextEncoder();
299
498
  heartbeat = setInterval(() => {
300
499
  controller.enqueue(encoder.encode(":ping\n\n"));
301
500
  }, 15 * 1e3);
501
+ let eventCount = 0;
302
502
  try {
303
503
  for await (const event of events) {
504
+ eventCount++;
505
+ (_a3 = logger.debug) == null ? void 0 : _a3.call(
506
+ logger,
507
+ { eventType: event.type, eventCount },
508
+ "Emitting SSE event"
509
+ );
510
+ (_b2 = logger.trace) == null ? void 0 : _b2.call(logger, { aguiEvent: event }, "SSE event content");
304
511
  const sseChunk = `data: ${JSON.stringify(event)}
305
512
 
306
513
  `;
307
514
  controller.enqueue(encoder.encode(sseChunk));
308
515
  }
516
+ (_c2 = logger.info) == null ? void 0 : _c2.call(logger, { eventCount }, "Request completed");
309
517
  } catch (error) {
310
- console.error("[AGUI Server] Stream error:", error);
518
+ (_d2 = logger.error) == null ? void 0 : _d2.call(logger, { err: error }, "Stream error");
519
+ const errorCode = (0, import_agent_shared3.isErrorWithCode)(error) ? error.code : ErrorCode.INTERNAL_ERROR;
520
+ const errorMessage = error instanceof Error ? error.message : String(error);
311
521
  const errorEvent = {
312
522
  type: import_client2.EventType.RUN_ERROR,
313
- message: error instanceof Error ? error.message : String(error)
523
+ code: errorCode,
524
+ message: errorMessage
314
525
  };
315
526
  controller.enqueue(
316
527
  encoder.encode(`data: ${JSON.stringify(errorEvent)}
@@ -324,6 +535,8 @@ function createServerAdapter2(createAgent) {
324
535
  }
325
536
  },
326
537
  cancel() {
538
+ var _a3;
539
+ (_a3 = logger.info) == null ? void 0 : _a3.call(logger, "Request cancelled by client");
327
540
  if (heartbeat) clearInterval(heartbeat);
328
541
  safeCleanup();
329
542
  }
@@ -362,7 +575,7 @@ __export(openai_exports, {
362
575
  });
363
576
 
364
577
  // src/agui/openai/handler.ts
365
- var import_uuid3 = require("uuid");
578
+ var import_uuid4 = require("uuid");
366
579
  var import_repeater3 = require("@repeaterjs/repeater");
367
580
  function handler3(input, agent) {
368
581
  var _a;
@@ -374,12 +587,12 @@ function handler3(input, agent) {
374
587
  description: tool.function.description,
375
588
  parameters: tool.function.parameters
376
589
  })),
377
- conversationId: (0, import_uuid3.v4)()
590
+ conversationId: (0, import_uuid4.v4)()
378
591
  },
379
592
  agent
380
593
  );
381
594
  return new import_repeater3.Repeater(async (push, stop) => {
382
- const id = (0, import_uuid3.v4)();
595
+ const id = (0, import_uuid4.v4)();
383
596
  let tools = [];
384
597
  let lastWithToolCall = false;
385
598
  let maxIndex = 0;
@@ -576,16 +789,22 @@ function createExpressRoutes({
576
789
  basePath: _basePath,
577
790
  express,
578
791
  useAGUI: _useAGUI,
579
- aguiOptions
792
+ aguiOptions,
793
+ logger: _logger
580
794
  }) {
795
+ var _a, _b, _c;
581
796
  const useAGUI = _useAGUI ?? true;
797
+ const logger = _logger ?? import_agent_shared2.noopLogger;
582
798
  const basePath = _basePath ?? (process.env.TENCENTCLOUD_RUNENV === "SCF" ? "/v1/aibot/bots/:agentId/" : "/");
583
- const sendMessageServerAdapter = useAGUI ? sendMessageAGUI_exports.createServerAdapter(createAgent) : sendMessage_exports.createServerAdapter(createAgent);
799
+ const serverLogger = ((_a = logger.child) == null ? void 0 : _a.call(logger, { component: "server" })) ?? logger;
800
+ (_b = serverLogger.debug) == null ? void 0 : _b.call(serverLogger, { basePath, useAGUI }, "Initializing server routes");
801
+ const sendMessageServerAdapter = useAGUI ? sendMessageAGUI_exports.createServerAdapter(createAgent, { logger: serverLogger }) : sendMessage_exports.createServerAdapter(createAgent);
584
802
  if (useAGUI) {
585
803
  createAGUIRoute({
586
804
  basePath,
587
805
  express,
588
806
  createAgent,
807
+ logger: serverLogger,
589
808
  ...aguiOptions || {}
590
809
  });
591
810
  }
@@ -594,6 +813,7 @@ function createExpressRoutes({
594
813
  express.use(`${basePath}send-message`, sendMessageServerAdapter);
595
814
  express.use(`${basePath}healthz`, healthzServerAdapter);
596
815
  express.use(`${basePath}chat/completions`, openaiServerAdapter);
816
+ (_c = serverLogger.info) == null ? void 0 : _c.call(serverLogger, { basePath }, "Server routes initialized");
597
817
  return express;
598
818
  }
599
819
  var AGUIRpcHandlerPromise = null;
@@ -602,11 +822,13 @@ function getAGUIRpcHandler({
602
822
  runtimeOptions,
603
823
  basePath,
604
824
  endpointOptions,
605
- request
825
+ request,
826
+ logger,
827
+ requestId
606
828
  }) {
607
829
  if (AGUIRpcHandlerPromise) return AGUIRpcHandlerPromise;
608
830
  AGUIRpcHandlerPromise = (async () => {
609
- const { agent } = await createAgent({ request });
831
+ const { agent } = await createAgent({ request, logger, requestId });
610
832
  const templateAgent = "toAGUIAgent" in agent ? agent.toAGUIAgent() : agent;
611
833
  templateAgent.clone = agentCloneFn;
612
834
  const runtime = new import_runtime.CopilotRuntime({
@@ -629,12 +851,21 @@ function createAGUIRoute({
629
851
  basePath,
630
852
  createAgent,
631
853
  runtimeOptions,
632
- endpointOptions
854
+ endpointOptions,
855
+ logger
633
856
  }) {
857
+ var _a;
858
+ const routeLogger = ((_a = logger.child) == null ? void 0 : _a.call(logger, { component: "agui-route" })) ?? logger;
634
859
  express.post(`${basePath}agui`, import_express.default.json(), async (req, res) => {
860
+ var _a2, _b;
635
861
  const webRequest = (0, import_server8.normalizeNodeRequest)(req, DefaultFetchAPI);
862
+ const requestId = getOrGenerateRequestId(webRequest.headers, "agui");
863
+ const requestLogger = ((_a2 = routeLogger.child) == null ? void 0 : _a2.call(routeLogger, { requestId })) ?? routeLogger;
864
+ (_b = requestLogger.info) == null ? void 0 : _b.call(requestLogger, { path: `${basePath}agui` }, "Request received");
636
865
  const { agent: rawAgent, cleanup } = await createAgent({
637
- request: webRequest
866
+ request: webRequest,
867
+ logger: requestLogger,
868
+ requestId
638
869
  });
639
870
  const preparedAgent = "toAGUIAgent" in rawAgent ? rawAgent.toAGUIAgent() : rawAgent;
640
871
  preparedAgent.clone = agentCloneFn;
@@ -643,7 +874,9 @@ function createAGUIRoute({
643
874
  basePath,
644
875
  runtimeOptions,
645
876
  endpointOptions,
646
- request: webRequest
877
+ request: webRequest,
878
+ logger: requestLogger,
879
+ requestId
647
880
  });
648
881
  preparedAgentStorage.run(preparedAgent, () => {
649
882
  rpcHandler(req, res);
@@ -658,8 +891,15 @@ function isCorsOptions(cors2) {
658
891
  }
659
892
  // Annotate the CommonJS export names for ESM import in node:
660
893
  0 && (module.exports = {
894
+ ErrorCode,
661
895
  agui,
896
+ createConsoleLogger,
662
897
  createExpressRoutes,
663
898
  createExpressServer,
899
+ extractRequestId,
900
+ generateRequestId,
901
+ getOrGenerateRequestId,
902
+ isErrorWithCode,
903
+ noopLogger,
664
904
  run
665
905
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/agent-server",
3
- "version": "0.0.12",
3
+ "version": "0.0.14",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist/",
@@ -20,13 +20,16 @@
20
20
  "express": "^5.1.0",
21
21
  "openai": "6.3.0",
22
22
  "uuid": "^10.0.0",
23
- "zod": "^4.1.12",
24
- "@cloudbase/agent-shared": "^0.0.12"
23
+ "@cloudbase/agent-shared": "^0.0.14"
24
+ },
25
+ "peerDependencies": {
26
+ "zod": "^3.25.0 || ^4.0.0"
25
27
  },
26
28
  "devDependencies": {
27
29
  "@types/cors": "^2.8.19",
28
30
  "@types/express": "^5.0.3",
29
- "tsup": "^8.5.0"
31
+ "tsup": "^8.5.0",
32
+ "zod": "^4.0.0"
30
33
  },
31
34
  "scripts": {
32
35
  "test": "echo \"Error: no test specified\" && exit 1",