@axiom-lattice/gateway 8.0.0 → 8.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/embed/{embed-page-AgentDetailSideApp-NK6VQBXS.js → embed-page-AgentDetailSideApp-23TCREK6.js} +1 -1
  2. package/dist/embed/embed-page-AgentGovernanceWorkbench-N3F65F3W.js +1 -0
  3. package/dist/embed/{embed-page-LangfuseDashboard-EYK2T2VK.js → embed-page-LangfuseDashboard-WBE7GJPU.js} +1 -1
  4. package/dist/embed/{embed-page-MessageGraph-P73B52OR.js → embed-page-MessageGraph-T3EFAXTX.js} +1 -1
  5. package/dist/embed/{embed-page-ReactChart-LK6DUA4R.js → embed-page-ReactChart-FJFQU4IV.js} +1 -1
  6. package/dist/embed/{embed-page-SkillFlow-54RIT6M2.js → embed-page-SkillFlow-2BUXCLAL.js} +1 -1
  7. package/dist/embed/{embed-page-TasksSideApp-RK64OPAA.js → embed-page-TasksSideApp-VFKEYFGR.js} +1 -1
  8. package/dist/embed/{embed-page-ThreadMaintenancePanel-PI3U76W3.js → embed-page-ThreadMaintenancePanel-EPBJ4J3L.js} +1 -1
  9. package/dist/embed/{embed-page-TopologyRuntimeView-X6QPRQE2.js → embed-page-TopologyRuntimeView-OWESU7IK.js} +1 -1
  10. package/dist/embed/{embed-page-WorkflowAutomationView-3PE6YCRK.js → embed-page-WorkflowAutomationView-5J2RQTZ7.js} +1 -1
  11. package/dist/embed/{embed-page-chunk-BD7DUF2M.js → embed-page-chunk-2ZBEWYJQ.js} +1 -1
  12. package/dist/embed/{embed-page-chunk-AICFKU43.js → embed-page-chunk-34RWKVD7.js} +1 -1
  13. package/dist/embed/{embed-page-chunk-GYO2ELMI.js → embed-page-chunk-6QLLZJVH.js} +1 -1
  14. package/dist/embed/embed-page-chunk-B2KNZ3EW.js +59 -0
  15. package/dist/embed/{embed-page-chunk-UV6IYDW5.js → embed-page-chunk-BFVNPGSW.js} +1 -1
  16. package/dist/embed/embed-page-chunk-CKUSXUKW.js +6746 -0
  17. package/dist/embed/{embed-page-chunk-YWJQVBZV.js → embed-page-chunk-CQLDPGEG.js} +1 -1
  18. package/dist/embed/{embed-page-chunk-TSZQWEXD.js → embed-page-chunk-DJKD2PHO.js} +1 -1
  19. package/dist/embed/{embed-page-chunk-KF3HZ4TX.js → embed-page-chunk-EU32IF7M.js} +1 -1
  20. package/dist/embed/{embed-page-chunk-T2HKN7ZS.js → embed-page-chunk-F7TA3LRH.js} +1 -1
  21. package/dist/embed/embed-page-chunk-F7ZUYG42.js +121 -0
  22. package/dist/embed/{embed-page-chunk-3VNL5M2Q.js → embed-page-chunk-GSUSX54K.js} +1 -1
  23. package/dist/embed/embed-page-chunk-JMTQCORF.js +211 -0
  24. package/dist/embed/{embed-page-chunk-US46Q3B7.js → embed-page-chunk-L7TDL27M.js} +2 -2
  25. package/dist/embed/{embed-page-chunk-OIML5DX4.js → embed-page-chunk-PTKGTA4B.js} +1 -1
  26. package/dist/embed/{embed-page-chunk-767LVAGR.js → embed-page-chunk-R7TLHZR3.js} +1 -1
  27. package/dist/embed/{embed-page-chunk-OKZPPZMF.js → embed-page-chunk-WKQHSEZ4.js} +1 -1
  28. package/dist/embed/{embed-page-code-highlighter-DD23LJY3.js → embed-page-code-highlighter-72YW5HXH.js} +1 -1
  29. package/dist/embed/embed-page-en-G5J7KW6V.js +1 -0
  30. package/dist/embed/embed-page-en-HDSVQ4O6.js +1 -0
  31. package/dist/embed/embed-page-en-TSCGSJAI.js +1 -0
  32. package/dist/embed/{embed-page-mermaid-IN3A3YH2.js → embed-page-mermaid-4PZJJXQU.js} +1 -1
  33. package/dist/embed/embed-page-zh-72QSTYRF.js +1 -0
  34. package/dist/embed/embed-page-zh-IR652A6J.js +1 -0
  35. package/dist/embed/embed-page-zh-Q22DIOB3.js +1 -0
  36. package/dist/embed/embed-page.js +1 -1
  37. package/dist/index.d.mts +19 -11
  38. package/dist/index.d.ts +19 -11
  39. package/dist/index.js +316 -190
  40. package/dist/index.js.map +1 -1
  41. package/dist/index.mjs +167 -37
  42. package/dist/index.mjs.map +1 -1
  43. package/package.json +7 -7
  44. package/dist/embed/embed-page-AgentGovernanceWorkbench-TKVV2GA6.js +0 -1
  45. package/dist/embed/embed-page-chunk-A5GIM22E.js +0 -117
  46. package/dist/embed/embed-page-chunk-EB43T3BJ.js +0 -6746
  47. package/dist/embed/embed-page-chunk-MEY3NEJZ.js +0 -211
  48. package/dist/embed/embed-page-chunk-WXMPVIXV.js +0 -59
  49. package/dist/embed/embed-page-en-27OIE2UA.js +0 -1
  50. package/dist/embed/embed-page-en-PQOH5CU4.js +0 -1
  51. package/dist/embed/embed-page-en-X6B6RVNL.js +0 -1
  52. package/dist/embed/embed-page-zh-EQ5X2M32.js +0 -1
  53. package/dist/embed/embed-page-zh-FXQGY5HD.js +0 -1
  54. package/dist/embed/embed-page-zh-XO36BV2R.js +0 -1
