@cloudbase/agent-server 0.0.15 → 0.0.16

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/dist/index.d.ts CHANGED
@@ -10,6 +10,14 @@ import { Repeater } from '@repeaterjs/repeater';
10
10
  import * as _whatwg_node_server from '@whatwg-node/server';
11
11
  import { OpenAI } from 'openai';
12
12
 
13
+ /**
14
+ * Type-only reference to ObservabilityConfig for documentation purposes.
15
+ * The actual type is: ObservabilityConfig | ObservabilityConfig[]
16
+ *
17
+ * At runtime, this accepts any value matching the ObservabilityConfig interface
18
+ * from @cloudbase/agent-observability/server package (if installed).
19
+ */
20
+ type ObservabilityConfigOrArray = any;
13
21
  /**
14
22
  * Context passed to the agent factory function.
15
23
  * Contains request information for per-request agent configuration.
@@ -53,16 +61,49 @@ interface ICreateServer {
53
61
  * createExpressServer({ createAgent, logger: pino({ level: 'info' }) });
54
62
  */
55
63
  logger?: Logger;
64
+ /**
65
+ * Observability configuration for trace exporters.
66
+ *
67
+ * Requires @cloudbase/agent-observability package to be installed.
68
+ * If the package is not installed, this option is silently ignored.
69
+ *
70
+ * Type reference: ObservabilityConfig | ObservabilityConfig[] from @cloudbase/agent-observability/server
71
+ *
72
+ * @example
73
+ * // Console exporter (from env AUTO_TRACES_STDOUT)
74
+ * createExpressServer({ createAgent, observability: { type: 'console' } });
75
+ *
76
+ * // OTLP exporter (Langfuse, Jaeger, etc.)
77
+ * createExpressServer({
78
+ * createAgent,
79
+ * observability: {
80
+ * type: 'otlp',
81
+ * url: 'https://cloud.langfuse.com/api/public/otlp/v1/traces',
82
+ * headers: { 'Authorization': 'Basic xxx' }
83
+ * }
84
+ * });
85
+ *
86
+ * // Multiple exporters
87
+ * createExpressServer({
88
+ * createAgent,
89
+ * observability: [
90
+ * { type: 'console' },
91
+ * { type: 'otlp', url: 'http://localhost:4318/v1/traces' }
92
+ * ]
93
+ * });
94
+ */
95
+ observability?: ObservabilityConfigOrArray;
56
96
  }
57
97
  interface IRun extends ICreateServer {
58
98
  port?: number | string;
59
99
  }
60
100
  interface ICreateExpressRoutes extends Omit<ICreateServer, "cors"> {
61
101
  express: Express;
102
+ observability?: ICreateServer["observability"];
62
103
  }
63
104
  declare function run(props: IRun): void;
64
105
  declare function createExpressServer(props: ICreateServer): Express;
