@hebo-ai/gateway 0.8.2 → 0.9.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 (44) hide show
  1. package/README.md +131 -32
  2. package/dist/endpoints/chat-completions/converters.d.ts +4 -21
  3. package/dist/endpoints/chat-completions/converters.js +23 -160
  4. package/dist/endpoints/chat-completions/handler.js +2 -2
  5. package/dist/endpoints/chat-completions/schema.d.ts +45 -101
  6. package/dist/endpoints/chat-completions/schema.js +13 -69
  7. package/dist/endpoints/conversations/converters.js +2 -3
  8. package/dist/endpoints/conversations/schema.d.ts +506 -644
  9. package/dist/endpoints/conversations/schema.js +8 -159
  10. package/dist/endpoints/conversations/storage/dialects/greptime.js +20 -6
  11. package/dist/endpoints/conversations/storage/dialects/mysql.js +3 -1
  12. package/dist/endpoints/conversations/storage/dialects/postgres.js +6 -3
  13. package/dist/endpoints/conversations/storage/dialects/sqlite.js +3 -1
  14. package/dist/endpoints/conversations/storage/sql.js +11 -6
  15. package/dist/endpoints/embeddings/handler.js +1 -1
  16. package/dist/endpoints/responses/converters.d.ts +17 -0
  17. package/dist/endpoints/responses/converters.js +1034 -0
  18. package/dist/endpoints/responses/handler.d.ts +2 -0
  19. package/dist/endpoints/responses/handler.js +137 -0
  20. package/dist/endpoints/responses/index.d.ts +4 -0
  21. package/dist/endpoints/responses/index.js +4 -0
  22. package/dist/endpoints/responses/otel.d.ts +6 -0
  23. package/dist/endpoints/responses/otel.js +221 -0
  24. package/dist/endpoints/responses/schema.d.ts +2109 -0
  25. package/dist/endpoints/responses/schema.js +314 -0
  26. package/dist/endpoints/shared/converters.d.ts +56 -0
  27. package/dist/endpoints/shared/converters.js +179 -0
  28. package/dist/endpoints/shared/schema.d.ts +70 -0
  29. package/dist/endpoints/shared/schema.js +46 -0
  30. package/dist/gateway.d.ts +1 -0
  31. package/dist/gateway.js +2 -0
  32. package/dist/index.d.ts +0 -4
  33. package/dist/index.js +0 -4
  34. package/dist/lifecycle.js +46 -29
  35. package/dist/models/anthropic/middleware.d.ts +1 -1
  36. package/dist/models/anthropic/presets.js +6 -1
  37. package/dist/models/google/middleware.d.ts +1 -1
  38. package/dist/models/google/middleware.js +9 -3
  39. package/dist/models/meta/presets.js +12 -2
  40. package/dist/providers/registry.d.ts +1 -1
  41. package/dist/types.d.ts +18 -6
  42. package/dist/utils/env.js +1 -1
  43. package/dist/utils/preset.js +0 -1
  44. package/package.json +8 -4
@@ -1,159 +1,8 @@
1
1
  import * as z from "zod";
