@uncensoredcode/openbridge 0.1.0

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 (145) hide show
  1. package/README.md +117 -0
  2. package/bin/openbridge.js +10 -0
  3. package/package.json +85 -0
  4. package/packages/cli/dist/args.d.ts +30 -0
  5. package/packages/cli/dist/args.js +160 -0
  6. package/packages/cli/dist/cli.d.ts +2 -0
  7. package/packages/cli/dist/cli.js +9 -0
  8. package/packages/cli/dist/index.d.ts +26 -0
  9. package/packages/cli/dist/index.js +76 -0
  10. package/packages/runtime/dist/assistant-protocol.d.ts +34 -0
  11. package/packages/runtime/dist/assistant-protocol.js +121 -0
  12. package/packages/runtime/dist/execution/in-process.d.ts +14 -0
  13. package/packages/runtime/dist/execution/in-process.js +45 -0
  14. package/packages/runtime/dist/execution/types.d.ts +49 -0
  15. package/packages/runtime/dist/execution/types.js +20 -0
  16. package/packages/runtime/dist/index.d.ts +86 -0
  17. package/packages/runtime/dist/index.js +60 -0
  18. package/packages/runtime/dist/normalizers/index.d.ts +6 -0
  19. package/packages/runtime/dist/normalizers/index.js +12 -0
  20. package/packages/runtime/dist/normalizers/legacy-packet.d.ts +6 -0
  21. package/packages/runtime/dist/normalizers/legacy-packet.js +131 -0
  22. package/packages/runtime/dist/output-sanitizer.d.ts +23 -0
  23. package/packages/runtime/dist/output-sanitizer.js +78 -0
  24. package/packages/runtime/dist/packet-extractor.d.ts +17 -0
  25. package/packages/runtime/dist/packet-extractor.js +43 -0
  26. package/packages/runtime/dist/packet-normalizer.d.ts +21 -0
  27. package/packages/runtime/dist/packet-normalizer.js +47 -0
  28. package/packages/runtime/dist/prompt-compiler.d.ts +28 -0
  29. package/packages/runtime/dist/prompt-compiler.js +301 -0
  30. package/packages/runtime/dist/protocol.d.ts +44 -0
  31. package/packages/runtime/dist/protocol.js +165 -0
  32. package/packages/runtime/dist/provider-failure.d.ts +52 -0
  33. package/packages/runtime/dist/provider-failure.js +236 -0
  34. package/packages/runtime/dist/provider.d.ts +40 -0
  35. package/packages/runtime/dist/provider.js +1 -0
  36. package/packages/runtime/dist/runtime.d.ts +86 -0
  37. package/packages/runtime/dist/runtime.js +462 -0
  38. package/packages/runtime/dist/session-bound-provider.d.ts +52 -0
  39. package/packages/runtime/dist/session-bound-provider.js +366 -0
  40. package/packages/runtime/dist/tool-name-aliases.d.ts +5 -0
  41. package/packages/runtime/dist/tool-name-aliases.js +13 -0
  42. package/packages/runtime/dist/tools/bash.d.ts +9 -0
  43. package/packages/runtime/dist/tools/bash.js +157 -0
  44. package/packages/runtime/dist/tools/edit.d.ts +9 -0
  45. package/packages/runtime/dist/tools/edit.js +94 -0
  46. package/packages/runtime/dist/tools/index.d.ts +39 -0
  47. package/packages/runtime/dist/tools/index.js +27 -0
  48. package/packages/runtime/dist/tools/list-dir.d.ts +9 -0
  49. package/packages/runtime/dist/tools/list-dir.js +127 -0
  50. package/packages/runtime/dist/tools/read.d.ts +9 -0
  51. package/packages/runtime/dist/tools/read.js +56 -0
  52. package/packages/runtime/dist/tools/registry.d.ts +15 -0
  53. package/packages/runtime/dist/tools/registry.js +38 -0
  54. package/packages/runtime/dist/tools/runtime-path.d.ts +7 -0
  55. package/packages/runtime/dist/tools/runtime-path.js +22 -0
  56. package/packages/runtime/dist/tools/search-files.d.ts +9 -0
  57. package/packages/runtime/dist/tools/search-files.js +149 -0
  58. package/packages/runtime/dist/tools/text-file.d.ts +32 -0
  59. package/packages/runtime/dist/tools/text-file.js +101 -0
  60. package/packages/runtime/dist/tools/workspace-path.d.ts +17 -0
  61. package/packages/runtime/dist/tools/workspace-path.js +70 -0
  62. package/packages/runtime/dist/tools/write.d.ts +9 -0
  63. package/packages/runtime/dist/tools/write.js +59 -0
  64. package/packages/server/dist/bridge/bridge-model-catalog.d.ts +56 -0
  65. package/packages/server/dist/bridge/bridge-model-catalog.js +100 -0
  66. package/packages/server/dist/bridge/bridge-runtime-service.d.ts +61 -0
  67. package/packages/server/dist/bridge/bridge-runtime-service.js +1386 -0
  68. package/packages/server/dist/bridge/chat-completions/chat-completion-service.d.ts +127 -0
  69. package/packages/server/dist/bridge/chat-completions/chat-completion-service.js +1026 -0
  70. package/packages/server/dist/bridge/index.d.ts +335 -0
  71. package/packages/server/dist/bridge/index.js +45 -0
  72. package/packages/server/dist/bridge/live-provider-extraction-canary.d.ts +69 -0
  73. package/packages/server/dist/bridge/live-provider-extraction-canary.js +186 -0
  74. package/packages/server/dist/bridge/providers/generic-provider-transport.d.ts +53 -0
  75. package/packages/server/dist/bridge/providers/generic-provider-transport.js +973 -0
  76. package/packages/server/dist/bridge/providers/provider-session-resolver.d.ts +17 -0
  77. package/packages/server/dist/bridge/providers/provider-session-resolver.js +95 -0
  78. package/packages/server/dist/bridge/providers/provider-streams.d.ts +80 -0
  79. package/packages/server/dist/bridge/providers/provider-streams.js +844 -0
  80. package/packages/server/dist/bridge/providers/provider-transport-profile.d.ts +194 -0
  81. package/packages/server/dist/bridge/providers/provider-transport-profile.js +198 -0
  82. package/packages/server/dist/bridge/providers/web-provider-transport.d.ts +30 -0
  83. package/packages/server/dist/bridge/providers/web-provider-transport.js +151 -0
  84. package/packages/server/dist/bridge/state/file-bridge-state-store.d.ts +36 -0
  85. package/packages/server/dist/bridge/state/file-bridge-state-store.js +164 -0
  86. package/packages/server/dist/bridge/stores/local-session-package-store.d.ts +23 -0
  87. package/packages/server/dist/bridge/stores/local-session-package-store.js +548 -0
  88. package/packages/server/dist/bridge/stores/provider-store.d.ts +94 -0
  89. package/packages/server/dist/bridge/stores/provider-store.js +143 -0
  90. package/packages/server/dist/bridge/stores/session-backed-provider-store.d.ts +7 -0
  91. package/packages/server/dist/bridge/stores/session-backed-provider-store.js +26 -0
  92. package/packages/server/dist/bridge/stores/session-package-store.d.ts +286 -0
  93. package/packages/server/dist/bridge/stores/session-package-store.js +1527 -0
  94. package/packages/server/dist/bridge/stores/session-store.d.ts +120 -0
  95. package/packages/server/dist/bridge/stores/session-store.js +139 -0
  96. package/packages/server/dist/cli/index.d.ts +9 -0
  97. package/packages/server/dist/cli/index.js +6 -0
  98. package/packages/server/dist/cli/main.d.ts +2 -0
  99. package/packages/server/dist/cli/main.js +9 -0
  100. package/packages/server/dist/cli/run-bridge-server-cli.d.ts +54 -0
  101. package/packages/server/dist/cli/run-bridge-server-cli.js +371 -0
  102. package/packages/server/dist/client/bridge-api-client.d.ts +61 -0
  103. package/packages/server/dist/client/bridge-api-client.js +267 -0
  104. package/packages/server/dist/client/index.d.ts +11 -0
  105. package/packages/server/dist/client/index.js +11 -0
  106. package/packages/server/dist/config/bridge-server-config.d.ts +52 -0
  107. package/packages/server/dist/config/bridge-server-config.js +118 -0
  108. package/packages/server/dist/config/index.d.ts +20 -0
  109. package/packages/server/dist/config/index.js +8 -0
  110. package/packages/server/dist/http/bridge-api-route-context.d.ts +14 -0
  111. package/packages/server/dist/http/bridge-api-route-context.js +1 -0
  112. package/packages/server/dist/http/create-bridge-api-server.d.ts +72 -0
  113. package/packages/server/dist/http/create-bridge-api-server.js +225 -0
  114. package/packages/server/dist/http/index.d.ts +5 -0
  115. package/packages/server/dist/http/index.js +5 -0
  116. package/packages/server/dist/http/parse-request.d.ts +6 -0
  117. package/packages/server/dist/http/parse-request.js +27 -0
  118. package/packages/server/dist/http/register-bridge-api-routes.d.ts +7 -0
  119. package/packages/server/dist/http/register-bridge-api-routes.js +17 -0
  120. package/packages/server/dist/http/routes/admin-routes.d.ts +7 -0
  121. package/packages/server/dist/http/routes/admin-routes.js +135 -0
  122. package/packages/server/dist/http/routes/chat-completions-route.d.ts +7 -0
  123. package/packages/server/dist/http/routes/chat-completions-route.js +49 -0
  124. package/packages/server/dist/http/routes/health-routes.d.ts +6 -0
  125. package/packages/server/dist/http/routes/health-routes.js +7 -0
  126. package/packages/server/dist/http/routes/message-routes.d.ts +7 -0
  127. package/packages/server/dist/http/routes/message-routes.js +7 -0
  128. package/packages/server/dist/index.d.ts +85 -0
  129. package/packages/server/dist/index.js +28 -0
  130. package/packages/server/dist/security/bridge-auth.d.ts +9 -0
  131. package/packages/server/dist/security/bridge-auth.js +41 -0
  132. package/packages/server/dist/security/cors-policy.d.ts +5 -0
  133. package/packages/server/dist/security/cors-policy.js +34 -0
  134. package/packages/server/dist/security/index.d.ts +16 -0
  135. package/packages/server/dist/security/index.js +12 -0
  136. package/packages/server/dist/security/redact-sensitive-values.d.ts +19 -0
  137. package/packages/server/dist/security/redact-sensitive-values.js +67 -0
  138. package/packages/server/dist/shared/api-schema.d.ts +133 -0
  139. package/packages/server/dist/shared/api-schema.js +1 -0
  140. package/packages/server/dist/shared/bridge-api-error.d.ts +17 -0
  141. package/packages/server/dist/shared/bridge-api-error.js +19 -0
  142. package/packages/server/dist/shared/index.d.ts +7 -0
  143. package/packages/server/dist/shared/index.js +7 -0
  144. package/packages/server/dist/shared/output.d.ts +5 -0
  145. package/packages/server/dist/shared/output.js +14 -0
