@hebo-ai/gateway 0.4.0-beta.1 → 0.4.0-beta.2

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/lifecycle.js CHANGED
@@ -2,7 +2,7 @@ import { parseConfig } from "./config";
2
2
  import { toOpenAIErrorResponse } from "./errors/openai";
3
3
  import { logger } from "./logger";
4
4
  import { withOtel } from "./telemetry/otel";
5
- import { addSpanEvent } from "./telemetry/span";
5
+ import { addSpanEvent, recordSpanError } from "./telemetry/span";
6
6
  import { resolveRequestId } from "./utils/headers";
7
7
  import { maybeApplyRequestPatch, prepareRequestHeaders } from "./utils/request";
8
8
  import { prepareResponseInit, toResponse } from "./utils/response";
@@ -32,6 +32,7 @@ export const winterCgHandler = (run, config) => {
32
32
  }
33
33
  }
34
34
  catch (error) {
35
+ recordSpanError(error);
35
36
  logger.error({
36
37
  requestId: resolveRequestId(ctx.request),
37
38
  err: error instanceof Error ? error : new Error(String(error)),
@@ -7,3 +7,4 @@ export declare const startSpan: (name: string, options?: SpanOptions, customTrac
7
7
  };
8
8
  export declare const withSpan: <T>(name: string, run: () => Promise<T> | T, options?: SpanOptions) => Promise<T>;
9
9
  export declare const addSpanEvent: (name: string, attributes?: Attributes) => void;
10
+ export declare const recordSpanError: (error: unknown) => void;
@@ -62,3 +62,11 @@ export const addSpanEvent = (name, attributes) => {
62
62
  const allAttributes = Object.assign(attributes ?? {}, getMemoryAttributes());
63
63
  trace.getActiveSpan()?.addEvent(name, allAttributes);
64
64
  };
65
+ export const recordSpanError = (error) => {
66
+ const span = trace.getActiveSpan();
67
+ if (!span)
68
+ return;
69
+ const err = toError(error);
70
+ span.recordException(err);
71
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
72
+ };
@@ -1,8 +1,6 @@
1
1
  export type InstrumentStreamHooks = {
2
2
  onComplete?: (status: number, stats: {
3
3
  bytes: number;
4
- streamStart: number;
5
- streamEnd: number;
6
4
  }) => void;
7
5
  onError?: (error: unknown, status: number) => void;
8
6
  };
@@ -1,5 +1,5 @@
1
1
  export const instrumentStream = (src, hooks, signal) => {
2
- const stats = { bytes: 0, streamStart: performance.now() };
2
+ const stats = { bytes: 0 };
3
3
  let done = false;
4
4
  const finish = (status, reason) => {
5
5
  if (done)
@@ -10,12 +10,7 @@ export const instrumentStream = (src, hooks, signal) => {
10
10
  if (status >= 400) {
11
11
  hooks.onError?.(reason, status);
12
12
  }
13
- const timing = {
14
- bytes: stats.bytes,
15
- streamStart: stats.streamStart,
16
- streamEnd: performance.now(),
17
- };
18
- hooks.onComplete?.(status, timing);
13
+ hooks.onComplete?.(status, stats);
19
14
  };
20
15
  return new ReadableStream({
21
16
  async start(controller) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hebo-ai/gateway",
3
- "version": "0.4.0-beta.1",
3
+ "version": "0.4.0-beta.2",
4
4
  "description": "AI gateway as a framework. For full control over models, routing & lifecycle. OpenAI-compatible /chat/completions, /embeddings & /models.",
5
5
  "keywords": [
6
6
  "ai",
package/src/lifecycle.ts CHANGED
@@ -9,7 +9,7 @@ import { parseConfig } from "./config";
9
9
  import { toOpenAIErrorResponse } from "./errors/openai";
10
10
  import { logger } from "./logger";
11
11
  import { withOtel } from "./telemetry/otel";
12
- import { addSpanEvent } from "./telemetry/span";
12
+ import { addSpanEvent, recordSpanError } from "./telemetry/span";
13
13
  import { resolveRequestId } from "./utils/headers";
14
14
  import { maybeApplyRequestPatch, prepareRequestHeaders } from "./utils/request";
15
15
  import { prepareResponseInit, toResponse } from "./utils/response";
@@ -46,6 +46,7 @@ export const winterCgHandler = (
46
46
  }
47
47
  }
48
48
  } catch (error) {
49
+ recordSpanError(error);
49
50
  logger.error({
50
51
  requestId: resolveRequestId(ctx.request),
51
52
  err: error instanceof Error ? error : new Error(String(error)),
@@ -86,3 +86,12 @@ export const addSpanEvent = (name: string, attributes?: Attributes) => {
86
86
  const allAttributes = Object.assign(attributes ?? {}, getMemoryAttributes());
87
87
  trace.getActiveSpan()?.addEvent(name, allAttributes);
88
88
  };
89
+
90
+ export const recordSpanError = (error: unknown) => {
91
+ const span = trace.getActiveSpan();
92
+ if (!span) return;
93
+
94
+ const err = toError(error);
95
+ span.recordException(err);
96
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
97
+ };
@@ -1,8 +1,5 @@
1
1
  export type InstrumentStreamHooks = {
2
- onComplete?: (
3
- status: number,
4
- stats: { bytes: number; streamStart: number; streamEnd: number },
5
- ) => void;
2
+ onComplete?: (status: number, stats: { bytes: number }) => void;
6
3
  onError?: (error: unknown, status: number) => void;
7
4
  };
8
5
 
@@ -11,7 +8,7 @@ export const instrumentStream = (
11
8
  hooks: InstrumentStreamHooks,
12
9
  signal?: AbortSignal,
13
10
  ): ReadableStream<Uint8Array> => {
14
- const stats = { bytes: 0, streamStart: performance.now() };
11
+ const stats = { bytes: 0 };
15
12
  let done = false;
16
13
 
17
14
  const finish = (status: number, reason?: unknown) => {
@@ -24,13 +21,7 @@ export const instrumentStream = (
24
21
  hooks.onError?.(reason, status);
25
22
  }
26
23
 
27
- const timing = {
28
- bytes: stats.bytes,
29
- streamStart: stats.streamStart,
30
- streamEnd: performance.now(),
31
- };
32
-
33
- hooks.onComplete?.(status, timing);
24
+ hooks.onComplete?.(status, stats);
34
25
  };
35
26
 
36
27
  return new ReadableStream<Uint8Array>({