65
- declare function createExpressRoutes({ createAgent, basePath: _basePath, express, useAGUI: _useAGUI, aguiOptions, logger: _logger, }: ICreateExpressRoutes): expressLib.Express;
106
+ declare function createExpressRoutes({ createAgent, basePath: _basePath, express, useAGUI: _useAGUI, aguiOptions, logger: _logger, observability, }: ICreateExpressRoutes): expressLib.Express;
66
107
  interface AGUIOptions {
67
108
  runtimeOptions?: Partial<CopilotRuntimeOptions>;
68
109
  endpointOptions?: Partial<CreateCopilotRuntimeServerOptions>;
package/dist/index.js CHANGED
@@ -389,12 +389,45 @@ var ErrorCode = {
389
389
  };
390
390
 
391
391
  // src/agui/sendMessageAGUI/server.ts
392
+ var startObservation;
393
+ var setupObservability;
394
+ var observabilityLoadAttempted = false;
395
+ async function loadObservability() {
396
+ if (!observabilityLoadAttempted) {
397
+ observabilityLoadAttempted = true;
398
+ try {
399
+ const obs = await import("@cloudbase/agent-observability");
400
+ const obsServer = await import("@cloudbase/agent-observability/server");
401
+ startObservation = obs.startObservation;
402
+ setupObservability = obsServer.setupObservability;
403
+ return true;
404
+ } catch (e) {
405
+ return false;
406
+ }
407
+ }
408
+ return !!startObservation;
409
+ }
410
+ async function ensureObservabilityReady() {
411
+ if (!setupObservability) return false;
412
+ try {
413
+ const timeoutPromise = new Promise((_, reject) => {
414
+ setTimeout(() => reject(new Error("Observability setup timeout")), 2e3);
415
+ });
416
+ await Promise.race([
417
+ setupObservability(),
418
+ timeoutPromise
419
+ ]);
420
+ return true;
421
+ } catch (e) {
422
+ return false;
423
+ }
424
+ }
392
425
  function createServerAdapter2(createAgent, options) {
393
426
  var _a;
394
427
  const { logger: parentLogger = import_agent_shared2.noopLogger } = options ?? {};
395
428
  const adapterLogger = ((_a = parentLogger.child) == null ? void 0 : _a.call(parentLogger, { component: "sendMessageAGUI" })) ?? parentLogger;
396
429
  return (0, import_server3.createServerAdapter)(async (request) => {
397
- var _a2, _b, _c, _d, _e, _f, _g, _h;
430
+ var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
398
431
  const requestId = getOrGenerateRequestId(request.headers, "agui");
399
432
  const logger = ((_a2 = adapterLogger.child) == null ? void 0 : _a2.call(adapterLogger, { requestId })) ?? adapterLogger;
400
433
  (_b = logger.info) == null ? void 0 : _b.call(logger, "Request received");
@@ -474,11 +507,46 @@ function createServerAdapter2(createAgent, options) {
474
507
  }
475
508
  );
476
509
  }
477
- const events = handler2(
478
- inputRes.result,
479
- createAgentRes.result.agent
480
- );
481
- let heartbeat;
510
+ const hasObservability = await loadObservability();
511
+ let serverSpan = null;
512
+ let serverContextData = null;
513
+ if (hasObservability && startObservation) {
514
+ try {
515
+ const isReady = await ensureObservabilityReady();
516
+ if (isReady) {
517
+ serverSpan = startObservation(
518
+ "AG-UI.Server",
519
+ {
520
+ "http.method": request.method,
521
+ "http.url": request.url,
522
+ "http.host": request.headers.get("host") || "unknown",
523
+ "http.user_agent": request.headers.get("user-agent") || "unknown",
524
+ "agui.thread_id": inputRes.result.threadId,
525
+ "agui.run_id": inputRes.result.runId
526
+ },
527
+ { asType: "span" }
528
+ );
529
+ const spanContext = serverSpan.otelSpan.spanContext();
530
+ serverContextData = {
531
+ traceId: spanContext.traceId,
532
+ spanId: spanContext.spanId,
533
+ traceFlags: spanContext.traceFlags
534
+ };
535
+ inputRes.result.forwardedProps = {
536
+ ...inputRes.result.forwardedProps,
537
+ __agui_server_context: serverContextData
538
+ };
539
+ (_i = logger.debug) == null ? void 0 : _i.call(logger, "\u2713 Server span created:", {
540
+ traceId: serverContextData.traceId,
541
+ spanId: serverContextData.spanId
542
+ });
543
+ } else {
544
+ (_j = logger.debug) == null ? void 0 : _j.call(logger, "Observability not ready, skipping span creation");
545
+ }
546
+ } catch (e) {
547
+ (_k = logger.debug) == null ? void 0 : _k.call(logger, "Failed to create server span:", e);
548
+ }
549
+ }
482
550
  let cleanupCalled = false;
483
551
  const safeCleanup = () => {
484
552
  var _a3, _b2, _c2;
@@ -491,9 +559,36 @@ function createServerAdapter2(createAgent, options) {
491
559
  }
492
560
  }
493
561
  };
562
+ const eventsResult = safe(
563
+ () => handler2(
564
+ inputRes.result,
565
+ createAgentRes.result.agent
566
+ )
567
+ );
568
+ if ("error" in eventsResult) {
569
+ const { error } = eventsResult;
570
+ (_l = logger.error) == null ? void 0 : _l.call(logger, { err: error }, "Run agent failed");
571
+ const errorCode = (0, import_agent_shared3.isErrorWithCode)(error) ? error.code : ErrorCode.INTERNAL_ERROR;
572
+ const errorMessage = error instanceof Error ? error.message : String(error);
573
+ return new Response(
574
+ JSON.stringify({
575
+ error: {
576
+ code: errorCode,
577
+ message: errorMessage
578
+ },
579
+ requestId
580
+ }),
581
+ {
582
+ status: 500,
583
+ headers: { "Content-Type": "application/json" }
584
+ }
585
+ );
586
+ }
587
+ const { result: events } = eventsResult;
588
+ let heartbeat;
494
589
  const stream = new ReadableStream({
495
590
  async start(controller) {
496
- var _a3, _b2, _c2, _d2;
591
+ var _a3, _b2, _c2, _d2, _e2;
497
592
  const encoder = new TextEncoder();
498
593
  heartbeat = setInterval(() => {
499
594
  controller.enqueue(encoder.encode(":ping\n\n"));
@@ -532,13 +627,21 @@ function createServerAdapter2(createAgent, options) {
532
627
  if (heartbeat) clearInterval(heartbeat);
533
628
  controller.close();
534
629
  safeCleanup();
630
+ if (serverSpan) {
631
+ serverSpan.end();
632
+ (_e2 = logger.debug) == null ? void 0 : _e2.call(logger, "\u2713 Server span ended");
633
+ }
535
634
  }
536
635
  },
537
636
  cancel() {
538
- var _a3;
637
+ var _a3, _b2;
539
638
  (_a3 = logger.info) == null ? void 0 : _a3.call(logger, "Request cancelled by client");
540
639
  if (heartbeat) clearInterval(heartbeat);
541
640
  safeCleanup();
641
+ if (serverSpan) {
642
+ serverSpan.end();
643
+ (_b2 = logger.debug) == null ? void 0 : _b2.call(logger, "\u2713 Server span ended (cancelled)");
644
+ }
542
645
  }
543
646
  });
544
647
  const headers = new Headers({
@@ -558,6 +661,15 @@ async function safeAsync(fn) {
558
661
  return { error };
559
662
  }
560
663
  }
664
+ function safe(fn) {
665
+ try {
666
+ return {
667
+ result: fn()
668
+ };
669
+ } catch (error) {
670
+ return { error };
671
+ }
672
+ }
561
673
 
562
674
  // src/agui/healthz/index.ts
563
675
  var healthz_exports = {};
@@ -756,6 +868,13 @@ var import_cors = __toESM(require("cors"));
756
868
  var import_async_hooks = require("async_hooks");
757
869
  var import_server8 = require("@whatwg-node/server");
758
870
  var DefaultFetchAPI = __toESM(require("@whatwg-node/fetch"));
871
+ async function setupObservabilityIfAvailable(configs) {
872
+ try {
873
+ const { setupObservability: setupObservability2 } = await import("@cloudbase/agent-observability/server");
874
+ await setupObservability2(configs);
875
+ } catch (error) {
876
+ }
877
+ }
759
878
  var preparedAgentStorage = new import_async_hooks.AsyncLocalStorage();
760
879
  function agentCloneFn() {
761
880
  const preparedAgent = preparedAgentStorage.getStore();
@@ -790,33 +909,77 @@ function createExpressRoutes({
790
909
  express,
791
910
  useAGUI: _useAGUI,
792
911
  aguiOptions,
793
- logger: _logger
912
+ logger: _logger,
913
+ observability
794
914
  }) {
795
- var _a, _b, _c;
915
+ var _a, _b, _c, _d;
796
916
  const useAGUI = _useAGUI ?? true;
797
917
  const logger = _logger ?? import_agent_shared2.noopLogger;
798
- const basePath = _basePath ?? (process.env.TENCENTCLOUD_RUNENV === "SCF" ? "/v1/aibot/bots/:agentId/" : "/");
918
+ const userProvidedBasePath = _basePath !== void 0;
799
919
  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);
802
- if (useAGUI) {
803
- createAGUIRoute({
804
- basePath,
805
- express,
806
- createAgent,
807
- logger: serverLogger,
808
- ...aguiOptions || {}
920
+ (_b = serverLogger.debug) == null ? void 0 : _b.call(
921
+ serverLogger,
922
+ { basePath: _basePath, useAGUI, userProvidedBasePath },
923
+ "Initializing server routes"
924
+ );
925
+ if (observability) {
926
+ setupObservabilityIfAvailable(observability).catch(() => {
809
927
  });
810
928
  }
929
+ const sendMessageServerAdapter = useAGUI ? sendMessageAGUI_exports.createServerAdapter(createAgent, {
930
+ logger: serverLogger
931
+ }) : sendMessage_exports.createServerAdapter(createAgent);
811
932
  const openaiServerAdapter = openai_exports.createServerAdapter(createAgent);
812
933
  const healthzServerAdapter = healthz_exports.serverAdapter;
813
- express.use(`${basePath}send-message`, sendMessageServerAdapter);
814
- express.use(`${basePath}healthz`, healthzServerAdapter);
815
- express.use(`${basePath}chat/completions`, openaiServerAdapter);
816
- (_c = serverLogger.info) == null ? void 0 : _c.call(serverLogger, { basePath }, "Server routes initialized");
934
+ if (userProvidedBasePath) {
935
+ const basePath = _basePath;
936
+ if (useAGUI) {
937
+ createAGUIRoute({
938
+ basePath,
939
+ express,
940
+ createAgent,
941
+ logger: serverLogger,
942
+ ...aguiOptions || {}
943
+ });
944
+ }
945
+ express.use(`${basePath}send-message`, sendMessageServerAdapter);
946
+ express.use(`${basePath}healthz`, healthzServerAdapter);
947
+ express.use(`${basePath}chat/completions`, openaiServerAdapter);
948
+ (_c = serverLogger.info) == null ? void 0 : _c.call(serverLogger, { basePath }, "Server routes initialized");
949
+ } else {
950
+ const simplePath = "/";
951
+ const scfPath = "/v1/aibot/bots/:agentId/";
952
+ if (useAGUI) {
953
+ createAGUIRoute({
954
+ basePath: simplePath,
955
+ express,
956
+ createAgent,
957
+ logger: serverLogger,
958
+ ...aguiOptions || {}
959
+ });
960
+ createAGUIRoute({
961
+ basePath: scfPath,
962
+ express,
963
+ createAgent,
964
+ logger: serverLogger,
965
+ ...aguiOptions || {}
966
+ });
967
+ }
968
+ express.use(`${simplePath}send-message`, sendMessageServerAdapter);
969
+ express.use(`${simplePath}healthz`, healthzServerAdapter);
970
+ express.use(`${simplePath}chat/completions`, openaiServerAdapter);
971
+ express.use(`${scfPath}send-message`, sendMessageServerAdapter);
972
+ express.use(`${scfPath}healthz`, healthzServerAdapter);
973
+ express.use(`${scfPath}chat/completions`, openaiServerAdapter);
974
+ (_d = serverLogger.info) == null ? void 0 : _d.call(
975
+ serverLogger,
976
+ { simplePath, scfPath },
977
+ "Server routes initialized (dual endpoints)"
978
+ );
979
+ }
817
980
  return express;
818
981
  }
819
- var AGUIRpcHandlerPromise = null;
982
+ var AGUIRpcHandlerPromiseMap = /* @__PURE__ */ new Map();
820
983
  function getAGUIRpcHandler({
821
984
  createAgent,
822
985
  runtimeOptions,
@@ -826,8 +989,9 @@ function getAGUIRpcHandler({
826
989
  logger,
827
990
  requestId
828
991
  }) {
829
- if (AGUIRpcHandlerPromise) return AGUIRpcHandlerPromise;
830
- AGUIRpcHandlerPromise = (async () => {
992
+ const cached = AGUIRpcHandlerPromiseMap.get(basePath);
993
+ if (cached) return cached;
994
+ const handlerPromise = (async () => {
831
995
  const { agent } = await createAgent({ request, logger, requestId });
832
996
  const templateAgent = "toAGUIAgent" in agent ? agent.toAGUIAgent() : agent;
833
997
  templateAgent.clone = agentCloneFn;
@@ -844,7 +1008,8 @@ function getAGUIRpcHandler({
844
1008
  ...endpointOptions || {}
845
1009
  });
846
1010
  })();
847
- return AGUIRpcHandlerPromise;
1011
+ AGUIRpcHandlerPromiseMap.set(basePath, handlerPromise);
1012
+ return handlerPromise;
848
1013
  }
849
1014
  function createAGUIRoute({
850
1015
  express,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudbase/agent-server",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "main": "dist/index.js",
5
5
  "files": [
6
6
  "dist/",
@@ -20,11 +20,14 @@
20
20
  "express": "^5.1.0",
21
21
  "openai": "6.3.0",
22
22
  "uuid": "^10.0.0",
23
- "@cloudbase/agent-shared": "^0.0.15"
23
+ "@cloudbase/agent-shared": "^0.0.16"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "zod": "^3.25.0 || ^4.0.0"
27
27
  },
28
+ "optionalDependencies": {
29
+ "@cloudbase/agent-observability": "0.0.16"
30
+ },
28
31
  "devDependencies": {
29
32
  "@types/cors": "^2.8.19",
30
33
  "@types/express": "^5.0.3",