@hebo-ai/gateway 0.4.0-beta.4 → 0.4.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.
Files changed (42) hide show
  1. package/README.md +34 -7
  2. package/dist/endpoints/chat-completions/converters.d.ts +3 -3
  3. package/dist/endpoints/chat-completions/converters.js +15 -7
  4. package/dist/endpoints/chat-completions/handler.js +9 -9
  5. package/dist/endpoints/chat-completions/otel.js +10 -4
  6. package/dist/endpoints/embeddings/handler.js +5 -4
  7. package/dist/errors/gateway.d.ts +1 -1
  8. package/dist/errors/gateway.js +3 -3
  9. package/dist/errors/openai.js +2 -1
  10. package/dist/errors/utils.d.ts +2 -1
  11. package/dist/errors/utils.js +1 -0
  12. package/dist/lifecycle.js +14 -6
  13. package/dist/models/anthropic/presets.d.ts +463 -0
  14. package/dist/models/anthropic/presets.js +10 -2
  15. package/dist/models/types.d.ts +1 -1
  16. package/dist/models/types.js +1 -0
  17. package/dist/providers/bedrock/canonical.js +1 -0
  18. package/dist/telemetry/gen-ai.d.ts +2 -1
  19. package/dist/telemetry/gen-ai.js +21 -3
  20. package/dist/telemetry/memory.d.ts +2 -0
  21. package/dist/telemetry/memory.js +27 -0
  22. package/dist/telemetry/span.js +1 -1
  23. package/dist/telemetry/stream.d.ts +1 -1
  24. package/dist/telemetry/stream.js +25 -28
  25. package/dist/types.d.ts +2 -3
  26. package/package.json +2 -1
  27. package/src/endpoints/chat-completions/converters.ts +17 -10
  28. package/src/endpoints/chat-completions/handler.ts +13 -9
  29. package/src/endpoints/chat-completions/otel.ts +11 -4
  30. package/src/endpoints/embeddings/handler.ts +9 -4
  31. package/src/errors/gateway.ts +5 -4
  32. package/src/errors/openai.ts +2 -1
  33. package/src/errors/utils.ts +1 -0
  34. package/src/lifecycle.ts +17 -6
  35. package/src/models/anthropic/presets.ts +14 -2
  36. package/src/models/types.ts +1 -0
  37. package/src/providers/bedrock/canonical.ts +1 -0
  38. package/src/telemetry/gen-ai.ts +31 -3
  39. package/src/telemetry/memory.ts +36 -0
  40. package/src/telemetry/span.ts +1 -1
  41. package/src/telemetry/stream.ts +31 -31
  42. package/src/types.ts +3 -6
@@ -1,54 +1,51 @@
1
- const isErrorChunk = (v: unknown) => !!(v as any)?.error;
1
+ import { toOpenAIError } from "../errors/openai";
2
+
3
+ const isErrorChunk = (v: unknown) => v instanceof Error || !!(v as any)?.error;
2
4
 