@@ -0,0 +1,1527 @@
1
+ import { z } from "zod";
2
+ import { bridgeApiErrorModule } from "../../shared/bridge-api-error.js";
3
+ import { providerStoreModule } from "./provider-store.js";
4
+ const { createProviderRequestSchema, providerDeleteResponseSchema, providerSchema } = providerStoreModule;
5
+ const { BridgeApiError } = bridgeApiErrorModule;
6
+ const nonEmptyString = (field) => z.string().trim().min(1, `${field} is required.`);
7
+ const looseObjectSchema = z.object({}).catchall(z.unknown());
8
+ const sessionPackageLifecycleStatusSchema = z.enum(["active", "expired", "revoked", "invalid"]);
9
+ const transportFamilySchema = z.enum(["http-sse", "http-json", "http-connect"]);
10
+ const transportPackageSchema = z
11
+ .object({
12
+ family: transportFamilySchema,
13
+ prompt: looseObjectSchema.optional(),
14
+ binding: looseObjectSchema.optional(),
15
+ session: looseObjectSchema.optional(),
16
+ request: looseObjectSchema.optional(),
17
+ response: looseObjectSchema.optional(),
18
+ seedBinding: looseObjectSchema.optional(),
19
+ bootstrap: looseObjectSchema.optional(),
20
+ preflight: looseObjectSchema.optional()
21
+ })
22
+ .strict();
23
+ const integrationPackageSchema = z
24
+ .object({
25
+ label: nonEmptyString("label").optional(),
26
+ enabled: z.boolean().optional(),
27
+ models: z.array(nonEmptyString("model")).optional(),
28
+ defaultModel: nonEmptyString("defaultModel").optional()
29
+ })
30
+ .strict();
31
+ const sessionPackageSchema = z
32
+ .object({
33
+ schemaVersion: z.number().int().min(1).optional(),
34
+ source: nonEmptyString("source"),
35
+ capturedAt: z.string().datetime({ offset: true }),
36
+ origin: z.string().url(),
37
+ cookies: z.array(looseObjectSchema).default([]),
38
+ localStorage: looseObjectSchema.default({}),
39
+ sessionStorage: looseObjectSchema.default({}),
40
+ headers: looseObjectSchema.default({}),
41
+ metadata: looseObjectSchema.default({}),
42
+ integration: integrationPackageSchema.optional(),
43
+ transport: transportPackageSchema.optional()
44
+ })
45
+ .strict();
46
+ const sessionPackageStatusResponseSchema = z
47
+ .object({
48
+ ok: z.literal(true),
49
+ providerId: nonEmptyString("providerId"),
50
+ hasSessionPackage: z.boolean(),
51
+ source: nonEmptyString("source").optional(),
52
+ capturedAt: z.string().datetime({ offset: true }).optional(),
53
+ origin: z.string().url().optional()
54
+ })
55
+ .strict();
56
+ const sessionPackageDeleteResponseSchema = z
57
+ .object({
58
+ ok: z.literal(true),
59
+ providerId: nonEmptyString("providerId")
60
+ })
61
+ .strict();
62
+ const sessionPackageMetadataSchema = z
63
+ .object({
64
+ handle: nonEmptyString("handle"),
65
+ providerId: nonEmptyString("providerId"),
66
+ source: nonEmptyString("source").optional(),
67
+ capturedAt: z.string().datetime({ offset: true }).optional(),
68
+ origin: z.string().url().optional(),
69
+ hasSessionPackage: z.boolean(),
70
+ createdAt: z.string().datetime({ offset: true }),
71
+ lastUsedAt: z.string().datetime({ offset: true }).optional(),
72
+ lastVerifiedAt: z.string().datetime({ offset: true }).optional(),
73
+ idleExpiresAt: z.string().datetime({ offset: true }).optional(),
74
+ absoluteExpiresAt: z.string().datetime({ offset: true }).optional(),
75
+ status: sessionPackageLifecycleStatusSchema,
76
+ version: z.number().int().min(1)
77
+ })
78
+ .strict();
79
+ const installedProviderPackageSchema = z
80
+ .object({
81
+ provider: providerSchema,
82
+ session: sessionPackageSchema.nullable()
83
+ })
84
+ .strict();
85
+ function createInMemorySessionPackageStore() {
86
+ const packages = new Map();
87
+ const metadata = new Map();
88
+ const store = {
89
+ listProviders() {
90
+ return [...packages.values()]
91
+ .map((entry) => cloneProvider(entry.provider))
92
+ .sort((left, right) => left.id.localeCompare(right.id));
93
+ },
94
+ getProvider(providerId) {
95
+ const stored = packages.get(providerId);
96
+ return stored ? cloneProvider(stored.provider) : null;
97
+ },
98
+ createProvider(input) {
99
+ if (packages.has(input.id)) {
100
+ throw new BridgeApiError({
101
+ statusCode: 409,
102
+ code: "provider_exists",
103
+ message: `Provider '${input.id}' already exists.`
104
+ });
105
+ }
106
+ const timestamp = createTimestamp();
107
+ const provider = providerSchema.parse({
108
+ ...createProviderRequestSchema.parse(input),
109
+ createdAt: timestamp,
110
+ updatedAt: timestamp
111
+ });
112
+ packages.set(provider.id, installedProviderPackageSchema.parse({
113
+ provider,
114
+ session: null
115
+ }));
116
+ metadata.set(provider.id, buildSessionPackageMetadata(provider.id, null, {
117
+ existing: metadata.get(provider.id) ?? null,
118
+ now: timestamp
119
+ }));
120
+ return cloneProvider(provider);
121
+ },
122
+ updateProvider(providerId, patch) {
123
+ const stored = packages.get(providerId);
124
+ if (!stored) {
125
+ throw missingProviderError(providerId);
126
+ }
127
+ const nextProvider = providerSchema.parse({
128
+ ...stored.provider,
129
+ ...patch,
130
+ config: patch.config === undefined ? stored.provider.config : cloneConfig(patch.config),
131
+ updatedAt: createTimestamp(stored.provider.updatedAt)
132
+ });
133
+ const nextPackage = installedProviderPackageSchema.parse({
134
+ provider: nextProvider,
135
+ session: stored.session ? cloneSessionPackage(stored.session) : null
136
+ });
137
+ packages.set(providerId, nextPackage);
138
+ metadata.set(providerId, buildSessionPackageMetadata(providerId, nextPackage.session, {
139
+ existing: metadata.get(providerId) ?? null,
140
+ now: nextProvider.updatedAt
141
+ }));
142
+ return cloneProvider(nextProvider);
143
+ },
144
+ get(providerId) {
145
+ const stored = packages.get(providerId)?.session;
146
+ return stored ? cloneSessionPackage(stored) : null;
147
+ },
148
+ getStatus(providerId) {
149
+ const stored = metadata.get(providerId);
150
+ return stored ? cloneSessionPackageMetadata(stored) : null;
151
+ },
152
+ put(providerId, value) {
153
+ const normalized = cloneSessionPackage(value);
154
+ const existing = packages.get(providerId);
155
+ const now = createTimestamp(existing?.provider.updatedAt);
156
+ const provider = inferProviderFromSessionPackage({
157
+ providerId,
158
+ value: normalized,
159
+ existing: existing?.provider ?? null,
160
+ now
161
+ });
162
+ packages.set(providerId, installedProviderPackageSchema.parse({
163
+ provider,
164
+ session: normalized
165
+ }));
166
+ const nextMetadata = buildSessionPackageMetadata(providerId, normalized, {
167
+ existing: metadata.get(providerId) ?? null,
168
+ now
169
+ });
170
+ metadata.set(providerId, nextMetadata);
171
+ return cloneSessionPackageMetadata(nextMetadata);
172
+ },
173
+ delete(providerId) {
174
+ if (!packages.delete(providerId)) {
175
+ throw missingProviderError(providerId);
176
+ }
177
+ metadata.delete(providerId);
178
+ return sessionPackageDeleteResponseSchema.parse({
179
+ ok: true,
180
+ providerId
181
+ });
182
+ },
183
+ deleteSession(providerId) {
184
+ const stored = packages.get(providerId);
185
+ if (!stored) {
186
+ throw missingProviderError(providerId);
187
+ }
188
+ packages.set(providerId, installedProviderPackageSchema.parse({
189
+ provider: cloneProvider(stored.provider),
190
+ session: null
191
+ }));
192
+ const now = createTimestamp(stored.provider.updatedAt);
193
+ metadata.set(providerId, buildSessionPackageMetadata(providerId, null, {
194
+ existing: metadata.get(providerId) ?? null,
195
+ now
196
+ }));
197
+ return sessionPackageDeleteResponseSchema.parse({
198
+ ok: true,
199
+ providerId
200
+ });
201
+ },
202
+ listPackages() {
203
+ return [...packages.values()]
204
+ .map(cloneInstalledProviderPackage)
205
+ .sort((left, right) => left.provider.id.localeCompare(right.provider.id));
206
+ },
207
+ getPackage(providerId) {
208
+ const stored = packages.get(providerId);
209
+ return stored ? cloneInstalledProviderPackage(stored) : null;
210
+ }
211
+ };
212
+ return store;
213
+ }
214
+ function buildSessionPackageStatus(providerId, stored) {
215
+ return sessionPackageStatusResponseSchema.parse({
216
+ ok: true,
217
+ providerId,
218
+ hasSessionPackage: Boolean(stored?.hasSessionPackage),
219
+ ...(stored?.hasSessionPackage
220
+ ? {
221
+ source: stored.source,
222
+ capturedAt: stored.capturedAt,
223
+ origin: stored.origin
224
+ }
225
+ : {})
226
+ });
227
+ }
228
+ function cloneProvider(provider) {
229
+ return providerSchema.parse({
230
+ ...provider,
231
+ config: cloneConfig(provider.config)
232
+ });
233
+ }
234
+ function cloneConfig(config) {
235
+ return structuredClone(config);
236
+ }
237
+ function cloneSessionPackage(value) {
238
+ return sessionPackageSchema.parse(structuredClone(value));
239
+ }
240
+ function cloneSessionPackageMetadata(value) {
241
+ return sessionPackageMetadataSchema.parse(structuredClone(value));
242
+ }
243
+ function cloneInstalledProviderPackage(value) {
244
+ return installedProviderPackageSchema.parse(structuredClone(value));
245
+ }
246
+ function buildSessionPackageMetadata(providerId, session, input) {
247
+ return sessionPackageMetadataSchema.parse({
248
+ handle: input.existing?.handle ?? input.handle ?? `memory:${providerId}`,
249
+ providerId,
250
+ source: session?.source,
251
+ capturedAt: session?.capturedAt,
252
+ origin: session?.origin,
253
+ hasSessionPackage: Boolean(session),
254
+ createdAt: input.existing?.createdAt ?? input.now,
255
+ lastUsedAt: session ? input.now : input.existing?.lastUsedAt,
256
+ lastVerifiedAt: readLifecycleIsoString(session?.metadata, "lastVerifiedAt") ?? input.existing?.lastVerifiedAt,
257
+ idleExpiresAt: readLifecycleIsoString(session?.metadata, "idleExpiresAt"),
258
+ absoluteExpiresAt: readLifecycleIsoString(session?.metadata, "absoluteExpiresAt"),
259
+ status: "active",
260
+ version: 1
261
+ });
262
+ }
263
+ function inferProviderFromSessionPackage(input) {
264
+ const embeddedTransport = readEmbeddedTransport(input.value);
265
+ const capturedTransport = inferTransportFromRequestCapture(input.value);
266
+ const inferredTransport = embeddedTransport ??
267
+ (shouldRefreshTransportFromCapture(input.existing, capturedTransport)
268
+ ? capturedTransport
269
+ : null);
270
+ const explicitModels = readExplicitModelIds(input.value);
271
+ const inferredModels = inferModelIdsFromCapture(input.value);
272
+ const existingModels = readConfiguredModelIds(input.existing?.config);
273
+ const nextModels = explicitModels ?? mergeModelIds(existingModels, inferredModels);
274
+ return providerSchema.parse({
275
+ id: input.providerId,
276
+ kind: inferredTransport?.family ?? input.existing?.kind ?? "http-json",
277
+ label: readLabel(input.value, input.providerId) ?? input.existing?.label ?? input.providerId,
278
+ enabled: input.value.integration?.enabled ?? input.existing?.enabled ?? true,
279
+ config: {
280
+ ...(input.existing?.config ?? {}),
281
+ ...(inferredTransport ? { transport: inferredTransport.config } : {}),
282
+ models: nextModels
283
+ },
284
+ createdAt: input.existing?.createdAt ?? input.now,
285
+ updatedAt: input.now
286
+ });
287
+ }
288
+ function shouldRefreshTransportFromCapture(existing, capturedTransport) {
289
+ if (!capturedTransport) {
290
+ return false;
291
+ }
292
+ if (!existing) {
293
+ return true;
294
+ }
295
+ const existingTransport = readConfiguredTransport(existing.config);
296
+ if (!existingTransport) {
297
+ return true;
298
+ }
299
+ const existingRequest = typeof existingTransport.request === "object" && existingTransport.request !== null
300
+ ? existingTransport.request
301
+ : null;
302
+ const capturedRequest = typeof capturedTransport.config.request === "object" &&
303
+ capturedTransport.config.request !== null
304
+ ? capturedTransport.config.request
305
+ : null;
306
+ const existingUrl = typeof existingRequest?.url === "string" ? existingRequest.url.trim() : "";
307
+ const capturedUrl = typeof capturedRequest?.url === "string" ? capturedRequest.url.trim() : "";
308
+ if (existing.kind !== capturedTransport.family) {
309
+ return true;
310
+ }
311
+ if (existingUrl && capturedUrl && existingUrl === capturedUrl) {
312
+ return true;
313
+ }
314
+ return false;
315
+ }
316
+ function readEmbeddedTransport(value) {
317
+ if (!value.transport) {
318
+ return null;
319
+ }
320
+ const parsed = transportPackageSchema.safeParse(value.transport);
321
+ if (!parsed.success) {
322
+ return null;
323
+ }
324
+ const { family, ...config } = parsed.data;
325
+ return {
326
+ family,
327
+ config
328
+ };
329
+ }
330
+ function inferTransportFromRequestCapture(value) {
331
+ const selectedRequest = readSelectedRequest(value.metadata);
332
+ if (!selectedRequest?.url || !selectedRequest?.method) {
333
+ return null;
334
+ }
335
+ const zaiConversationTransport = inferZaiConversationTransport(selectedRequest, value);
336
+ if (zaiConversationTransport) {
337
+ return zaiConversationTransport;
338
+ }
339
+ const qwenConversationTransport = inferQwenConversationTransport(selectedRequest, value);
340
+ if (qwenConversationTransport) {
341
+ return qwenConversationTransport;
342
+ }
343
+ const deepSeekConversationTransport = inferDeepSeekConversationTransport(selectedRequest, value);
344
+ if (deepSeekConversationTransport) {
345
+ return deepSeekConversationTransport;
346
+ }
347
+ const openAiConversationTransport = inferOpenAiConversationTransport(selectedRequest, value);
348
+ if (openAiConversationTransport) {
349
+ return openAiConversationTransport;
350
+ }
351
+ const family = readTransportFamily(selectedRequest);
352
+ const requestBody = readTemplateRequestBody(selectedRequest);
353
+ return {
354
+ family,
355
+ config: {
356
+ prompt: {
357
+ mode: "flatten"
358
+ },
359
+ binding: {
360
+ firstTurn: "empty"
361
+ },
362
+ session: {
363
+ requireCookie: Array.isArray(value.cookies) && value.cookies.length > 0,
364
+ requireBearerToken: hasBearerAuthorization(value.headers),
365
+ requireUserAgent: hasHeader(value.headers, "user-agent"),
366
+ includeExtraHeaders: true
367
+ },
368
+ request: {
369
+ method: String(selectedRequest.method).toUpperCase(),
370
+ url: String(selectedRequest.url),
371
+ headers: {},
372
+ ...(requestBody === undefined ? {} : { body: requestBody })
373
+ },
374
+ response: {
375
+ contentPaths: family === "http-sse"
376
+ ? DEFAULT_SSE_CONTENT_PATHS
377
+ : family === "http-connect"
378
+ ? DEFAULT_CONNECT_CONTENT_PATHS
379
+ : DEFAULT_JSON_CONTENT_PATHS,
380
+ responseIdPaths: DEFAULT_RESPONSE_ID_PATHS,
381
+ conversationIdPaths: DEFAULT_CONVERSATION_ID_PATHS,
382
+ trimLeadingAssistantBlock: true
383
+ }
384
+ }
385
+ };
386
+ }
387
+ function inferQwenConversationTransport(selectedRequest, value) {
388
+ const requestUrl = typeof selectedRequest.url === "string" ? selectedRequest.url.trim() : "";
389
+ if (!isQwenConversationRequestUrl(requestUrl)) {
390
+ return null;
391
+ }
392
+ const requestBody = readTemplateRequestBody(selectedRequest);
393
+ const capturedBootstrapHeaders = readCapturedRequestHeaders(value.metadata, isQwenBootstrapRequestUrl);
394
+ const bootstrapHeaders = mergeHeaderRecords({
395
+ Accept: "application/json",
396
+ "Content-Type": "application/json",
397
+ Origin: "https://chat.qwen.ai",
398
+ Referer: "https://chat.qwen.ai/"
399
+ }, capturedBootstrapHeaders);
400
+ return {
401
+ family: "http-sse",
402
+ config: {
403
+ prompt: {
404
+ mode: "flatten"
405
+ },
406
+ binding: {
407
+ firstTurn: "seed"
408
+ },
409
+ session: {
410
+ requireCookie: Array.isArray(value.cookies) && value.cookies.length > 0,
411
+ requireBearerToken: hasBearerAuthorization(value.headers),
412
+ requireUserAgent: hasHeader(value.headers, "user-agent"),
413
+ includeExtraHeaders: true
414
+ },
415
+ request: {
416
+ method: String(selectedRequest.method).toUpperCase(),
417
+ url: "https://chat.qwen.ai/api/v2/chat/completions?chat_id={{conversationId}}",
418
+ headers: {},
419
+ ...(requestBody === undefined ? {} : { body: requestBody })
420
+ },
421
+ response: {
422
+ contentPaths: DEFAULT_SSE_CONTENT_PATHS,
423
+ responseIdPaths: DEFAULT_RESPONSE_ID_PATHS,
424
+ conversationIdPaths: ["response.created.chat_id", ...DEFAULT_CONVERSATION_ID_PATHS],
425
+ eventFilters: [
426
+ {
427
+ path: "choices.0.delta.phase",
428
+ equals: "answer"
429
+ }
430
+ ],
431
+ trimLeadingAssistantBlock: true
432
+ },
433
+ bootstrap: {
434
+ request: {
435
+ method: "POST",
436
+ url: "https://chat.qwen.ai/api/v2/chats/new",
437
+ headers: bootstrapHeaders,
438
+ body: buildQwenBootstrapRequestBody(selectedRequest)
439
+ },
440
+ conversationIdPath: "data.id"
441
+ }
442
+ }
443
+ };
444
+ }
445
+ function inferDeepSeekConversationTransport(selectedRequest, value) {
446
+ const requestUrl = typeof selectedRequest.url === "string" ? selectedRequest.url.trim() : "";
447
+ if (!isDeepSeekConversationRequestUrl(requestUrl)) {
448
+ return null;
449
+ }
450
+ const requestBody = readTemplateRequestBody(selectedRequest);
451
+ const capturedCompletionHeaders = omitHeaders(filterCapturedRequestHeaders(readSelectedRequestHeaders(selectedRequest)), ["x-ds-pow-response"]);
452
+ const capturedBootstrapHeaders = omitHeaders(readCapturedRequestHeaders(value.metadata, isDeepSeekBootstrapRequestUrl), ["x-ds-pow-response"]);
453
+ const capturedPreflightHeaders = omitHeaders(readCapturedRequestHeaders(value.metadata, isDeepSeekPowChallengeRequestUrl), ["x-ds-pow-response"]);
454
+ const requestHeaders = mergeHeaderRecords({
455
+ Accept: "*/*",
456
+ "Content-Type": "application/json",
457
+ Origin: "https://chat.deepseek.com",
458
+ Referer: "https://chat.deepseek.com/"
459
+ }, capturedCompletionHeaders);
460
+ const bootstrapHeaders = mergeHeaderRecords({
461
+ Accept: "*/*",
462
+ "Content-Type": "application/json",
463
+ Origin: "https://chat.deepseek.com",
464
+ Referer: "https://chat.deepseek.com/"
465
+ }, capturedBootstrapHeaders);
466
+ const preflightHeaders = mergeHeaderRecords({
467
+ Accept: "*/*",
468
+ "Content-Type": "application/json",
469
+ Origin: "https://chat.deepseek.com",
470
+ Referer: "https://chat.deepseek.com/"
471
+ }, capturedPreflightHeaders);
472
+ return {
473
+ family: "http-sse",
474
+ config: {
475
+ prompt: {
476
+ mode: "flatten"
477
+ },
478
+ binding: {
479
+ firstTurn: "empty"
480
+ },
481
+ session: {
482
+ requireCookie: Array.isArray(value.cookies) && value.cookies.length > 0,
483
+ requireBearerToken: hasBearerAuthorization(value.headers),
484
+ requireUserAgent: hasHeader(value.headers, "user-agent"),
485
+ includeExtraHeaders: false
486
+ },
487
+ request: {
488
+ method: "POST",
489
+ url: "https://chat.deepseek.com/api/v0/chat/completion",
490
+ headers: requestHeaders,
491
+ ...(requestBody === undefined ? {} : { body: requestBody })
492
+ },
493
+ response: {
494
+ contentPaths: ["__bridge__.deepseek.response"],
495
+ responseIdPaths: [
496
+ "response_message_id",
497
+ "chat_message.message_id",
498
+ "data.biz_data.message_id",
499
+ ...DEFAULT_RESPONSE_ID_PATHS
500
+ ],
501
+ conversationIdPaths: [
502
+ "chat_message.chat_session_id",
503
+ "data.biz_data.chat_session.id",
504
+ "data.biz_data.chat_session_id",
505
+ ...DEFAULT_CONVERSATION_ID_PATHS
506
+ ],
507
+ trimLeadingAssistantBlock: true
508
+ },
509
+ bootstrap: {
510
+ request: {
511
+ method: "POST",
512
+ url: "https://chat.deepseek.com/api/v0/chat_session/create",
513
+ headers: bootstrapHeaders,
514
+ body: {}
515
+ },
516
+ conversationIdPath: "data.biz_data.chat_session.id"
517
+ },
518
+ preflight: {
519
+ request: {
520
+ method: "POST",
521
+ url: "https://chat.deepseek.com/api/v0/chat/create_pow_challenge",
522
+ headers: preflightHeaders,
523
+ body: {
524
+ target_path: "/api/v0/chat/completion"
525
+ }
526
+ },
527
+ proofOfWork: {
528
+ kind: "sha3-wasm-salt-expiry",
529
+ headerName: "x-ds-pow-response",
530
+ wasmUrl: "https://fe-static.deepseek.com/chat/static/sha3_wasm_bg.7b9ca65ddd.wasm",
531
+ algorithmPath: "data.biz_data.challenge.algorithm",
532
+ challengePath: "data.biz_data.challenge.challenge",
533
+ saltPath: "data.biz_data.challenge.salt",
534
+ signaturePath: "data.biz_data.challenge.signature",
535
+ difficultyPath: "data.biz_data.challenge.difficulty",
536
+ expireAtPath: "data.biz_data.challenge.expire_at",
537
+ targetPathPath: "data.biz_data.challenge.target_path"
538
+ }
539
+ }
540
+ }
541
+ };
542
+ }
543
+ function inferZaiConversationTransport(selectedRequest, value) {
544
+ const requestUrl = typeof selectedRequest.url === "string" ? selectedRequest.url.trim() : "";
545
+ if (!isZaiConversationRequestUrl(requestUrl)) {
546
+ return null;
547
+ }
548
+ const capturedBootstrapHeaders = readCapturedRequestHeaders(value.metadata, isZaiBootstrapRequestUrl);
549
+ const bootstrapHeaders = mergeHeaderRecords({
550
+ Accept: "application/json",
551
+ "Accept-Language": "en-US",
552
+ Connection: "keep-alive",
553
+ "Content-Type": "application/json",
554
+ Origin: "https://chat.z.ai",
555
+ "Sec-Fetch-Dest": "empty",
556
+ "Sec-Fetch-Mode": "cors",
557
+ "Sec-Fetch-Site": "same-origin"
558
+ }, capturedBootstrapHeaders);
559
+ return {
560
+ family: "http-sse",
561
+ config: {
562
+ prompt: {
563
+ mode: "latest_user"
564
+ },
565
+ binding: {
566
+ firstTurn: "seed"
567
+ },
568
+ session: {
569
+ requireCookie: Array.isArray(value.cookies) && value.cookies.length > 0,
570
+ requireBearerToken: hasBearerAuthorization(value.headers),
571
+ requireUserAgent: hasHeader(value.headers, "user-agent"),
572
+ includeExtraHeaders: true
573
+ },
574
+ request: {
575
+ method: "POST",
576
+ url: "https://chat.z.ai/api/v2/chat/completions",
577
+ headers: {
578
+ Accept: "*/*",
579
+ "Accept-Language": "en-US",
580
+ Connection: "keep-alive",
581
+ "Content-Type": "application/json",
582
+ Origin: "https://chat.z.ai",
583
+ "Sec-Fetch-Dest": "empty",
584
+ "Sec-Fetch-Mode": "cors",
585
+ "Sec-Fetch-Site": "same-origin",
586
+ "X-FE-Version": "prod-fe-1.1.2"
587
+ },
588
+ signing: {
589
+ kind: "z-ai-v1"
590
+ },
591
+ body: {
592
+ stream: true,
593
+ model: "{{modelId}}",
594
+ messages: [
595
+ {
596
+ role: "user",
597
+ content: "{{prompt}}"
598
+ }
599
+ ],
600
+ signature_prompt: "{{prompt}}",
601
+ params: {},
602
+ extra: {},
603
+ features: {
604
+ image_generation: false,
605
+ web_search: false,
606
+ auto_web_search: false,
607
+ preview_mode: true,
608
+ flags: [],
609
+ vlm_tools_enable: false,
610
+ vlm_web_search_enable: false,
611
+ vlm_website_mode: false,
612
+ enable_thinking: "{{thinkingEnabledOrTrue}}"
613
+ },
614
+ variables: {
615
+ "{{USER_NAME}}": "{{userName}}",
616
+ "{{USER_LOCATION}}": "Unknown",
617
+ "{{CURRENT_DATETIME}}": "{{currentDateTime}}",
618
+ "{{CURRENT_DATE}}": "{{currentDate}}",
619
+ "{{CURRENT_TIME}}": "{{currentTime}}",
620
+ "{{CURRENT_WEEKDAY}}": "{{currentWeekday}}",
621
+ "{{CURRENT_TIMEZONE}}": "{{currentTimezone}}",
622
+ "{{USER_LANGUAGE}}": "{{userLanguage}}"
623
+ },
624
+ chat_id: "{{conversationId}}",
625
+ id: "{{assistantMessageId}}",
626
+ current_user_message_id: "{{userMessageId}}",
627
+ current_user_message_parent_id: "{{parentIdOrNull}}",
628
+ background_tasks: {
629
+ title_generation: true,
630
+ tags_generation: true
631
+ }
632
+ }
633
+ },
634
+ response: {
635
+ contentPaths: ["data.delta_content"],
636
+ eventFilters: [
637
+ {
638
+ path: "data.phase",
639
+ equals: "answer"
640
+ }
641
+ ],
642
+ fallbackResponseId: "assistantMessageId",
643
+ trimLeadingAssistantBlock: false
644
+ },
645
+ bootstrap: {
646
+ request: {
647
+ method: "POST",
648
+ url: "https://chat.z.ai/api/v1/chats/new",
649
+ headers: bootstrapHeaders,
650
+ body: {
651
+ chat: {
652
+ id: "",
653
+ title: "New Chat",
654
+ models: ["{{modelId}}"],
655
+ params: {},
656
+ history: {
657
+ messages: {
658
+ "bootstrap-user": {
659
+ id: "bootstrap-user",
660
+ parentId: null,
661
+ childrenIds: [],
662
+ role: "user",
663
+ content: "{{prompt}}",
664
+ timestamp: "{{unixTimestampSec}}",
665
+ models: ["{{modelId}}"]
666
+ }
667
+ },
668
+ currentId: "bootstrap-user"
669
+ },
670
+ tags: [],
671
+ flags: [],
672
+ features: [
673
+ { type: "mcp", server: "vibe-coding", status: "hidden" },
674
+ { type: "mcp", server: "ppt-maker", status: "hidden" },
675
+ { type: "mcp", server: "image-search", status: "hidden" },
676
+ { type: "mcp", server: "deep-research", status: "hidden" },
677
+ { type: "tool_selector", server: "tool_selector", status: "hidden" }
678
+ ],
679
+ mcp_servers: [],
680
+ enable_thinking: "{{thinkingEnabledOrTrue}}",
681
+ auto_web_search: false,
682
+ message_version: 1,
683
+ extra: {},
684
+ timestamp: "{{unixTimestampMs}}",
685
+ type: "default"
686
+ }
687
+ }
688
+ },
689
+ conversationIdPath: "id"
690
+ }
691
+ }
692
+ };
693
+ }
694
+ function inferOpenAiConversationTransport(selectedRequest, value) {
695
+ const requestUrl = typeof selectedRequest.url === "string" ? selectedRequest.url.trim() : "";
696
+ if (!isOpenAiConversationRequestUrl(requestUrl)) {
697
+ return null;
698
+ }
699
+ return {
700
+ family: "http-sse",
701
+ config: {
702
+ prompt: {
703
+ mode: "auto_join"
704
+ },
705
+ binding: {
706
+ firstTurn: "empty"
707
+ },
708
+ session: {
709
+ requireCookie: Array.isArray(value.cookies) && value.cookies.length > 0,
710
+ requireBearerToken: hasBearerAuthorization(value.headers),
711
+ requireUserAgent: hasHeader(value.headers, "user-agent"),
712
+ includeExtraHeaders: true
713
+ },
714
+ request: {
715
+ method: String(selectedRequest.method).toUpperCase(),
716
+ url: requestUrl,
717
+ headers: {},
718
+ body: buildOpenAiConversationRequestBody(readRequestBodyObject(selectedRequest))
719
+ },
720
+ response: {
721
+ contentPaths: ["v.message.content.parts.*", "message.content.parts.*"],
722
+ responseIdPaths: ["v.message.id", "message.id"],
723
+ conversationIdPaths: ["conversation_id", "v.conversation_id"],
724
+ allowVisibleTextFinal: true,
725
+ trimLeadingAssistantBlock: false
726
+ }
727
+ }
728
+ };
729
+ }
730
+ function readCapturedRequestHeaders(metadata, matcher) {
731
+ const requests = readCapturedRequests(metadata);
732
+ for (let index = requests.length - 1; index >= 0; index -= 1) {
733
+ const request = requests[index];
734
+ const url = typeof request.url === "string" ? request.url.trim() : "";
735
+ if (!url || !matcher(url)) {
736
+ continue;
737
+ }
738
+ return filterCapturedRequestHeaders(readSelectedRequestHeaders(request));
739
+ }
740
+ return {};
741
+ }
742
+ function omitHeaders(source, names) {
743
+ if (Object.keys(source).length === 0 || names.length === 0) {
744
+ return source;
745
+ }
746
+ const excluded = new Set(names.map((name) => name.toLowerCase()));
747
+ return Object.fromEntries(Object.entries(source).filter(([key]) => !excluded.has(key.toLowerCase())));
748
+ }
749
+ function readCapturedRequests(metadata) {
750
+ const capture = metadata.requestCapture;
751
+ if (!capture || typeof capture !== "object" || Array.isArray(capture)) {
752
+ return [];
753
+ }
754
+ const requests = capture.requests;
755
+ return Array.isArray(requests)
756
+ ? requests.filter((entry) => typeof entry === "object" && entry !== null && !Array.isArray(entry))
757
+ : [];
758
+ }
759
+ function filterCapturedRequestHeaders(headers) {
760
+ if (!headers) {
761
+ return {};
762
+ }
763
+ return Object.fromEntries(Object.entries(headers).flatMap(([key, value]) => {
764
+ if (typeof value !== "string" || !value.trim()) {
765
+ return [];
766
+ }
767
+ const normalized = key.toLowerCase();
768
+ if (normalized === "cookie" ||
769
+ normalized === "authorization" ||
770
+ normalized === "user-agent" ||
771
+ normalized === "content-length") {
772
+ return [];
773
+ }
774
+ return [[key, value.trim()]];
775
+ }));
776
+ }
777
+ function mergeHeaderRecords(...sources) {
778
+ const merged = {};
779
+ const canonicalKeys = new Map();
780
+ for (const source of sources) {
781
+ for (const [key, value] of Object.entries(source)) {
782
+ if (typeof value !== "string" || !value.trim()) {
783
+ continue;
784
+ }
785
+ const normalized = key.toLowerCase();
786
+ const existingKey = canonicalKeys.get(normalized);
787
+ if (existingKey && existingKey !== key) {
788
+ delete merged[existingKey];
789
+ }
790
+ canonicalKeys.set(normalized, key);
791
+ merged[key] = value.trim();
792
+ }
793
+ }
794
+ return merged;
795
+ }
796
+ function isZaiConversationRequestUrl(requestUrl) {
797
+ if (!requestUrl) {
798
+ return false;
799
+ }
800
+ try {
801
+ const url = new URL(requestUrl);
802
+ return (url.hostname.toLowerCase() === "chat.z.ai" &&
803
+ /^\/api\/v2\/chat\/completions\/?$/i.test(url.pathname));
804
+ }
805
+ catch {
806
+ return false;
807
+ }
808
+ }
809
+ function isOpenAiConversationRequestUrl(requestUrl) {
810
+ if (!requestUrl) {
811
+ return false;
812
+ }
813
+ try {
814
+ const url = new URL(requestUrl);
815
+ const normalizedHost = url.hostname.toLowerCase();
816
+ const normalizedPath = url.pathname.toLowerCase();
817
+ return ((normalizedHost === "chatgpt.com" || normalizedHost.endsWith(".chatgpt.com")) &&
818
+ /^\/backend-api(?:\/f)?\/conversation\/?$/.test(normalizedPath));
819
+ }
820
+ catch {
821
+ return false;
822
+ }
823
+ }
824
+ function isQwenConversationRequestUrl(requestUrl) {
825
+ if (!requestUrl) {
826
+ return false;
827
+ }
828
+ try {
829
+ const url = new URL(requestUrl);
830
+ const normalizedHost = url.hostname.toLowerCase();
831
+ const normalizedPath = url.pathname.toLowerCase();
832
+ return ((normalizedHost === "chat.qwen.ai" || normalizedHost.endsWith(".chat.qwen.ai")) &&
833
+ normalizedPath === "/api/v2/chat/completions");
834
+ }
835
+ catch {
836
+ return false;
837
+ }
838
+ }
839
+ function isQwenBootstrapRequestUrl(requestUrl) {
840
+ if (!requestUrl) {
841
+ return false;
842
+ }
843
+ try {
844
+ const url = new URL(requestUrl);
845
+ const normalizedHost = url.hostname.toLowerCase();
846
+ const normalizedPath = url.pathname.toLowerCase();
847
+ return ((normalizedHost === "chat.qwen.ai" || normalizedHost.endsWith(".chat.qwen.ai")) &&
848
+ normalizedPath === "/api/v2/chats/new");
849
+ }
850
+ catch {
851
+ return false;
852
+ }
853
+ }
854
+ function isDeepSeekConversationRequestUrl(requestUrl) {
855
+ if (!requestUrl) {
856
+ return false;
857
+ }
858
+ try {
859
+ const url = new URL(requestUrl);
860
+ const normalizedHost = url.hostname.toLowerCase();
861
+ const normalizedPath = url.pathname.toLowerCase();
862
+ return ((normalizedHost === "chat.deepseek.com" || normalizedHost.endsWith(".chat.deepseek.com")) &&
863
+ normalizedPath === "/api/v0/chat/completion");
864
+ }
865
+ catch {
866
+ return false;
867
+ }
868
+ }
869
+ function isDeepSeekBootstrapRequestUrl(requestUrl) {
870
+ if (!requestUrl) {
871
+ return false;
872
+ }
873
+ try {
874
+ const url = new URL(requestUrl);
875
+ const normalizedHost = url.hostname.toLowerCase();
876
+ const normalizedPath = url.pathname.toLowerCase();
877
+ return ((normalizedHost === "chat.deepseek.com" || normalizedHost.endsWith(".chat.deepseek.com")) &&
878
+ normalizedPath === "/api/v0/chat_session/create");
879
+ }
880
+ catch {
881
+ return false;
882
+ }
883
+ }
884
+ function isDeepSeekPowChallengeRequestUrl(requestUrl) {
885
+ if (!requestUrl) {
886
+ return false;
887
+ }
888
+ try {
889
+ const url = new URL(requestUrl);
890
+ const normalizedHost = url.hostname.toLowerCase();
891
+ const normalizedPath = url.pathname.toLowerCase();
892
+ return ((normalizedHost === "chat.deepseek.com" || normalizedHost.endsWith(".chat.deepseek.com")) &&
893
+ normalizedPath === "/api/v0/chat/create_pow_challenge");
894
+ }
895
+ catch {
896
+ return false;
897
+ }
898
+ }
899
+ function buildQwenBootstrapRequestBody(selectedRequest) {
900
+ const requestBody = readRequestBodyObject(selectedRequest);
901
+ const topLevelChatType = typeof requestBody?.chat_type === "string" && requestBody.chat_type.trim()
902
+ ? requestBody.chat_type.trim()
903
+ : "";
904
+ const topLevelChatMode = typeof requestBody?.chat_mode === "string" && requestBody.chat_mode.trim()
905
+ ? requestBody.chat_mode.trim()
906
+ : "";
907
+ const projectId = typeof requestBody?.project_id === "string" ? requestBody.project_id : "";
908
+ const firstMessage = Array.isArray(requestBody?.messages) &&
909
+ requestBody.messages.length > 0 &&
910
+ typeof requestBody.messages[0] === "object" &&
911
+ requestBody.messages[0] !== null
912
+ ? requestBody.messages[0]
913
+ : null;
914
+ const messageChatType = typeof firstMessage?.chat_type === "string" && firstMessage.chat_type.trim()
915
+ ? firstMessage.chat_type.trim()
916
+ : "";
917
+ const messageSubChatType = typeof firstMessage?.sub_chat_type === "string" && firstMessage.sub_chat_type.trim()
918
+ ? firstMessage.sub_chat_type.trim()
919
+ : "";
920
+ return {
921
+ title: "New Chat",
922
+ models: ["{{modelId}}"],
923
+ chat_mode: topLevelChatMode || "normal",
924
+ chat_type: topLevelChatType || messageChatType || messageSubChatType || "t2t",
925
+ timestamp: "{{unixTimestampMs}}",
926
+ project_id: projectId
927
+ };
928
+ }
929
+ function buildOpenAiConversationRequestBody(requestBody) {
930
+ const base = requestBody ? structuredClone(requestBody) : {};
931
+ const capturedMessage = Array.isArray(requestBody?.messages) &&
932
+ requestBody.messages.length > 0 &&
933
+ typeof requestBody.messages[0] === "object" &&
934
+ requestBody.messages[0] !== null
935
+ ? requestBody.messages[0]
936
+ : null;
937
+ const nextBody = {
938
+ ...base,
939
+ action: typeof requestBody?.action === "string" && requestBody.action.trim()
940
+ ? requestBody.action
941
+ : "next",
942
+ messages: [buildOpenAiConversationUserMessage(capturedMessage)],
943
+ parent_message_id: "{{parentIdOrClientCreatedRoot}}",
944
+ model: "{{modelId}}"
945
+ };
946
+ delete nextBody.conversation_id;
947
+ delete nextBody.conversationId;
948
+ return nextBody;
949
+ }
950
+ function buildOpenAiConversationUserMessage(capturedMessage) {
951
+ const base = capturedMessage ? structuredClone(capturedMessage) : {};
952
+ const author = capturedMessage?.author &&
953
+ typeof capturedMessage.author === "object" &&
954
+ !Array.isArray(capturedMessage.author)
955
+ ? structuredClone(capturedMessage.author)
956
+ : {};
957
+ const content = capturedMessage?.content &&
958
+ typeof capturedMessage.content === "object" &&
959
+ !Array.isArray(capturedMessage.content)
960
+ ? structuredClone(capturedMessage.content)
961
+ : {};
962
+ return {
963
+ ...base,
964
+ id: "{{messageId}}",
965
+ author: {
966
+ ...author,
967
+ role: "user"
968
+ },
969
+ create_time: "{{unixTimestampSec}}",
970
+ content: {
971
+ ...content,
972
+ content_type: typeof content.content_type === "string" && content.content_type.trim()
973
+ ? content.content_type
974
+ : "text",
975
+ parts: ["{{prompt}}"]
976
+ }
977
+ };
978
+ }
979
+ function readTemplateRequestBody(selectedRequest) {
980
+ const requestBodyJson = selectedRequest.requestBodyJson;
981
+ if (requestBodyJson && typeof requestBodyJson === "object" && !Array.isArray(requestBodyJson)) {
982
+ return templateRequestValue(requestBodyJson, {
983
+ parentKey: "",
984
+ parentRole: ""
985
+ });
986
+ }
987
+ const requestBodyText = typeof selectedRequest.requestBodyText === "string"
988
+ ? selectedRequest.requestBodyText.trim()
989
+ : "";
990
+ if (!requestBodyText) {
991
+ return undefined;
992
+ }
993
+ const contentType = readSelectedRequestContentType(selectedRequest);
994
+ if (isConnectJsonContentType(contentType)) {
995
+ const connectJson = decodeConnectJsonBody(requestBodyText);
996
+ if (connectJson && typeof connectJson === "object" && !Array.isArray(connectJson)) {
997
+ return templateRequestValue(connectJson, {
998
+ parentKey: "",
999
+ parentRole: ""
1000
+ });
1001
+ }
1002
+ }
1003
+ try {
1004
+ return templateRequestValue(JSON.parse(requestBodyText), {
1005
+ parentKey: "",
1006
+ parentRole: ""
1007
+ });
1008
+ }
1009
+ catch {
1010
+ return requestBodyText;
1011
+ }
1012
+ }
1013
+ function readSeedBinding(selectedRequest) {
1014
+ const requestBodyJson = readRequestBodyObject(selectedRequest);
1015
+ const requestUrl = typeof selectedRequest.url === "string" ? selectedRequest.url : "";
1016
+ const conversationId = readConversationIdFromUrl(requestUrl) ||
1017
+ readFirstNestedStringByKeys(requestBodyJson, [
1018
+ "chat_id",
1019
+ "chat_session_id",
1020
+ "chatSessionId",
1021
+ "conversation_id",
1022
+ "conversationId",
1023
+ "thread_id",
1024
+ "threadId",
1025
+ "session_id",
1026
+ "sessionId"
1027
+ ]);
1028
+ const parentId = readFirstNestedStringByKeys(requestBodyJson, [
1029
+ "parent_id",
1030
+ "parentId",
1031
+ "parent_message_id",
1032
+ "parentMessageId",
1033
+ "message_id",
1034
+ "messageId"
1035
+ ]);
1036
+ return conversationId
1037
+ ? {
1038
+ seedBinding: {
1039
+ conversationId,
1040
+ ...(parentId ? { parentId } : {})
1041
+ }
1042
+ }
1043
+ : {};
1044
+ }
1045
+ function readConversationIdFromUrl(requestUrl) {
1046
+ if (!requestUrl) {
1047
+ return "";
1048
+ }
1049
+ try {
1050
+ const url = new URL(requestUrl);
1051
+ for (const key of [
1052
+ "chat_id",
1053
+ "chat_session_id",
1054
+ "chatSessionId",
1055
+ "conversation_id",
1056
+ "conversationId",
1057
+ "thread_id",
1058
+ "threadId",
1059
+ "session_id",
1060
+ "sessionId"
1061
+ ]) {
1062
+ const value = url.searchParams.get(key);
1063
+ if (value?.trim()) {
1064
+ return value.trim();
1065
+ }
1066
+ }
1067
+ }
1068
+ catch {
1069
+ return "";
1070
+ }
1071
+ return "";
1072
+ }
1073
+ function readFirstStringByKeys(value, keys) {
1074
+ if (!value) {
1075
+ return "";
1076
+ }
1077
+ for (const key of keys) {
1078
+ const entry = value[key];
1079
+ if (typeof entry === "string" && entry.trim()) {
1080
+ return entry.trim();
1081
+ }
1082
+ if (typeof entry === "number" && Number.isFinite(entry)) {
1083
+ return String(entry);
1084
+ }
1085
+ }
1086
+ return "";
1087
+ }
1088
+ function readFirstNestedStringByKeys(value, keys) {
1089
+ if (!value) {
1090
+ return "";
1091
+ }
1092
+ const direct = readFirstStringByKeys(value, keys);
1093
+ if (direct) {
1094
+ return direct;
1095
+ }
1096
+ for (const entry of Object.values(value)) {
1097
+ if (Array.isArray(entry)) {
1098
+ for (const item of entry) {
1099
+ if (typeof item !== "object" || item === null || Array.isArray(item)) {
1100
+ continue;
1101
+ }
1102
+ const nested = readFirstNestedStringByKeys(item, keys);
1103
+ if (nested) {
1104
+ return nested;
1105
+ }
1106
+ }
1107
+ continue;
1108
+ }
1109
+ if (typeof entry !== "object" || entry === null) {
1110
+ continue;
1111
+ }
1112
+ const nested = readFirstNestedStringByKeys(entry, keys);
1113
+ if (nested) {
1114
+ return nested;
1115
+ }
1116
+ }
1117
+ return "";
1118
+ }
1119
+ function templateRequestValue(value, context) {
1120
+ if (Array.isArray(value)) {
1121
+ if (/^children(ids|_ids)?$/i.test(context.parentKey)) {
1122
+ return [];
1123
+ }
1124
+ return value.map((entry) => templateRequestValue(entry, context));
1125
+ }
1126
+ if (typeof value === "object" && value !== null) {
1127
+ const record = value;
1128
+ const nextRole = typeof record.role === "string" ? record.role.toLowerCase() : context.parentRole;
1129
+ return Object.fromEntries(Object.entries(record).map(([key, entry]) => [
1130
+ key,
1131
+ templateRequestValue(entry, {
1132
+ parentKey: key,
1133
+ parentRole: nextRole
1134
+ })
1135
+ ]));
1136
+ }
1137
+ if (typeof value === "number" && Number.isFinite(value)) {
1138
+ const key = context.parentKey.toLowerCase();
1139
+ if (/(^|_)(parent|parentid|parent_id|messageid|message_id)$/.test(key)) {
1140
+ return "{{parentIdNumberOrOmit}}";
1141
+ }
1142
+ if (/(^|_)(timestamp|time|ts)$/.test(key)) {
1143
+ return value >= 1000000000000 ? "{{unixTimestampMs}}" : "{{unixTimestampSec}}";
1144
+ }
1145
+ return value;
1146
+ }
1147
+ if (typeof value === "boolean") {
1148
+ const key = context.parentKey.toLowerCase();
1149
+ if (key === "thinking") {
1150
+ return value ? "{{thinkingEnabledOrTrue}}" : "{{thinkingEnabledOrFalse}}";
1151
+ }
1152
+ return value;
1153
+ }
1154
+ if (typeof value !== "string") {
1155
+ return value;
1156
+ }
1157
+ const key = context.parentKey.toLowerCase();
1158
+ const role = context.parentRole.toLowerCase();
1159
+ if (key === "fid") {
1160
+ return "{{messageId}}";
1161
+ }
1162
+ if ((key === "message_id" || key === "messageid") && value.trim() === "") {
1163
+ return value;
1164
+ }
1165
+ if (/(^|_)(parent|parentid|parent_id|messageid|message_id)$/.test(key) &&
1166
+ /^-?(?:0|[1-9]\d*)$/.test(value.trim())) {
1167
+ return "{{parentIdNumberOrOmit}}";
1168
+ }
1169
+ if (/(^|_)(model|modelid|model_id|models)$/.test(key)) {
1170
+ return "{{modelId}}";
1171
+ }
1172
+ if (/(^|_)(trace|request|requestid|request_id)$/.test(key)) {
1173
+ return "{{requestUuid}}";
1174
+ }
1175
+ if (/(^|_)(conversation|chat|session|thread)(id|_id)?$/.test(key)) {
1176
+ return "{{conversationIdOrOmit}}";
1177
+ }
1178
+ if (/(^|_)(parent|parentid|parent_id|messageid|message_id)$/.test(key)) {
1179
+ return "{{parentIdOrOmit}}";
1180
+ }
1181
+ if (/(^|_)(prompt|input|query|text|message)$/.test(key)) {
1182
+ return "{{prompt}}";
1183
+ }
1184
+ if (key === "content" && (!role || role === "user")) {
1185
+ return "{{prompt}}";
1186
+ }
1187
+ return value;
1188
+ }
1189
+ function readExplicitModelIds(value) {
1190
+ const integrationModels = value.integration?.models?.map((entry) => entry.trim()).filter(Boolean) ?? [];
1191
+ if (integrationModels.length > 0) {
1192
+ return [...new Set(integrationModels)].sort((left, right) => left.localeCompare(right));
1193
+ }
1194
+ const metadataModels = readMetadataModelCatalog(value.metadata);
1195
+ if (metadataModels.length > 0) {
1196
+ return metadataModels;
1197
+ }
1198
+ return null;
1199
+ }
1200
+ function inferModelIdsFromCapture(value) {
1201
+ const selectedRequest = readSelectedRequest(value.metadata);
1202
+ const topLevelModelHints = Array.isArray(selectedRequest?.modelHints)
1203
+ ? selectedRequest.modelHints
1204
+ : [];
1205
+ const inferred = typeof selectedRequest?.inferred === "object" && selectedRequest.inferred !== null
1206
+ ? selectedRequest.inferred
1207
+ : null;
1208
+ const inferredModelHints = Array.isArray(inferred?.modelHints) ? inferred.modelHints : [];
1209
+ const mirroredSelectedRequest = typeof value.metadata.selectedRequest === "object" && value.metadata.selectedRequest !== null
1210
+ ? value.metadata.selectedRequest
1211
+ : null;
1212
+ const mirroredModelHints = Array.isArray(mirroredSelectedRequest?.modelHints)
1213
+ ? mirroredSelectedRequest.modelHints
1214
+ : [];
1215
+ const rawModelHints = [...topLevelModelHints, ...inferredModelHints, ...mirroredModelHints];
1216
+ return [
1217
+ ...new Set(rawModelHints
1218
+ .filter((entry) => typeof entry === "string")
1219
+ .map((entry) => entry.trim()))
1220
+ ]
1221
+ .filter(Boolean)
1222
+ .sort((left, right) => left.localeCompare(right));
1223
+ }
1224
+ function readMetadataModelCatalog(metadata) {
1225
+ const explicitLists = [metadata.availableModels, metadata.supportedModels, metadata.modelCatalog];
1226
+ for (const candidate of explicitLists) {
1227
+ const parsed = normalizeModelCatalogEntries(candidate);
1228
+ if (parsed.length > 0) {
1229
+ return parsed;
1230
+ }
1231
+ }
1232
+ return [];
1233
+ }
1234
+ function normalizeModelCatalogEntries(value) {
1235
+ if (!Array.isArray(value)) {
1236
+ return [];
1237
+ }
1238
+ return [
1239
+ ...new Set(value.flatMap((entry) => {
1240
+ if (typeof entry === "string") {
1241
+ const normalized = entry.trim();
1242
+ return normalized ? [normalized] : [];
1243
+ }
1244
+ if (typeof entry !== "object" || entry === null || Array.isArray(entry)) {
1245
+ return [];
1246
+ }
1247
+ for (const key of ["id", "model", "name"]) {
1248
+ const candidate = entry[key];
1249
+ if (typeof candidate === "string" && candidate.trim()) {
1250
+ return [candidate.trim()];
1251
+ }
1252
+ }
1253
+ return [];
1254
+ }))
1255
+ ].sort((left, right) => left.localeCompare(right));
1256
+ }
1257
+ function mergeModelIds(existing, inferred) {
1258
+ return [...new Set([...existing, ...inferred])].sort((left, right) => left.localeCompare(right));
1259
+ }
1260
+ function readLabel(value, fallback) {
1261
+ const explicit = value.integration?.label?.trim();
1262
+ if (explicit) {
1263
+ return explicit;
1264
+ }
1265
+ const metadata = value.metadata;
1266
+ const title = typeof metadata.tabTitle === "string" ? metadata.tabTitle.trim() : "";
1267
+ if (title) {
1268
+ return title;
1269
+ }
1270
+ try {
1271
+ return new URL(value.origin).hostname;
1272
+ }
1273
+ catch {
1274
+ return fallback;
1275
+ }
1276
+ }
1277
+ function readSelectedRequest(metadata) {
1278
+ const capture = metadata.requestCapture;
1279
+ if (typeof capture !== "object" || capture === null) {
1280
+ return null;
1281
+ }
1282
+ const selectedRequest = capture.selectedRequest;
1283
+ return typeof selectedRequest === "object" && selectedRequest !== null
1284
+ ? selectedRequest
1285
+ : null;
1286
+ }
1287
+ function readUsesSse(selectedRequest) {
1288
+ if (selectedRequest.usesSse === true) {
1289
+ return true;
1290
+ }
1291
+ const inferred = selectedRequest.inferred;
1292
+ if (typeof inferred === "object" &&
1293
+ inferred !== null &&
1294
+ inferred.usesSse === true) {
1295
+ return true;
1296
+ }
1297
+ return false;
1298
+ }
1299
+ function readTransportFamily(selectedRequest) {
1300
+ if (readUsesSse(selectedRequest)) {
1301
+ return "http-sse";
1302
+ }
1303
+ if (isConnectJsonContentType(readSelectedRequestContentType(selectedRequest))) {
1304
+ return "http-connect";
1305
+ }
1306
+ return "http-json";
1307
+ }
1308
+ function readSelectedRequestContentType(selectedRequest) {
1309
+ const direct = selectedRequest.contentType;
1310
+ if (typeof direct === "string" && direct.trim()) {
1311
+ return direct.trim();
1312
+ }
1313
+ const headers = readSelectedRequestHeaders(selectedRequest);
1314
+ if (typeof headers !== "object" || headers === null || Array.isArray(headers)) {
1315
+ return "";
1316
+ }
1317
+ const entry = Object.entries(headers).find(([key]) => key.toLowerCase() === "content-type")?.[1];
1318
+ return typeof entry === "string" ? entry.trim() : "";
1319
+ }
1320
+ function readSelectedRequestHeaders(selectedRequest) {
1321
+ for (const key of ["headers", "requestHeaders"]) {
1322
+ const candidate = selectedRequest[key];
1323
+ if (typeof candidate === "object" && candidate !== null && !Array.isArray(candidate)) {
1324
+ return candidate;
1325
+ }
1326
+ }
1327
+ return null;
1328
+ }
1329
+ function isConnectJsonContentType(value) {
1330
+ return /^application\/connect\+json\b/i.test(value.trim());
1331
+ }
1332
+ function isZaiBootstrapRequestUrl(value) {
1333
+ try {
1334
+ const url = new URL(value);
1335
+ return url.origin === "https://chat.z.ai" && url.pathname === "/api/v1/chats/new";
1336
+ }
1337
+ catch {
1338
+ return false;
1339
+ }
1340
+ }
1341
+ function readRequestBodyObject(selectedRequest) {
1342
+ const requestBodyJson = selectedRequest.requestBodyJson;
1343
+ if (requestBodyJson && typeof requestBodyJson === "object" && !Array.isArray(requestBodyJson)) {
1344
+ return requestBodyJson;
1345
+ }
1346
+ const requestBodyText = typeof selectedRequest.requestBodyText === "string"
1347
+ ? selectedRequest.requestBodyText.trim()
1348
+ : "";
1349
+ if (!requestBodyText) {
1350
+ return null;
1351
+ }
1352
+ if (isConnectJsonContentType(readSelectedRequestContentType(selectedRequest))) {
1353
+ const decoded = decodeConnectJsonBody(requestBodyText);
1354
+ if (decoded && typeof decoded === "object" && !Array.isArray(decoded)) {
1355
+ return decoded;
1356
+ }
1357
+ }
1358
+ try {
1359
+ const parsed = JSON.parse(requestBodyText);
1360
+ return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)
1361
+ ? parsed
1362
+ : null;
1363
+ }
1364
+ catch {
1365
+ return null;
1366
+ }
1367
+ }
1368
+ function decodeConnectJsonBody(value) {
1369
+ const encoded = value.trim();
1370
+ if (!encoded) {
1371
+ return null;
1372
+ }
1373
+ const bytes = Uint8Array.from(encoded, (char) => char.charCodeAt(0) & 0xff);
1374
+ if (bytes.length >= 5) {
1375
+ const length = ((bytes[1] ?? 0) << 24) | ((bytes[2] ?? 0) << 16) | ((bytes[3] ?? 0) << 8) | (bytes[4] ?? 0);
1376
+ if (length > 0 && bytes.length >= 5 + length) {
1377
+ const payload = new TextDecoder().decode(bytes.slice(5, 5 + length)).trim();
1378
+ if (payload) {
1379
+ try {
1380
+ return JSON.parse(payload);
1381
+ }
1382
+ catch {
1383
+ // Fall through to the textual JSON-start recovery path below.
1384
+ }
1385
+ }
1386
+ }
1387
+ }
1388
+ const jsonStart = [...encoded].findIndex((char) => char === "{" || char === "[");
1389
+ if (jsonStart < 0) {
1390
+ return null;
1391
+ }
1392
+ try {
1393
+ return JSON.parse(encoded.slice(jsonStart).trim());
1394
+ }
1395
+ catch {
1396
+ return null;
1397
+ }
1398
+ }
1399
+ function readConfiguredModelIds(config) {
1400
+ if (!config || !Array.isArray(config.models)) {
1401
+ return [];
1402
+ }
1403
+ return [
1404
+ ...new Set(config.models
1405
+ .filter((value) => typeof value === "string")
1406
+ .map((value) => value.trim()))
1407
+ ]
1408
+ .filter(Boolean)
1409
+ .sort((left, right) => left.localeCompare(right));
1410
+ }
1411
+ function readConfiguredTransport(config) {
1412
+ if (!config) {
1413
+ return null;
1414
+ }
1415
+ const transport = config.transport;
1416
+ if (typeof transport !== "object" || transport === null || Array.isArray(transport)) {
1417
+ return null;
1418
+ }
1419
+ return transport;
1420
+ }
1421
+ function hasBearerAuthorization(headers) {
1422
+ const authorization = Object.entries(headers).find(([key]) => key.toLowerCase() === "authorization")?.[1];
1423
+ return typeof authorization === "string" && /^Bearer\s+\S+/i.test(authorization);
1424
+ }
1425
+ function hasHeader(headers, headerName) {
1426
+ const target = headerName.toLowerCase();
1427
+ return Object.entries(headers).some(([key, value]) => key.toLowerCase() === target && typeof value === "string" && value.trim());
1428
+ }
1429
+ function readLifecycleIsoString(value, key) {
1430
+ if (typeof value !== "object" || value === null) {
1431
+ return undefined;
1432
+ }
1433
+ const record = value;
1434
+ const candidate = record[key];
1435
+ if (typeof candidate !== "string") {
1436
+ return undefined;
1437
+ }
1438
+ return z.string().datetime({ offset: true }).safeParse(candidate).success ? candidate : undefined;
1439
+ }
1440
+ function createTimestamp(previous) {
1441
+ const previousTime = previous ? Date.parse(previous) : 0;
1442
+ const now = Date.now();
1443
+ const nextTime = previousTime >= now ? previousTime + 1 : now;
1444
+ return new Date(nextTime).toISOString();
1445
+ }
1446
+ function missingProviderError(id) {
1447
+ return new BridgeApiError({
1448
+ statusCode: 404,
1449
+ code: "provider_not_found",
1450
+ message: `Provider '${id}' was not found.`
1451
+ });
1452
+ }
1453
+ const DEFAULT_SSE_CONTENT_PATHS = [
1454
+ "v.message.content.parts.*",
1455
+ "message.content.parts.*",
1456
+ "choices.0.delta.content",
1457
+ "data.choices.0.delta.content",
1458
+ "v.response.fragments.*.content",
1459
+ "response.fragments.*.content",
1460
+ "delta.content",
1461
+ "content"
1462
+ ];
1463
+ const DEFAULT_CONNECT_CONTENT_PATHS = [
1464
+ "choices.0.delta.content",
1465
+ "data.choices.0.delta.content",
1466
+ "message.content",
1467
+ "message.blocks.*.text.content",
1468
+ "block.text.content",
1469
+ "blocks.*.text.content",
1470
+ "delta.content",
1471
+ "text",
1472
+ "content"
1473
+ ];
1474
+ const DEFAULT_JSON_CONTENT_PATHS = [
1475
+ "choices.0.message.content",
1476
+ "message.content",
1477
+ "output_text",
1478
+ "content",
1479
+ "data.content"
1480
+ ];
1481
+ const DEFAULT_RESPONSE_ID_PATHS = [
1482
+ "v.message.id",
1483
+ "response_id",
1484
+ "response_message_id",
1485
+ "id",
1486
+ "message.id",
1487
+ "message_id",
1488
+ "block.messageId",
1489
+ "data.id",
1490
+ "response.id",
1491
+ "response.message_id",
1492
+ "v.response.message_id"
1493
+ ];
1494
+ const DEFAULT_CONVERSATION_ID_PATHS = [
1495
+ "v.conversation_id",
1496
+ "conversation_id",
1497
+ "conversation.id",
1498
+ "conversationId",
1499
+ "chat.id",
1500
+ "chat_id",
1501
+ "thread.id",
1502
+ "thread_id",
1503
+ "threadId",
1504
+ "session.id",
1505
+ "session_id",
1506
+ "sessionId",
1507
+ "data.conversation_id",
1508
+ "data.chat_id",
1509
+ "data.thread_id",
1510
+ "response.conversation_id"
1511
+ ];
1512
+ export const sessionPackageStoreModule = {
1513
+ sessionPackageSchema,
1514
+ sessionPackageStatusResponseSchema,
1515
+ sessionPackageDeleteResponseSchema,
1516
+ sessionPackageMetadataSchema,
1517
+ installedProviderPackageSchema,
1518
+ createInMemorySessionPackageStore,
1519
+ buildSessionPackageStatus,
1520
+ cloneProvider,
1521
+ cloneConfig,
1522
+ cloneSessionPackage,
1523
+ cloneSessionPackageMetadata,
1524
+ cloneInstalledProviderPackage,
1525
+ buildSessionPackageMetadata,
1526
+ inferProviderFromSessionPackage
1527
+ };