2
- /**
3
- * --- Metadata ---
4
- */
5
- // Note: The 16-key limit is not currently validated.
6
- export const MetadataSchema = z
7
- .record(z.string().max(64), z.string().max(512))
8
- .nullable()
9
- .optional();
10
- export const ItemStatusSchema = z.enum(["in_progress", "completed", "incomplete"]);
11
- export const ImageDetailSchema = z.enum(["low", "high", "auto"]);
12
- /**
13
- * --- Messaging Content & Items ---
14
- */
15
- // Content Parts
16
- export const ResponseInputTextSchema = z.object({
17
- type: z.literal("input_text"),
18
- text: z.string(),
19
- });
20
- const ResponseInputImageURLSchema = z.object({
21
- type: z.literal("input_image"),
22
- image_url: z.string(),
23
- file_id: z.string().optional(),
24
- detail: ImageDetailSchema.optional(),
25
- });
26
- const ResponseInputImageIDSchema = z.object({
27
- type: z.literal("input_image"),
28
- file_id: z.string(),
29
- image_url: z.string().optional(),
30
- detail: ImageDetailSchema.optional(),
31
- });
32
- export const ResponseInputImageSchema = z.union([
33
- ResponseInputImageURLSchema,
34
- ResponseInputImageIDSchema,
35
- ]);
36
- const ResponseInputFileDataSchema = z.object({
37
- type: z.literal("input_file"),
38
- file_data: z.string(),
39
- file_id: z.string().optional(),
40
- file_url: z.string().optional(),
41
- filename: z.string().optional(),
42
- });
43
- const ResponseInputFileIDSchema = z.object({
44
- type: z.literal("input_file"),
45
- file_id: z.string(),
46
- file_data: z.string().optional(),
47
- file_url: z.string().optional(),
48
- filename: z.string().optional(),
49
- });
50
- const ResponseInputFileURLSchema = z.object({
51
- type: z.literal("input_file"),
52
- file_url: z.string(),
53
- file_data: z.string().optional(),
54
- file_id: z.string().optional(),
55
- filename: z.string().optional(),
56
- });
57
- export const ResponseInputFileSchema = z.union([
58
- ResponseInputFileDataSchema,
59
- ResponseInputFileIDSchema,
60
- ResponseInputFileURLSchema,
61
- ]);
62
- export const ResponseInputContentSchema = z.union([
63
- ResponseInputTextSchema,
64
- ResponseInputImageURLSchema,
65
- ResponseInputImageIDSchema,
66
- ResponseInputFileDataSchema,
67
- ResponseInputFileIDSchema,
68
- ResponseInputFileURLSchema,
69
- ]);
70
- export const ResponseOutputTextSchema = z.object({
71
- type: z.literal("output_text"),
72
- text: z.string(),
73
- annotations: z.array(z.unknown()).optional(),
74
- });
75
- // Message Items
76
- const MessageItemBaseSchema = z
77
- .object({
78
- type: z.literal("message"),
79
- id: z.string().optional(),
80
- status: ItemStatusSchema.optional(),
81
- })
82
- .loose();
83
- const UserMessageSchema = MessageItemBaseSchema.extend({
84
- role: z.literal("user"),
85
- content: z.union([z.string(), z.array(ResponseInputContentSchema)]),
86
- });
87
- const AssistantMessageSchema = MessageItemBaseSchema.extend({
88
- role: z.literal("assistant"),
89
- content: z.union([z.string(), z.array(ResponseOutputTextSchema)]),
90
- });
91
- const SystemMessageSchema = MessageItemBaseSchema.extend({
92
- role: z.literal("system"),
93
- content: z.union([z.string(), z.array(ResponseInputContentSchema)]),
94
- });
95
- const DeveloperMessageSchema = MessageItemBaseSchema.extend({
96
- role: z.literal("developer"),
97
- content: z.union([z.string(), z.array(ResponseInputContentSchema)]),
98
- });
99
- export const MessageItemUnionSchema = z.discriminatedUnion("role", [
100
- UserMessageSchema,
101
- AssistantMessageSchema,
102
- SystemMessageSchema,
103
- DeveloperMessageSchema,
104
- ]);
105
- /**
106
- * --- Function ---
107
- */
108
- export const ResponseFunctionToolCallSchema = z
109
- .object({
110
- type: z.literal("function_call"),
111
- id: z.string().optional(),
112
- call_id: z.string(),
113
- name: z.string(),
114
- arguments: z.string(),
115
- status: ItemStatusSchema.optional(),
116
- })
117
- .loose();
118
- export const FunctionCallOutputSchema = z
119
- .object({
120
- type: z.literal("function_call_output"),
121
- id: z.string().optional(),
122
- call_id: z.string(),
123
- output: z.union([z.string(), z.array(ResponseInputContentSchema)]),
124
- status: ItemStatusSchema.optional(),
125
- })
126
- .loose();
127
- /**
128
- * --- Reasoning ---
129
- */
130
- export const ResponseSummaryTextSchema = z.object({
131
- type: z.literal("summary_text"),
132
- text: z.string(),
133
- });
134
- export const ResponseReasoningTextSchema = z.object({
135
- type: z.literal("reasoning_text"),
136
- text: z.string(),
137
- });
138
- export const ResponseReasoningItemSchema = z
139
- .object({
140
- type: z.literal("reasoning"),
141
- id: z.string().optional(),
142
- summary: z.array(ResponseSummaryTextSchema),
143
- content: z.array(ResponseReasoningTextSchema).optional(),
144
- encrypted_content: z.string().optional(),
145
- status: ItemStatusSchema.optional(),
146
- })
147
- .loose();
2
+ import { ResponsesMetadataSchema, ResponsesInputItemSchema } from "../responses/schema";
148
3
  /**
149
4
  * --- Entities ---
150
5
  */