3
5
  export const wrapStream = (
4
6
  src: ReadableStream,
5
7
  hooks: { onDone?: (status: number, reason: unknown) => void },
6
- signal?: AbortSignal,
7
8
  ): ReadableStream => {
8
- let finishOnce = false;
9
-
10
- const finish = (status: number, reason?: unknown) => {
11
- if (finishOnce) return;
12
- finishOnce = true;
9
+ let finished = false;
13
10
 
14
- hooks.onDone?.(status, reason ?? signal?.reason);
11
+ const done = (
12
+ reader: ReadableStreamDefaultReader,
13
+ controller: ReadableStreamDefaultController,
14
+ status: number,
15
+ reason?: unknown,
16
+ ) => {
17
+ if (!finished) {
18
+ finished = true;
19
+ hooks.onDone?.(status, reason);
20
+ }
21
+ reader.cancel(reason).catch(() => {});
22
+ controller.close();
15
23
  };
16
24
 
17
25
  return new ReadableStream({
18
26
  async start(controller) {
19
27
  const reader = src.getReader();
20
28
 
21
- const close = (status: number, reason?: unknown) => {
22
- finish(status, reason);
23
- reader.cancel(reason).catch(() => {});
24
- controller.close();
25
- };
26
-
27
29
  try {
28
30
  for (;;) {
29
- if (signal?.aborted) {
30
- close(499, signal.reason);
31
- return;
32
- }
33
-
34
31
  // eslint-disable-next-line no-await-in-loop
35
- const { value, done } = await reader.read();
36
- if (done) break;
32
+ const { value, done: eof } = await reader.read();
33
+ if (eof) break;
37
34
 
38
- controller.enqueue(value);
35
+ const out = isErrorChunk(value) ? toOpenAIError(value) : value;
36
+ controller.enqueue(out);
39
37
 
40
- if (isErrorChunk(value)) {
41
- const status = value.error.type === "invalid_request_error" ? 422 : 502;
42
- close(status, value.error.message);
38
+ if (out !== value) {
39
+ const status = out.error?.type === "invalid_request_error" ? 422 : 502;
40
+ done(reader, controller, status, value);
43
41
  return;
44
42
  }
45
43
  }
46
44
 
47
- finish(200);
48
- controller.close();
45
+ done(reader, controller, 200);
49
46
  } catch (err) {
50
- const status = signal?.aborted ? 499 : (err as any)?.name === "AbortError" ? 503 : 502;
51
- close(status, err);
47
+ controller.enqueue(toOpenAIError(err));
48
+ done(reader, controller, 502, err);
52
49
  } finally {
53
50
  try {
54
51
  reader.releaseLock();
@@ -56,8 +53,11 @@ export const wrapStream = (
56
53
  }
57
54
  },
58
55
 
59
- cancel(reason?: unknown) {
60
- finish(499, reason);
56
+ cancel(reason) {
57
+ if (!finished) {
58
+ finished = true;
59
+ hooks.onDone?.(499, reason);
60
+ }
61
61
  src.cancel(reason).catch(() => {});
62
62
  },
63
63
  });
package/src/types.ts CHANGED
@@ -8,7 +8,6 @@ import type {
8
8
  } from "./endpoints/chat-completions/schema";
9
9
  import type { Embeddings, EmbeddingsBody } from "./endpoints/embeddings/schema";
10
10
  import type { Model, ModelList } from "./endpoints/models";
11
- import type { OpenAIError } from "./errors/openai";
12
11
  import type { Logger, LoggerConfig } from "./logger";
13
12
  import type { ModelCatalog, ModelId } from "./models/types";
14
13
  import type { ProviderId, ProviderRegistry } from "./providers/types";
@@ -76,7 +75,7 @@ export type GatewayContext = {
76
75
  */
77
76
  result?:
78
77
  | ChatCompletions
79
- | ReadableStream<ChatCompletionsChunk | OpenAIError>
78
+ | ReadableStream<ChatCompletionsChunk | Error>
80
79
  | Embeddings
81
80
  | Model
82
81
  | ModelList;
@@ -150,11 +149,9 @@ export type GatewayHooks = {
150
149
  ) =>
151
150
  | void
152
151
  | ChatCompletions
153
- | ReadableStream<ChatCompletionsChunk | OpenAIError>
152
+ | ReadableStream<ChatCompletionsChunk | Error>
154
153
  | Embeddings
155
- | Promise<
156
- void | ChatCompletions | ReadableStream<ChatCompletionsChunk | OpenAIError> | Embeddings
157
- >;
154
+ | Promise<void | ChatCompletions | ReadableStream<ChatCompletionsChunk | Error> | Embeddings>;
158
155
  /**
159
156
  * Runs after the lifecycle has produced the final Response.
160
157
  * @returns Replacement Response, or undefined to keep original.