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

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 CHANGED
@@ -620,7 +620,7 @@ const gw = gateway({
620
620
  // "required" = minimal baseline attributes
621
621
  // "recommended" = practical operational attributes (request/response metadata, genai model/usage fields)
622
622
  // "full" = also include body fields (e.g. genai input/output messages)
623
- attributes: "recommended",
623
+ attributes: "full",
624
624
  },
625
625
  });
626
626
  ```
@@ -628,10 +628,10 @@ const gw = gateway({
628
628
  Attribute names and span semantics follow OpenTelemetry GenAI semantic conventions:
629
629
  https://opentelemetry.io/docs/specs/semconv/gen-ai/gen-ai-spans/
630
630
 
631
- To populate custom span attributes, the inbound W3C `baggage` header is supported. Keys in the `hebo.` namespace are mapped to span attributes, with the namespace stripped. For example: `baggage: hebo.user_id=u-123` becomes span attribute `user_id=u-123`.
632
-
633
631
  > [!TIP]
634
- > For observability integration that is not otel compliant (for example, Langfuse), you can disable built-in telemetry and manually instrument requests during `before` / `after` hooks.
632
+ > To populate custom span attributes, the inbound W3C `baggage` header is supported. Keys in the `hebo.` namespace are mapped to span attributes, with the namespace stripped. For example: `baggage: hebo.user_id=u-123` becomes span attribute `user_id=u-123`.
633
+
634
+ For observability integration that is not otel compliant, you can disable built-in telemetry and manually instrument requests during `before` / `after` hooks.
635
635
 
636
636
  ### Passing Framework State to Hooks
637
637
 
@@ -93,8 +93,8 @@ export const chatCompletions = (config) => {
93
93
  onAbort: () => {
94
94
  throw new DOMException("Upstream failed", "AbortError");
95
95
  },
96
- onFinish: (event) => {
97
- ctx.streamResult = toChatCompletions(event, ctx.resolvedModelId);
96
+ onFinish: (result) => {
97
+ ctx.streamResult = toChatCompletions(result, ctx.resolvedModelId);
98
98
  },
99
99
  timeout: {
100
100
  totalMs: 5 * 60 * 1000,
@@ -1,4 +1,5 @@
1
1
  import { logger } from "../logger";
2
+ import { addSpanEvent } from "../telemetry/span";
2
3
  import { forwardParamsEmbeddingMiddleware, forwardParamsMiddleware } from "./common";
3
4
  class SimpleMatcher {
4
5
  rules = [];
@@ -82,6 +83,7 @@ class ModelMiddlewareMatcher {
82
83
  break;
83
84
  }
84
85
  logger.warn(`[middleware] cache eviction`);
86
+ addSpanEvent("hebo.middelware.cache.evicted");
85
87
  }
86
88
  this.cache.set(key, out);
87
89
  return out;
@@ -59,5 +59,6 @@ export const withSpan = async (name, run, options) => {
59
59
  }
60
60
  };
61
61
  export const addSpanEvent = (name, attributes) => {
62
- trace.getActiveSpan()?.addEvent(name, attributes);
62
+ const allAttributes = Object.assign(attributes ?? {}, getMemoryAttributes());
63
+ trace.getActiveSpan()?.addEvent(name, allAttributes);
63
64
  };
@@ -1,4 +1,4 @@
1
- import { resolveRequestId } from "#/utils/headers";
1
+ import { resolveRequestId } from "../utils/headers";
2
2
  const DEFAULT_ATTRIBUTES_LEVEL = "recommended";
3
3
  const HEBO_BAGGAGE_PREFIX = "hebo.";
4
4
  const toTextPart = (content) => ({ type: "text", content });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hebo-ai/gateway",
3
- "version": "0.4.0-beta.0",
3
+ "version": "0.4.0-beta.1",
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",
@@ -127,9 +127,9 @@ export const chatCompletions = (config: GatewayConfig): Endpoint => {
127
127
  onAbort: () => {
128
128
  throw new DOMException("Upstream failed", "AbortError");
129
129
  },
130
- onFinish: (event) => {
130
+ onFinish: (result) => {
131
131
  ctx.streamResult = toChatCompletions(
132
- event as unknown as GenerateTextResult<ToolSet, Output.Output>,
132
+ result as unknown as GenerateTextResult<ToolSet, Output.Output>,
133
133
  ctx.resolvedModelId!,
134
134
  );
135
135
  },
@@ -4,6 +4,7 @@ import type { ModelId } from "../models/types";
4
4
  import type { ProviderId } from "../providers/types";
5
5
 
6
6
  import { logger } from "../logger";
7
+ import { addSpanEvent } from "../telemetry/span";
7
8
  import { forwardParamsEmbeddingMiddleware, forwardParamsMiddleware } from "./common";
8
9
 
9
10
  type MiddlewareEntries = {
@@ -117,6 +118,7 @@ class ModelMiddlewareMatcher {
117
118
  if (--n === 0) break;
118
119
  }
119
120
  logger.warn(`[middleware] cache eviction`);
121
+ addSpanEvent("hebo.middelware.cache.evicted");
120
122
  }
121
123
 
122
124
  this.cache.set(key, out);
@@ -83,5 +83,6 @@ export const withSpan = async <T>(
83
83
  };
84
84
 
85
85
  export const addSpanEvent = (name: string, attributes?: Attributes) => {
86
- trace.getActiveSpan()?.addEvent(name, attributes);
86
+ const allAttributes = Object.assign(attributes ?? {}, getMemoryAttributes());
87
+ trace.getActiveSpan()?.addEvent(name, allAttributes);
87
88
  };
@@ -1,13 +1,12 @@
1
- import type { Embeddings, EmbeddingsBody } from "#/endpoints/embeddings";
2
-
3
- import { resolveRequestId } from "#/utils/headers";
4
-
5
1
  import type {
6
2
  ChatCompletions,
7
3
  ChatCompletionsBody,
8
4
  ChatCompletionsContentPart,
9
5
  ChatCompletionsMessage,
10
6
  } from "../endpoints/chat-completions/schema";
7
+ import type { Embeddings, EmbeddingsBody } from "../endpoints/embeddings";
8
+
9
+ import { resolveRequestId } from "../utils/headers";
11
10
 
12
11
  type GenAIPart = Record<string, unknown>;
13
12
  const DEFAULT_ATTRIBUTES_LEVEL = "recommended";