151
- export const ResponseInputItemSchema = z.discriminatedUnion("type", [
152
- MessageItemUnionSchema,
153
- ResponseFunctionToolCallSchema,
154
- FunctionCallOutputSchema,
155
- ResponseReasoningItemSchema,
156
- ]);
157
6
  export const ConversationItemSchema = z
158
7
  .object({
159
8
  id: z.string(),
@@ -161,12 +10,12 @@ export const ConversationItemSchema = z
161
10
  created_at: z.number().int(),
162
11
  })
163
12
  .loose()
164
- .and(ResponseInputItemSchema);
13
+ .and(ResponsesInputItemSchema);
165
14
  export const ConversationSchema = z.object({
166
15
  id: z.string(),
167
16
  object: z.literal("conversation"),
168
17
  created_at: z.number().int(),
169
- metadata: MetadataSchema,
18
+ metadata: ResponsesMetadataSchema,
170
19
  });
171
20
  export const ConversationDeletedSchema = z.object({
172
21
  id: z.string(),
@@ -177,14 +26,14 @@ export const ConversationDeletedSchema = z.object({
177
26
  * --- API ---
178
27
  */
179
28
  export const ConversationCreateParamsSchema = z.object({
180
- items: z.array(ResponseInputItemSchema).max(1000).optional(),
181
- metadata: MetadataSchema.optional(),
29
+ items: z.array(ResponsesInputItemSchema).max(1000).optional(),
30
+ metadata: ResponsesMetadataSchema.optional(),
182
31
  });
183
32
  export const ConversationUpdateBodySchema = z.object({
184
- metadata: MetadataSchema,
33
+ metadata: ResponsesMetadataSchema,
185
34
  });
186
35
  export const ConversationItemsAddBodySchema = z.object({
187
- items: z.array(ResponseInputItemSchema).max(1000),
36
+ items: z.array(ResponsesInputItemSchema).max(1000),
188
37
  });
189
38
  export const ConversationItemListSchema = z.object({
190
39
  object: z.literal("list"),
@@ -221,5 +70,5 @@ export const ConversationListParamsSchema = z.preprocess((input) => {
221
70
  }
222
71
  return rest;
223
72
  }, ConversationItemListParamsSchema.extend({
224
- metadata: MetadataSchema.optional(),
73
+ metadata: ResponsesMetadataSchema.optional(),
225
74
  }));
@@ -29,10 +29,22 @@ export const GrepTimeDialectConfig = Object.assign({}, PostgresDialectConfig, Gr
29
29
  partitionClause: (cols) => {
30
30
  const col = cols[0];
31
31
  return (`PARTITION ON COLUMNS (${col}) (` +
32
- `${col} < '4', ` +
33
- `${col} >= '4' AND ${col} < '8', ` +
34
- `${col} >= '8' AND ${col} < 'c', ` +
35
- `${col} >= 'c')`);
32
+ `${col} < '1', ` +
33
+ `${col} >= 'f', ` +
34
+ `${col} >= '1' AND ${col} < '2', ` +
35
+ `${col} >= '2' AND ${col} < '3', ` +
36
+ `${col} >= '3' AND ${col} < '4', ` +
37
+ `${col} >= '4' AND ${col} < '5', ` +
38
+ `${col} >= '5' AND ${col} < '6', ` +
39
+ `${col} >= '6' AND ${col} < '7', ` +
40
+ `${col} >= '7' AND ${col} < '8', ` +
41
+ `${col} >= '8' AND ${col} < '9', ` +
42
+ `${col} >= '9' AND ${col} < 'a', ` +
43
+ `${col} >= 'a' AND ${col} < 'b', ` +
44
+ `${col} >= 'b' AND ${col} < 'c', ` +
45
+ `${col} >= 'c' AND ${col} < 'd', ` +
46
+ `${col} >= 'd' AND ${col} < 'e', ` +
47
+ `${col} >= 'e' AND ${col} < 'f')`);
36
48
  },
37
49
  types: GrepTimeBase.types,
38
50
  });
@@ -47,8 +59,10 @@ function dateToGreptimeString(v) {
47
59
  // coerces JavaScript types differently. There is no unified parameter format:
48
60
  //
49
61
  // 1. Timestamps:
50
- // - `pg` requires a strictly formatted string (YYYY-MM-DD HH:mm:ss.SSS). It fails on BigInt.
51
- // - `postgresjs` requires a BigInt (milliseconds). It parses strings into ISO formats which GreptimeDB rejects.
62
+ // - `pg` requires a strictly formatted string (YYYY-MM-DD HH:mm:ss.SSS).
63
+ // It fails on BigInt.
64
+ // - `postgresjs` requires a BigInt (milliseconds). It parses strings into ISO
65
+ // formats which GreptimeDB rejects.
52
66
  // - `Bun.SQL` is flexible, but we use BigInt for consistency with postgresjs.
53
67
  //
54
68
  // 2. JSON:
@@ -55,7 +55,9 @@ function createMysql2Executor(pool) {
55
55
  const header = res;
56
56
  return { changes: Number(header.affectedRows ?? 0) };
57
57
  },
58
- transaction: (f) => f(txExecutor),
58
+ transaction(txCallback) {
59
+ return txCallback(txExecutor);
60
+ },
59
61
  };
60
62
  try {
61
63
  const result = await fn(txExecutor);
@@ -80,7 +80,9 @@ function createPgExecutor(pool, mapParams) {
80
80
  const res = await client.query(getQuery(sql, p?.length > 0 ? p : undefined));
81
81
  return { changes: Number(res.rowCount ?? 0) };
82
82
  },
83
- transaction: (f) => f(txExecutor),
83
+ transaction(txCallback) {
84
+ return txCallback(txExecutor);
85
+ },
84
86
  };
85
87
  try {
86
88
  const result = await fn(txExecutor);
@@ -141,8 +143,9 @@ function createBunPostgresExecutor(sql, mapParams) {
141
143
  const res = (await sql.unsafe(query, p?.length > 0 ? p : undefined));
142
144
  const result = res;
143
145
  let changes = result.affectedRows ?? result.count ?? 0;
144
- // When Bun.SQL is used with GreptimeDB, mutation responses over the Postgres wire protocol
145
- // don't populate `count` or `affectedRows`, but they do provide a command string like "OK 1"
146
+ // When Bun.SQL is used with GreptimeDB, mutation responses over the Postgres wire
147
+ // protocol don't populate `count` or `affectedRows`, but they do provide a command
148
+ // string like "OK 1"
146
149
  if (changes === 0 && result.command?.startsWith("OK ")) {
147
150
  const parsed = parseInt(result.command.slice(3), 10);
148
151
  if (!isNaN(parsed))
@@ -114,7 +114,9 @@ function createLibsqlExecutor(client) {
114
114
  const rs = await tx.execute({ sql, args: mapParams(params) ?? [] });
115
115
  return { changes: Number(rs.rowsAffected) };
116
116
  },
117
- transaction: (f) => f(txExecutor),
117
+ transaction(txCallback) {
118
+ return txCallback(txExecutor);
119
+ },
118
120
  };
119
121
  try {
120
122
  const result = await fn(txExecutor);
@@ -93,7 +93,8 @@ export class SqlStorage {
93
93
  const metadata = params.metadata ?? null;
94
94
  const now = new Date();
95
95
  return this.executor.transaction(async (tx) => {
96
- await tx.run(`INSERT INTO ${q("conversations")} (${q("id")}, ${q("metadata")}, ${q("created_at")}) VALUES (${p(0)}, ${p(1)}, ${p(2)})`, [id, metadata, now]);
96
+ await tx.run(`INSERT INTO ${q("conversations")} (${q("id")}, ${q("metadata")}, ${q("created_at")}) ` +
97
+ `VALUES (${p(0)}, ${p(1)}, ${p(2)})`, [id, metadata, now]);
97
98
  const conversation = {
98
99
  id,
99
100
  created_at: now.getTime(),
@@ -158,10 +159,13 @@ export class SqlStorage {
158
159
  const { placeholder: p, quote: q, upsertSuffix } = this.config;
159
160
  return this.executor.transaction(async (tx) => {
160
161
  // Unified approach: Fetch original created_at to verify existence and preserve it.
161
- // 1. Existence check: Ensure the conversation exists before updating (returning undefined if missing).
162
- // This prevents clients from accidentally creating "zombie" conversations with custom IDs.
163
- // 2. Consistency: Standard SQL (Postgres/MySQL/SQLite) preserves the original creation timestamp.
164
- // 3. Deduplication: GreptimeDB requires the EXACT same Time Index (created_at) to deduplicate the row.
162
+ // 1. Existence check: Ensure the conversation exists before updating (returning
163
+ // undefined if missing). This prevents clients from accidentally creating
164
+ // "zombie" conversations with custom IDs.
165
+ // 2. Consistency: Standard SQL (Postgres/MySQL/SQLite) preserves the original
166
+ // creation timestamp.
167
+ // 3. Deduplication: GreptimeDB requires the EXACT same Time Index (created_at)
168
+ // to deduplicate the row.
165
169
  const conversation = await this.getConversationInternal(id, tx);
166
170
  if (!conversation)
167
171
  return;
@@ -169,7 +173,8 @@ export class SqlStorage {
169
173
  const pk = ["id"];
170
174
  const updateCols = ["metadata"];
171
175
  const suffix = upsertSuffix?.(q, pk, updateCols) ?? "";
172
- await tx.run(`INSERT INTO ${q("conversations")} (${q("id")}, ${q("metadata")}, ${q("created_at")}) VALUES (${p(0)}, ${p(1)}, ${p(2)}) ${suffix}`, [id, metadata ?? null, new Date(createdAt)]);
176
+ await tx.run(`INSERT INTO ${q("conversations")} (${q("id")}, ${q("metadata")}, ${q("created_at")}) ` +
177
+ `VALUES (${p(0)}, ${p(1)}, ${p(2)}) ${suffix}`, [id, metadata ?? null, new Date(createdAt)]);
173
178
  return {
174
179
  id,
175
180
  created_at: createdAt,
@@ -16,6 +16,7 @@ export const embeddings = (config) => {
16
16
  const handler = async (ctx, cfg) => {
17
17
  const start = performance.now();
18
18
  ctx.operation = "embeddings";
19
+ setSpanAttributes({ "gen_ai.operation.name": ctx.operation });
19
20
  addSpanEvent("hebo.handler.started");
20
21
  // Guard: enforce HTTP method early.
21
22
  if (!ctx.request || ctx.request.method !== "POST") {
@@ -66,7 +67,6 @@ export const embeddings = (config) => {
66
67
  setSpanAttributes(genAiGeneralAttrs);
67
68
  // Convert inputs to AI SDK call options.
68
69
  const { model: _model, ...inputs } = ctx.body;
69
- // oxlint-disable-next-line no-unsafe-argument
70
70
  const embedOptions = convertToEmbedCallOptions(inputs);
71
71
  logger.trace({ requestId: ctx.requestId, options: embedOptions }, "[embeddings] AI SDK options");
72
72
  addSpanEvent("hebo.options.prepared");
@@ -0,0 +1,17 @@
1
+ import type { GenerateTextResult, StreamTextResult, ToolSet, ModelMessage, LanguageModelUsage, TextStreamPart } from "ai";
2
+ import { Output } from "ai";
3
+ import type { ResponsesInputItem, ResponsesInputs, Responses, ResponsesUsage, ResponsesStream, ResponsesStreamEvent, ResponsesToolChoice, ResponsesTool } from "./schema";
4
+ import type { SseErrorFrame } from "../../utils/stream";
5
+ import { type TextCallOptions, type ToolChoiceOptions } from "../shared/converters";
6
+ export declare function convertToTextCallOptions(params: ResponsesInputs): TextCallOptions;
7
+ export declare function convertToModelMessages(input: string | ResponsesInputItem[], instructions?: string): ModelMessage[];
8
+ export declare const convertToToolSet: (tools: ResponsesTool[] | undefined) => ToolSet | undefined;
9
+ export declare const convertToToolChoiceOptions: (toolChoice: ResponsesToolChoice | undefined) => ToolChoiceOptions;
10
+ export declare function toResponses(result: GenerateTextResult<ToolSet, Output.Output>, model: string, metadata?: Record<string, string> | null): Responses;
11
+ export declare function toResponsesResponse(result: GenerateTextResult<ToolSet, Output.Output>, model: string, metadata?: Record<string, string> | null, responseInit?: ResponseInit): Response;
12
+ export declare function toResponsesStream(result: StreamTextResult<ToolSet, Output.Output>, model: string, metadata?: Record<string, string> | null): ResponsesStream;
13
+ export declare function toResponsesStreamResponse(result: StreamTextResult<ToolSet, Output.Output>, model: string, metadata?: Record<string, string> | null, responseInit?: ResponseInit): Response;
14
+ export declare function toResponsesUsage(usage: LanguageModelUsage): ResponsesUsage;
15
+ export declare class ResponsesTransformStream extends TransformStream<TextStreamPart<ToolSet>, ResponsesStreamEvent | SseErrorFrame> {
16
+ constructor(model: string, metadata?: Record<string, string> | null);
17
+ }