package/dist/index.mjs CHANGED
@@ -16986,6 +16986,7 @@ function registerA2ABridgeRoutes(app2) {
16986
16986
 
16987
16987
  // src/routes/stt.ts
16988
16988
  import { sttModelLatticeManager } from "@axiom-lattice/core";
16989
+ import { ASR_DEFAULT_KEY } from "@axiom-lattice/protocols";
16989
16990
  function tenantIdOf(request) {
16990
16991
  try {
16991
16992
  return resolveTenantScope(request, false).tenantId;
@@ -17046,12 +17047,19 @@ var registerSTTRoutes = (app2) => {
17046
17047
  return reply.status(400).send({ error: `Unsupported audio format: ${format}` });
17047
17048
  }
17048
17049
  try {
17050
+ const requestedKey = modelKey2 || ASR_DEFAULT_KEY;
17049
17051
  const client = await sttModelLatticeManager.getSTTClientWithTenantAsync(
17050
17052
  tenantIdOf(request),
17051
- modelKey2
17053
+ requestedKey
17054
+ ) ?? (requestedKey === ASR_DEFAULT_KEY ? void 0 : await sttModelLatticeManager.getSTTClientWithTenantAsync(
17055
+ tenantIdOf(request),
17056
+ ASR_DEFAULT_KEY
17057
+ )) ?? await sttModelLatticeManager.getSTTClientWithTenantAsync(
17058
+ tenantIdOf(request),
17059
+ "default"
17052
17060
  );
17053
17061
  if (!client) {
17054
- return reply.status(404).send({ error: `STT model "${modelKey2}" not found` });
17062
+ return reply.status(404).send({ error: `STT model "${requestedKey}" not found` });
17055
17063
  }
17056
17064
  const result = await client.transcribe(buffer, format);
17057
17065
  return reply.send({
@@ -21671,8 +21679,12 @@ import { randomUUID as randomUUID23 } from "crypto";
21671
21679
  import { toModelKey } from "@axiom-lattice/protocols";
21672
21680
  import {
21673
21681
  assertSafeUpstreamUrl,
21682
+ buildModelEmbeddingsConfig,
21674
21683
  buildModelLlmConfig,
21675
21684
  DEFAULT_MODEL_EXTRA,
21685
+ embeddingProbeCandidates,
21686
+ resolveEmbeddingEndpoint,
21687
+ resolveEmbeddingShape,
21676
21688
  UnsupportedModelProviderError,
21677
21689
  UnsafeUpstreamUrlError
21678
21690
  } from "@axiom-lattice/core";
@@ -21844,7 +21856,6 @@ var openAiCompatibleAdapter = {
21844
21856
  };
21845
21857
  async function probeEmbeddingInference(input, signal) {
21846
21858
  const startedAt = Date.now();
21847
- const endpoint = buildOpenAiEndpoint(input.baseURL, "embeddings");
21848
21859
  const headers = {
21849
21860
  Accept: "application/json",
21850
21861
  "Content-Type": "application/json"
@@ -21852,17 +21863,25 @@ async function probeEmbeddingInference(input, signal) {
21852
21863
  if (input.apiKey) {
21853
21864
  headers.Authorization = `Bearer ${input.apiKey}`;
21854
21865
  }
21866
+ const body = input.shape === "contents" ? JSON.stringify({
21867
+ model: input.modelId,
21868
+ input: { contents: [{ text: "ping" }] }
21869
+ }) : input.shape === "texts" ? JSON.stringify({
21870
+ model: input.modelId,
21871
+ input: { texts: ["ping"] }
21872
+ }) : JSON.stringify({ model: input.modelId, input: "ping" });
21873
+ let status;
21855
21874
  try {
21856
21875
  let response;
21857
21876
  try {
21858
- response = await fetch(endpoint, {
21877
+ response = await fetch(input.endpoint, {
21859
21878
  method: "POST",
21860
21879
  headers,
21861
21880
  // Never follow redirects: a redirected request could reach an address
21862
21881
  // that bypassed the SSRF checks.
21863
21882
  redirect: "manual",
21864
21883
  signal,
21865
- body: JSON.stringify({ model: input.modelId, input: "ping" })
21884
+ body
21866
21885
  });
21867
21886
  } catch (error) {
21868
21887
  if (error instanceof Error && error.name === "AbortError") {
@@ -21880,11 +21899,12 @@ async function probeEmbeddingInference(input, signal) {
21880
21899
  true
21881
21900
  );
21882
21901
  }
21902
+ status = response.status;
21883
21903
  assertUpstreamOk(response);
21884
- const body = await readBodyWithLimit(response, MAX_RESPONSE_BYTES);
21904
+ const text = await readBodyWithLimit(response, MAX_RESPONSE_BYTES);
21885
21905
  let payload;
21886
21906
  try {
21887
- payload = JSON.parse(body);
21907
+ payload = JSON.parse(text);
21888
21908
  } catch {
21889
21909
  throw new ModelProviderServiceError(
21890
21910
  "UPSTREAM_INVALID_RESPONSE",
@@ -21895,14 +21915,16 @@ async function probeEmbeddingInference(input, signal) {
21895
21915
  return {
21896
21916
  reachable: true,
21897
21917
  latencyMs: Date.now() - startedAt,
21898
- dimensions: readEmbeddingDimensions(payload)
21918
+ dimensions: input.shape === "openai" ? readEmbeddingDimensions(payload) : readServiceDimensions(payload),
21919
+ status
21899
21920
  };
21900
21921
  } catch (error) {
21901
21922
  if (error instanceof ModelProviderServiceError && isUpstreamErrorCode(error.code)) {
21902
21923
  return {
21903
21924
  reachable: false,
21904
21925
  latencyMs: Date.now() - startedAt,
21905
- error: error.code
21926
+ error: error.code,
21927
+ ...status === void 0 ? {} : { status }
21906
21928
  };
21907
21929
  }
21908
21930
  throw error;
@@ -21923,6 +21945,25 @@ function readEmbeddingDimensions(payload) {
21923
21945
  const embedding = first.embedding;
21924
21946
  return Array.isArray(embedding) ? embedding.length : void 0;
21925
21947
  }
21948
+ function readServiceDimensions(payload) {
21949
+ if (typeof payload !== "object" || payload === null) {
21950
+ return void 0;
21951
+ }
21952
+ const output = payload.output;
21953
+ if (typeof output !== "object" || output === null) {
21954
+ return void 0;
21955
+ }
21956
+ const embeddings = output.embeddings;
21957
+ if (!Array.isArray(embeddings) || embeddings.length === 0) {
21958
+ return void 0;
21959
+ }
21960
+ const first = embeddings[0];
21961
+ if (typeof first !== "object" || first === null) {
21962
+ return void 0;
21963
+ }
21964
+ const embedding = first.embedding;
21965
+ return Array.isArray(embedding) ? embedding.length : void 0;
21966
+ }
21926
21967
  async function readBodyWithLimit(response, maxBytes) {
21927
21968
  if (!response.body) {
21928
21969
  return response.text();
@@ -22369,14 +22410,57 @@ var ModelProviderService = class {
22369
22410
  );
22370
22411
  }
22371
22412
  try {
22372
- const outcome = await probeEmbeddingInference(
22373
- { baseURL: input.baseURL, apiKey, modelId: input.modelId },
22413
+ const provider = input.providerId ? await this.deps.providerStore.getProviderById(
22414
+ tenantId,
22415
+ input.providerId
22416
+ ) : null;
22417
+ const modelRow = provider && input.providerId ? await this.deps.providerStore.getModel(
22418
+ tenantId,
22419
+ input.providerId,
22420
+ input.modelId
22421
+ ) : null;
22422
+ const extra = modelRow?.extra ?? {};
22423
+ const explicitShape = extra.embeddingShape === "openai" || extra.embeddingShape === "contents" || extra.embeddingShape === "texts";
22424
+ const baseURL = provider?.baseURL ?? input.baseURL;
22425
+ const initialShape = provider && modelRow ? buildModelEmbeddingsConfig(provider, modelRow).shape : resolveEmbeddingShape(input.modelId, {});
22426
+ const attempt = (shape) => probeEmbeddingInference(
22427
+ {
22428
+ endpoint: resolveEmbeddingEndpoint(baseURL, shape, extra),
22429
+ apiKey,
22430
+ modelId: input.modelId,
22431
+ shape
22432
+ },
22374
22433
  controller.signal
22375
22434
  );
22435
+ const candidates = explicitShape ? [initialShape] : embeddingProbeCandidates(initialShape, input.modelId);
22436
+ let outcome = await attempt(candidates[0]);
22437
+ let usedShape = candidates[0];
22438
+ for (const candidate of candidates.slice(1)) {
22439
+ if (outcome.reachable || outcome.status !== 400 && outcome.status !== 404) {
22440
+ break;
22441
+ }
22442
+ const next = await attempt(candidate);
22443
+ if (!next.reachable) {
22444
+ continue;
22445
+ }
22446
+ outcome = next;
22447
+ usedShape = candidate;
22448
+ if (provider && modelRow) {
22449
+ await this.persistEmbeddingShape(
22450
+ tenantId,
22451
+ provider,
22452
+ modelRow,
22453
+ candidate,
22454
+ extra
22455
+ );
22456
+ }
22457
+ break;
22458
+ }
22376
22459
  return {
22377
22460
  reachable: outcome.reachable,
22378
22461
  latencyMs: outcome.latencyMs,
22379
22462
  models: [],
22463
+ shape: usedShape,
22380
22464
  ...outcome.dimensions === void 0 ? {} : { dimensions: outcome.dimensions },
22381
22465
  ...outcome.error ? { error: outcome.error } : {}
22382
22466
  };
@@ -22477,48 +22561,94 @@ var ModelProviderService = class {
22477
22561
  return this.toPublicEntry(provider, models.length);
22478
22562
  }
22479
22563
  /**
22480
- * Give a tenant's sole **chat** model the default flag.
22564
+ * Give each kind's sole model its default flag.
22481
22565
  *
22482
- * A tenant with exactly one runnable chat model has an obvious default, and
22483
- * saying so is what keeps the invariant the rest of the feature leans on: a
22484
- * tenant either has no chat model at all — and falls back to the deployment's
22485
- * default — or has a default, which cannot be deleted. Without this a tenant
22486
- * could sit with one model and no default, and deleting that model would
22487
- * leave nothing behind.
22566
+ * A tenant with exactly one runnable model **of a kind** has an obvious
22567
+ * default for that kind, and saying so keeps the invariant the rest of the
22568
+ * feature leans on: a kind either has no model at all — and falls back to the
22569
+ * deployment's default — or has a default, which cannot be deleted.
22488
22570
  *
22489
- * Chat only: a bare `"default"` key resolves to a chat client, so an
22490
- * embedding or ASR row must never be marked as one.
22571
+ * Per kind because each kind publishes its own alias key (`default`,
22572
+ * `default:embedding`, `default:asr`).
22491
22573
  *
22492
- * Deliberately narrow: more than one model is the tenant's choice to make,
22493
- * and a disabled model is not a candidate for "the model this tenant runs".
22574
+ * Deliberately narrow: more than one model of a kind is the tenant's choice to
22575
+ * make, and a disabled model is not a candidate.
22494
22576
  *
22495
22577
  * @param tenantId - The tenant whose model set just changed
22496
22578
  */
22497
22579
  async ensureDefaultModel(tenantId) {
22498
22580
  const models = await this.deps.providerStore.listModels(tenantId);
22499
- const chatModels = models.filter((model) => model.kind === "chat");
22500
- if (chatModels.length !== 1) {
22581
+ const toMark = ["chat", "embedding", "asr"].flatMap((kind) => {
22582
+ const ofKind = models.filter((model) => model.kind === kind);
22583
+ if (ofKind.length !== 1) {
22584
+ return [];
22585
+ }
22586
+ const [only] = ofKind;
22587
+ return only.enabled && !only.isDefault ? [only] : [];
22588
+ });
22589
+ if (toMark.length === 0) {
22501
22590
  return;
22502
22591
  }
22503
- const [only] = chatModels;
22504
- if (only.isDefault || !only.enabled) {
22505
- return;
22592
+ const byProvider = /* @__PURE__ */ new Map();
22593
+ for (const model of models) {
22594
+ const list = byProvider.get(model.providerId) ?? [];
22595
+ list.push(model);
22596
+ byProvider.set(model.providerId, list);
22506
22597
  }
22507
- const siblings = models.filter(
22508
- (model) => model.providerId === only.providerId
22598
+ for (const [providerId2, providerModels] of byProvider) {
22599
+ if (!providerModels.some((model) => toMark.includes(model))) {
22600
+ continue;
22601
+ }
22602
+ await this.deps.providerStore.replaceProviderModels(
22603
+ tenantId,
22604
+ providerId2,
22605
+ providerModels.map((model) => ({
22606
+ id: model.modelId,
22607
+ enabled: model.enabled,
22608
+ stale: model.stale,
22609
+ extra: model.extra,
22610
+ kind: model.kind,
22611
+ isDefault: toMark.includes(model) ? true : model.isDefault
22612
+ }))
22613
+ );
22614
+ }
22615
+ }
22616
+ /**
22617
+ * Persist the embedding shape a probe detected.
22618
+ *
22619
+ * A probe is read-only except for this: when the initial shape fails with
22620
+ * 400/404 and another shape works, writing it down is what makes the
22621
+ * runtime use it. The whole provider set is written because
22622
+ * `replaceProviderModels` replaces it — passing one row would delete its
22623
+ * siblings.
22624
+ */
22625
+ async persistEmbeddingShape(tenantId, provider, model, shape, extra) {
22626
+ const rows = await this.deps.providerStore.listModels(
22627
+ tenantId,
22628
+ provider.id
22509
22629
  );
22630
+ const nextExtra = { ...extra, embeddingShape: shape };
22631
+ if (shape === "openai" && typeof extra.embeddingPath !== "string") {
22632
+ delete nextExtra.embeddingPath;
22633
+ }
22510
22634
  await this.deps.providerStore.replaceProviderModels(
22511
22635
  tenantId,
22512
- only.providerId,
22513
- siblings.map((model) => ({
22514
- id: model.modelId,
22515
- enabled: model.enabled,
22516
- stale: model.stale,
22517
- extra: model.extra,
22518
- kind: model.kind,
22519
- isDefault: model.modelId === only.modelId
22636
+ provider.id,
22637
+ rows.map((row) => ({
22638
+ id: row.modelId,
22639
+ enabled: row.enabled,
22640
+ stale: row.stale,
22641
+ kind: row.kind,
22642
+ isDefault: row.isDefault,
22643
+ extra: row.modelId === model.modelId ? nextExtra : row.extra
22520
22644
  }))
22521
22645
  );
22646
+ const updated = await this.deps.providerStore.listModels(
22647
+ tenantId,
22648
+ provider.id
22649
+ );
22650
+ this.syncRegistry(tenantId, provider, updated);
22651
+ this.notifyChanged(tenantId, provider.id);
22522
22652
  }
22523
22653
  syncRegistry(tenantId, provider, models) {
22524
22654
  this.deps.registry.evictProviderCache?.(tenantId, provider.id);