@oscharko-dev/keiko 0.2.0-beta.7 → 0.2.0-beta.8

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 (210) hide show
  1. package/dist/ui/csp-hashes.json +14 -14
  2. package/dist/ui/static/404.html +1 -1
  3. package/dist/ui/static/__next.__PAGE__.txt +2 -2
  4. package/dist/ui/static/__next._full.txt +3 -3
  5. package/dist/ui/static/__next._head.txt +1 -1
  6. package/dist/ui/static/__next._index.txt +2 -2
  7. package/dist/ui/static/__next._tree.txt +2 -2
  8. package/dist/ui/static/_next/static/chunks/0i3jzgrj42so8.css +1 -0
  9. package/dist/ui/static/_next/static/chunks/1ru_021szp0u7.js +1 -0
  10. package/dist/ui/static/_next/static/chunks/1t7vb5d9ed2e7.js +1 -0
  11. package/dist/ui/static/_next/static/chunks/23o2c6pyjq92z.js +109 -0
  12. package/dist/ui/static/_not-found/__next._full.txt +2 -2
  13. package/dist/ui/static/_not-found/__next._head.txt +1 -1
  14. package/dist/ui/static/_not-found/__next._index.txt +2 -2
  15. package/dist/ui/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
  16. package/dist/ui/static/_not-found/__next._not-found.txt +1 -1
  17. package/dist/ui/static/_not-found/__next._tree.txt +2 -2
  18. package/dist/ui/static/_not-found.html +1 -1
  19. package/dist/ui/static/_not-found.txt +2 -2
  20. package/dist/ui/static/fonts/OFL.txt +93 -0
  21. package/dist/ui/static/fonts/jetbrains-mono-latin-wght-normal.woff2 +0 -0
  22. package/dist/ui/static/index.html +1 -1
  23. package/dist/ui/static/index.txt +3 -3
  24. package/dist/ui/static/launch/__next._full.txt +3 -3
  25. package/dist/ui/static/launch/__next._head.txt +1 -1
  26. package/dist/ui/static/launch/__next._index.txt +2 -2
  27. package/dist/ui/static/launch/__next._tree.txt +2 -2
  28. package/dist/ui/static/launch/__next.launch.__PAGE__.txt +2 -2
  29. package/dist/ui/static/launch/__next.launch.txt +1 -1
  30. package/dist/ui/static/launch.html +1 -1
  31. package/dist/ui/static/launch.txt +3 -3
  32. package/dist/ui/static/local-knowledge/__next._full.txt +3 -3
  33. package/dist/ui/static/local-knowledge/__next._head.txt +1 -1
  34. package/dist/ui/static/local-knowledge/__next._index.txt +2 -2
  35. package/dist/ui/static/local-knowledge/__next._tree.txt +2 -2
  36. package/dist/ui/static/local-knowledge/__next.local-knowledge.__PAGE__.txt +2 -2
  37. package/dist/ui/static/local-knowledge/__next.local-knowledge.txt +1 -1
  38. package/dist/ui/static/local-knowledge/capsule/__next._full.txt +3 -3
  39. package/dist/ui/static/local-knowledge/capsule/__next._head.txt +1 -1
  40. package/dist/ui/static/local-knowledge/capsule/__next._index.txt +2 -2
  41. package/dist/ui/static/local-knowledge/capsule/__next._tree.txt +2 -2
  42. package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.__PAGE__.txt +2 -2
  43. package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.txt +1 -1
  44. package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.txt +1 -1
  45. package/dist/ui/static/local-knowledge/capsule.html +1 -1
  46. package/dist/ui/static/local-knowledge/capsule.txt +3 -3
  47. package/dist/ui/static/local-knowledge.html +1 -1
  48. package/dist/ui/static/local-knowledge.txt +3 -3
  49. package/dist/ui/static/memoriaviva/__next._full.txt +2 -2
  50. package/dist/ui/static/memoriaviva/__next._head.txt +1 -1
  51. package/dist/ui/static/memoriaviva/__next._index.txt +2 -2
  52. package/dist/ui/static/memoriaviva/__next._tree.txt +2 -2
  53. package/dist/ui/static/memoriaviva/__next.memoriaviva.__PAGE__.txt +1 -1
  54. package/dist/ui/static/memoriaviva/__next.memoriaviva.txt +1 -1
  55. package/dist/ui/static/memoriaviva/consolidation/__next._full.txt +2 -2
  56. package/dist/ui/static/memoriaviva/consolidation/__next._head.txt +1 -1
  57. package/dist/ui/static/memoriaviva/consolidation/__next._index.txt +2 -2
  58. package/dist/ui/static/memoriaviva/consolidation/__next._tree.txt +2 -2
  59. package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.__PAGE__.txt +1 -1
  60. package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.txt +1 -1
  61. package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.txt +1 -1
  62. package/dist/ui/static/memoriaviva/consolidation.html +1 -1
  63. package/dist/ui/static/memoriaviva/consolidation.txt +2 -2
  64. package/dist/ui/static/memoriaviva/detail/__next._full.txt +2 -2
  65. package/dist/ui/static/memoriaviva/detail/__next._head.txt +1 -1
  66. package/dist/ui/static/memoriaviva/detail/__next._index.txt +2 -2
  67. package/dist/ui/static/memoriaviva/detail/__next._tree.txt +2 -2
  68. package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.__PAGE__.txt +1 -1
  69. package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.txt +1 -1
  70. package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.txt +1 -1
  71. package/dist/ui/static/memoriaviva/detail.html +1 -1
  72. package/dist/ui/static/memoriaviva/detail.txt +2 -2
  73. package/dist/ui/static/memoriaviva/review-queue/__next._full.txt +2 -2
  74. package/dist/ui/static/memoriaviva/review-queue/__next._head.txt +1 -1
  75. package/dist/ui/static/memoriaviva/review-queue/__next._index.txt +2 -2
  76. package/dist/ui/static/memoriaviva/review-queue/__next._tree.txt +2 -2
  77. package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.__PAGE__.txt +1 -1
  78. package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.txt +1 -1
  79. package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.txt +1 -1
  80. package/dist/ui/static/memoriaviva/review-queue.html +1 -1
  81. package/dist/ui/static/memoriaviva/review-queue.txt +2 -2
  82. package/dist/ui/static/memoriaviva.html +1 -1
  83. package/dist/ui/static/memoriaviva.txt +2 -2
  84. package/dist/ui/static/sw.js +7 -3
  85. package/node_modules/@oscharko-dev/keiko-cli/dist/.tsbuildinfo +1 -1
  86. package/node_modules/@oscharko-dev/keiko-cli/dist/memory.d.ts.map +1 -1
  87. package/node_modules/@oscharko-dev/keiko-cli/dist/memory.js +4 -5
  88. package/node_modules/@oscharko-dev/keiko-cli/package.json +1 -1
  89. package/node_modules/@oscharko-dev/keiko-contracts/dist/.tsbuildinfo +1 -1
  90. package/node_modules/@oscharko-dev/keiko-contracts/dist/index.d.ts +1 -1
  91. package/node_modules/@oscharko-dev/keiko-contracts/dist/index.js +1 -1
  92. package/node_modules/@oscharko-dev/keiko-contracts/package.json +1 -1
  93. package/node_modules/@oscharko-dev/keiko-evaluations/dist/.tsbuildinfo +1 -1
  94. package/node_modules/@oscharko-dev/keiko-evaluations/package.json +1 -1
  95. package/node_modules/@oscharko-dev/keiko-evidence/dist/.tsbuildinfo +1 -1
  96. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts +5 -0
  97. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts.map +1 -1
  98. package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.js +16 -0
  99. package/node_modules/@oscharko-dev/keiko-evidence/package.json +1 -1
  100. package/node_modules/@oscharko-dev/keiko-harness/dist/.tsbuildinfo +1 -1
  101. package/node_modules/@oscharko-dev/keiko-harness/package.json +1 -1
  102. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/.tsbuildinfo +1 -1
  103. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.d.ts.map +1 -1
  104. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.js +0 -10
  105. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.d.ts +2 -2
  106. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.d.ts.map +1 -1
  107. package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.js +3 -3
  108. package/node_modules/@oscharko-dev/keiko-local-knowledge/package.json +1 -1
  109. package/node_modules/@oscharko-dev/keiko-memory-capture/package.json +1 -1
  110. package/node_modules/@oscharko-dev/keiko-memory-consolidation/package.json +1 -1
  111. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/.tsbuildinfo +1 -1
  112. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/index.d.ts +1 -1
  113. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/index.d.ts.map +1 -1
  114. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/index.js +1 -1
  115. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/maintenance.d.ts +2 -16
  116. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/maintenance.d.ts.map +1 -1
  117. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/maintenance.js +49 -48
  118. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/retention.d.ts +2 -1
  119. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/retention.d.ts.map +1 -1
  120. package/node_modules/@oscharko-dev/keiko-memory-governance/dist/retention.js +15 -0
  121. package/node_modules/@oscharko-dev/keiko-memory-governance/package.json +1 -1
  122. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/.tsbuildinfo +1 -1
  123. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/decay.d.ts +2 -0
  124. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/decay.d.ts.map +1 -0
  125. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/decay.js +22 -0
  126. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/diversity.d.ts +8 -0
  127. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/diversity.d.ts.map +1 -0
  128. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/diversity.js +87 -0
  129. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/index.d.ts +4 -2
  130. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/index.d.ts.map +1 -1
  131. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/index.js +4 -1
  132. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/ranking.d.ts +5 -1
  133. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/ranking.d.ts.map +1 -1
  134. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/ranking.js +140 -21
  135. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/recency.d.ts.map +1 -1
  136. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/recency.js +4 -10
  137. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/retrieve.d.ts.map +1 -1
  138. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/retrieve.js +11 -1
  139. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/strength.d.ts +9 -0
  140. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/strength.d.ts.map +1 -0
  141. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/strength.js +51 -0
  142. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/types.d.ts +11 -0
  143. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/types.d.ts.map +1 -1
  144. package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/types.js +7 -0
  145. package/node_modules/@oscharko-dev/keiko-memory-retrieval/package.json +1 -1
  146. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/.tsbuildinfo +1 -1
  147. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/access.d.ts +3 -0
  148. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/access.d.ts.map +1 -1
  149. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/access.js +31 -1
  150. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/schema.d.ts +1 -1
  151. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/schema.d.ts.map +1 -1
  152. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/schema.js +16 -1
  153. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/types.d.ts +1 -0
  154. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/types.d.ts.map +1 -1
  155. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/vault.d.ts.map +1 -1
  156. package/node_modules/@oscharko-dev/keiko-memory-vault/dist/vault.js +4 -1
  157. package/node_modules/@oscharko-dev/keiko-memory-vault/package.json +1 -1
  158. package/node_modules/@oscharko-dev/keiko-model-gateway/dist/.tsbuildinfo +1 -1
  159. package/node_modules/@oscharko-dev/keiko-model-gateway/package.json +1 -1
  160. package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/.tsbuildinfo +1 -1
  161. package/node_modules/@oscharko-dev/keiko-quality-intelligence/package.json +1 -1
  162. package/node_modules/@oscharko-dev/keiko-sdk/dist/.tsbuildinfo +1 -1
  163. package/node_modules/@oscharko-dev/keiko-sdk/package.json +1 -1
  164. package/node_modules/@oscharko-dev/keiko-security/dist/.tsbuildinfo +1 -1
  165. package/node_modules/@oscharko-dev/keiko-security/package.json +1 -1
  166. package/node_modules/@oscharko-dev/keiko-server/dist/.tsbuildinfo +1 -1
  167. package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.d.ts.map +1 -1
  168. package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.js +44 -65
  169. package/node_modules/@oscharko-dev/keiko-server/dist/deps.d.ts +2 -0
  170. package/node_modules/@oscharko-dev/keiko-server/dist/deps.d.ts.map +1 -1
  171. package/node_modules/@oscharko-dev/keiko-server/dist/deps.js +1 -0
  172. package/node_modules/@oscharko-dev/keiko-server/dist/gateway-setup.d.ts.map +1 -1
  173. package/node_modules/@oscharko-dev/keiko-server/dist/gateway-setup.js +305 -66
  174. package/node_modules/@oscharko-dev/keiko-server/dist/memory-conv-handlers.d.ts.map +1 -1
  175. package/node_modules/@oscharko-dev/keiko-server/dist/memory-conv-handlers.js +34 -5
  176. package/node_modules/@oscharko-dev/keiko-server/dist/memory-embedding.d.ts +12 -2
  177. package/node_modules/@oscharko-dev/keiko-server/dist/memory-embedding.d.ts.map +1 -1
  178. package/node_modules/@oscharko-dev/keiko-server/dist/memory-embedding.js +127 -0
  179. package/node_modules/@oscharko-dev/keiko-server/dist/memory-handlers.d.ts.map +1 -1
  180. package/node_modules/@oscharko-dev/keiko-server/dist/memory-handlers.js +40 -11
  181. package/node_modules/@oscharko-dev/keiko-server/dist/memory-maintenance-handlers.d.ts +16 -3
  182. package/node_modules/@oscharko-dev/keiko-server/dist/memory-maintenance-handlers.d.ts.map +1 -1
  183. package/node_modules/@oscharko-dev/keiko-server/dist/memory-maintenance-handlers.js +72 -50
  184. package/node_modules/@oscharko-dev/keiko-server/dist/memory-retrieval-signals.d.ts +12 -0
  185. package/node_modules/@oscharko-dev/keiko-server/dist/memory-retrieval-signals.d.ts.map +1 -0
  186. package/node_modules/@oscharko-dev/keiko-server/dist/memory-retrieval-signals.js +84 -0
  187. package/node_modules/@oscharko-dev/keiko-server/dist/memory-salience.d.ts.map +1 -1
  188. package/node_modules/@oscharko-dev/keiko-server/dist/memory-salience.js +11 -6
  189. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +15 -0
  190. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -1
  191. package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.js +105 -0
  192. package/node_modules/@oscharko-dev/keiko-server/dist/routes.d.ts.map +1 -1
  193. package/node_modules/@oscharko-dev/keiko-server/dist/routes.js +2 -1
  194. package/node_modules/@oscharko-dev/keiko-server/package.json +1 -1
  195. package/node_modules/@oscharko-dev/keiko-tools/dist/.tsbuildinfo +1 -1
  196. package/node_modules/@oscharko-dev/keiko-tools/package.json +1 -1
  197. package/node_modules/@oscharko-dev/keiko-verification/dist/.tsbuildinfo +1 -1
  198. package/node_modules/@oscharko-dev/keiko-verification/package.json +1 -1
  199. package/node_modules/@oscharko-dev/keiko-workflows/dist/.tsbuildinfo +1 -1
  200. package/node_modules/@oscharko-dev/keiko-workflows/package.json +1 -1
  201. package/node_modules/@oscharko-dev/keiko-workspace/dist/.tsbuildinfo +1 -1
  202. package/node_modules/@oscharko-dev/keiko-workspace/package.json +1 -1
  203. package/package.json +2 -1
  204. package/dist/ui/static/_next/static/chunks/0-qhhdvxg2j_y.js +0 -1
  205. package/dist/ui/static/_next/static/chunks/0ke4ratkgvcxo.css +0 -1
  206. package/dist/ui/static/_next/static/chunks/3vf3oh2-sl2nc.js +0 -1
  207. package/dist/ui/static/_next/static/chunks/3wmd4-2vznp2g.js +0 -106
  208. /package/dist/ui/static/_next/static/{frhs0YcUqCPLHal-wHjDP → Ppze_8n_i3yc1FS_Qdj0I}/_buildManifest.js +0 -0
  209. /package/dist/ui/static/_next/static/{frhs0YcUqCPLHal-wHjDP → Ppze_8n_i3yc1FS_Qdj0I}/_clientMiddlewareManifest.js +0 -0
  210. /package/dist/ui/static/_next/static/{frhs0YcUqCPLHal-wHjDP → Ppze_8n_i3yc1FS_Qdj0I}/_ssgManifest.js +0 -0
@@ -9,7 +9,9 @@ import { apiKeyHeaderValue, ConfigInvalidError, DEFAULT_API_KEY_HEADER_NAME, Gat
9
9
  import { gatewayFetch, readJsonCapped } from "@oscharko-dev/keiko-model-gateway/internal/http";
10
10
  import { redact } from "@oscharko-dev/keiko-security";
11
11
  import { errorBody } from "./routes.js";
12
- import { currentGatewayEgressConfig } from "./deps.js";
12
+ import { currentGatewayConfig, currentGatewayEgressConfig } from "./deps.js";
13
+ import { classifyFigmaTransportError, FigmaConnectorError, } from "./qualityIntelligence/figma/figmaConnectorErrors.js";
14
+ import { classifyTokenFailure } from "./qualityIntelligence/figma/figmaTokenSource.js";
13
15
  const MAX_BODY_BYTES = 64_000;
14
16
  // Issue #144: exported so discovery-normalization tests can pin the slice cap
15
17
  // without hardcoding the number. The discovery surface is a public seam.
@@ -18,6 +20,8 @@ const MAX_DEPLOYMENT_NAMES = 100;
18
20
  const MAX_MODEL_ID_LENGTH = 160;
19
21
  const DISCOVERED_MODEL_SMOKE_TIMEOUT_MS = 15_000;
20
22
  const DEPLOYMENT_SMOKE_TIMEOUT_MS = 30_000;
23
+ const FIGMA_CREDENTIAL_SMOKE_TIMEOUT_MS = 15_000;
24
+ const FIGMA_CREDENTIAL_SMOKE_RESPONSE_BYTES = 64_000;
21
25
  const SETUP_SMOKE_CONCURRENCY = 4;
22
26
  const CHAT_COMPATIBLE_MODES = new Set(["chat", "completion", "responses"]);
23
27
  const EMBEDDING_ID_PATTERN = /(?:^|[-_/. ])(?:text-)?embed(?:ding)?s?(?:[-_/. ]|$)|ada-002(?:$|[-_/. ])/i;
@@ -113,7 +117,7 @@ function providerRaw(modelId, baseUrl, apiKey, options = {}) {
113
117
  : defaultCapability,
114
118
  timeoutMs: options.timeoutMs ?? 30_000,
115
119
  maxRetries: options.maxRetries ?? 2,
116
- retryBaseDelayMs: 500,
120
+ retryBaseDelayMs: options.retryBaseDelayMs ?? 500,
117
121
  };
118
122
  }
119
123
  function isLikelyEmbeddingModelId(modelId) {
@@ -161,6 +165,32 @@ function buildRawConfig(baseUrl, apiKey, modelIds, options = {}) {
161
165
  circuitBreaker: { failureThreshold: 5, cooldownMs: 30_000, halfOpenProbes: 2 },
162
166
  };
163
167
  }
168
+ function currentImageInputModelIds(config) {
169
+ return (config?.capabilities
170
+ ?.filter((capability) => capability.kind === "chat" && capability.supportsImageInput)
171
+ .map((capability) => capability.id) ?? []);
172
+ }
173
+ function rawConfigFromCurrent(config, figmaAccessToken) {
174
+ return {
175
+ providers: config.providers.map((provider) => {
176
+ const capability = config.capabilities?.find((item) => item.id === provider.modelId);
177
+ return {
178
+ modelId: provider.modelId,
179
+ baseUrl: provider.baseUrl,
180
+ apiKey: provider.apiKey,
181
+ apiKeyHeaderName: provider.apiKeyHeaderName ?? DEFAULT_API_KEY_HEADER_NAME,
182
+ timeoutMs: provider.timeoutMs,
183
+ maxRetries: provider.maxRetries,
184
+ retryBaseDelayMs: provider.retryBaseDelayMs,
185
+ ...(capability === undefined ? {} : { capability }),
186
+ };
187
+ }),
188
+ circuitBreaker: config.circuitBreaker,
189
+ ...(config.capabilities === undefined ? {} : { capabilities: config.capabilities }),
190
+ ...(config.grounding === undefined ? {} : { grounding: config.grounding }),
191
+ ...(figmaAccessToken === undefined ? {} : { figma: { accessToken: figmaAccessToken } }),
192
+ };
193
+ }
164
194
  function withInheritedEgress(rawConfig, egress) {
165
195
  if (egress === undefined || Object.hasOwn(rawConfig, "egress")) {
166
196
  return rawConfig;
@@ -424,6 +454,46 @@ async function defaultGatewaySetupTester(config, candidateModelIds) {
424
454
  });
425
455
  }, SETUP_SMOKE_CONCURRENCY);
426
456
  }
457
+ const FIGMA_ME_ENDPOINT = "https://api.figma.com/v1/me";
458
+ function figmaReason(body) {
459
+ if (!isRecord(body))
460
+ return undefined;
461
+ const reason = body.err ?? body.message;
462
+ return typeof reason === "string" ? reason : undefined;
463
+ }
464
+ async function defaultFigmaCredentialTester(accessToken, egress) {
465
+ try {
466
+ const response = await gatewayFetch(FIGMA_ME_ENDPOINT, {
467
+ method: "GET",
468
+ headers: {
469
+ Accept: "application/json",
470
+ "X-Figma-Token": accessToken,
471
+ },
472
+ redirect: "manual",
473
+ signal: AbortSignal.timeout(FIGMA_CREDENTIAL_SMOKE_TIMEOUT_MS),
474
+ ...(egress !== undefined ? { egress } : {}),
475
+ });
476
+ let body;
477
+ try {
478
+ body = await readJsonCapped(response, FIGMA_CREDENTIAL_SMOKE_RESPONSE_BYTES);
479
+ }
480
+ catch {
481
+ throw new FigmaConnectorError("FIGMA_RESPONSE_TOO_LARGE");
482
+ }
483
+ if (!response.ok) {
484
+ throw classifyTokenFailure(response.status, figmaReason(body));
485
+ }
486
+ if (!isRecord(body)) {
487
+ throw new FigmaConnectorError("FIGMA_INTERNAL");
488
+ }
489
+ }
490
+ catch (error) {
491
+ if (error instanceof FigmaConnectorError) {
492
+ throw error;
493
+ }
494
+ throw new FigmaConnectorError(classifyFigmaTransportError(error));
495
+ }
496
+ }
427
497
  function savePrivateJson(path, raw) {
428
498
  const resolvedPath = resolve(path);
429
499
  const dir = dirname(resolvedPath);
@@ -498,39 +568,111 @@ function readSetupModelLists(raw) {
498
568
  }
499
569
  return { deploymentNames, imageInputModelIds };
500
570
  }
501
- function readSetupRequest(raw, env) {
502
- if (!isRecord(raw)) {
503
- return { status: 400, body: errorBody("BAD_REQUEST", "Request body must be a JSON object.") };
571
+ function optionalSetupSecret(value, path) {
572
+ if (value === undefined) {
573
+ return undefined;
574
+ }
575
+ if (typeof value !== "string") {
576
+ return { status: 400, body: errorBody("BAD_REQUEST", `${path} must be a string.`) };
577
+ }
578
+ const trimmed = value.trim();
579
+ return trimmed.length === 0 ? undefined : trimmed;
580
+ }
581
+ function hasNonBlankStringField(raw, key) {
582
+ const value = raw[key];
583
+ return typeof value === "string" && value.trim().length > 0;
584
+ }
585
+ function hasNonEmptyListField(raw, key) {
586
+ const value = raw[key];
587
+ if (typeof value === "string") {
588
+ return normalizeDeploymentNames(deploymentNameValues(value) ?? []).length > 0;
589
+ }
590
+ return Array.isArray(value) && value.some((item) => typeof item === "string" && item.trim());
591
+ }
592
+ function shouldPreserveExisting(raw, current) {
593
+ return raw.preserveExisting === true && current !== undefined;
594
+ }
595
+ function firstProvider(current) {
596
+ return current?.providers[0];
597
+ }
598
+ function trimmedSubmittedString(raw, key) {
599
+ const value = raw[key];
600
+ if (typeof value !== "string")
601
+ return undefined;
602
+ const trimmed = value.trim();
603
+ return trimmed.length === 0 ? undefined : trimmed;
604
+ }
605
+ function submittedOrInheritedString(raw, key, inherited, preserveExisting) {
606
+ return trimmedSubmittedString(raw, key) ?? (preserveExisting ? (inherited ?? "") : "");
607
+ }
608
+ function setupApiKeyHeaderSource(raw, provider, preserveExisting) {
609
+ if (raw.apiKeyHeaderName !== undefined || !preserveExisting) {
610
+ return raw.apiKeyHeaderName;
504
611
  }
505
- const baseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl.trim() : "";
506
- const apiKey = typeof raw.apiKey === "string" ? raw.apiKey.trim() : "";
612
+ return provider?.apiKeyHeaderName ?? DEFAULT_API_KEY_HEADER_NAME;
613
+ }
614
+ function readSetupGatewayCredentials(raw, env, current, preserveExisting) {
615
+ const provider = firstProvider(current);
616
+ const baseUrl = submittedOrInheritedString(raw, "baseUrl", provider?.baseUrl, preserveExisting);
617
+ const apiKey = submittedOrInheritedString(raw, "apiKey", provider?.apiKey, preserveExisting);
507
618
  if (baseUrl.length === 0 || apiKey.length === 0) {
508
619
  return { status: 400, body: errorBody("BAD_REQUEST", "baseUrl and apiKey are required.") };
509
620
  }
510
- const apiKeyHeaderName = normalizeSetupApiKeyHeaderName(raw.apiKeyHeaderName);
621
+ const apiKeyHeaderSource = setupApiKeyHeaderSource(raw, provider, preserveExisting);
622
+ const apiKeyHeaderName = normalizeSetupApiKeyHeaderName(apiKeyHeaderSource);
511
623
  if (isRouteResult(apiKeyHeaderName)) {
512
624
  return apiKeyHeaderName;
513
625
  }
626
+ const invalidConnection = validateSetupConnection(baseUrl, apiKey, apiKeyHeaderName, env);
627
+ if (invalidConnection !== undefined) {
628
+ return invalidConnection;
629
+ }
630
+ return { baseUrl, apiKey, apiKeyHeaderName };
631
+ }
632
+ function resolveSetupModelLists(modelLists, current, preserveExisting) {
633
+ const existing = preserveExisting ? current : undefined;
634
+ return {
635
+ deploymentNames: existing !== undefined && modelLists.deploymentNames.length === 0
636
+ ? existing.providers.map((item) => item.modelId)
637
+ : modelLists.deploymentNames,
638
+ imageInputModelIds: existing !== undefined && modelLists.imageInputModelIds.length === 0
639
+ ? currentImageInputModelIds(existing)
640
+ : modelLists.imageInputModelIds,
641
+ };
642
+ }
643
+ function setupRequiresGatewayVerification(raw, preserveExisting) {
644
+ return (!preserveExisting ||
645
+ hasNonBlankStringField(raw, "baseUrl") ||
646
+ hasNonBlankStringField(raw, "apiKey") ||
647
+ hasNonBlankStringField(raw, "apiKeyHeaderName") ||
648
+ hasNonEmptyListField(raw, "deploymentNames") ||
649
+ hasNonEmptyListField(raw, "imageInputModelIds"));
650
+ }
651
+ function readSetupRequest(raw, env, current) {
652
+ if (!isRecord(raw)) {
653
+ return { status: 400, body: errorBody("BAD_REQUEST", "Request body must be a JSON object.") };
654
+ }
655
+ const preserveExisting = shouldPreserveExisting(raw, current);
656
+ const credentials = readSetupGatewayCredentials(raw, env, current, preserveExisting);
657
+ if (isRouteResult(credentials)) {
658
+ return credentials;
659
+ }
514
660
  const modelLists = readSetupModelLists(raw);
515
661
  if (isRouteResult(modelLists)) {
516
662
  return modelLists;
517
663
  }
518
- if (Object.hasOwn(raw, "figmaAccessToken")) {
519
- return {
520
- status: 400,
521
- body: errorBody("BAD_REQUEST", "Figma access tokens must be configured server-side, not through gateway setup."),
522
- };
523
- }
524
- const invalidConnection = validateSetupConnection(baseUrl, apiKey, apiKeyHeaderName, env);
525
- if (invalidConnection !== undefined) {
526
- return invalidConnection;
664
+ const figmaAccessToken = optionalSetupSecret(raw.figmaAccessToken, "figmaAccessToken");
665
+ if (isRouteResult(figmaAccessToken)) {
666
+ return figmaAccessToken;
527
667
  }
668
+ const resolvedModelLists = resolveSetupModelLists(modelLists, current, preserveExisting);
528
669
  return {
529
- baseUrl,
530
- apiKey,
531
- apiKeyHeaderName,
532
- deploymentNames: modelLists.deploymentNames,
533
- imageInputModelIds: modelLists.imageInputModelIds,
670
+ ...credentials,
671
+ deploymentNames: resolvedModelLists.deploymentNames,
672
+ imageInputModelIds: resolvedModelLists.imageInputModelIds,
673
+ figmaAccessToken: figmaAccessToken ?? current?.figma?.accessToken,
674
+ verifyGateway: setupRequiresGatewayVerification(raw, preserveExisting),
675
+ verifyFigmaCredential: figmaAccessToken !== undefined,
534
676
  };
535
677
  }
536
678
  function safeError(error, secrets) {
@@ -548,37 +690,55 @@ function assertImageInputModelsWereTested(imageInputModelIds, testedModelIds) {
548
690
  throw new Error("imageInputModelIds must match tested chat-callable model ids.");
549
691
  }
550
692
  }
551
- async function verifySetupCandidate(baseUrl, apiKey, apiKeyHeaderName, deploymentNames, imageInputModelIds, tester, discovery, env, egress) {
693
+ function validationConfigForSetup(input) {
694
+ const validationRawConfig = buildRawConfig(input.baseUrl, input.apiKey, ["setup-validation"], {
695
+ apiKeyHeaderName: input.apiKeyHeaderName,
696
+ imageInputModelIds: input.imageInputModelIds,
697
+ });
698
+ return parseGatewayConfig(withInheritedEgress(validationRawConfig, input.egress), input.env);
699
+ }
700
+ async function candidateModelIdsForSetup(input, validationConfig) {
701
+ return input.deploymentNames.length > 0
702
+ ? input.deploymentNames
703
+ : input.discovery(input.baseUrl, input.apiKey, input.apiKeyHeaderName, validationConfig.egress);
704
+ }
705
+ function finalRawConfigForSetup(input, testedModelIds) {
706
+ const embeddingModelIds = embeddingModelIdsFromDeployments(input.deploymentNames);
707
+ const configuredModelIds = mergeChatAndEmbeddingModelIds(testedModelIds, input.deploymentNames);
708
+ const rawConfig = buildRawConfig(input.baseUrl, input.apiKey, configuredModelIds, {
709
+ apiKeyHeaderName: input.apiKeyHeaderName,
710
+ imageInputModelIds: input.imageInputModelIds,
711
+ embeddingModelIds,
712
+ });
713
+ return {
714
+ ...rawConfig,
715
+ ...(input.current?.grounding === undefined ? {} : { grounding: input.current.grounding }),
716
+ ...(input.figmaAccessToken === undefined
717
+ ? {}
718
+ : { figma: { accessToken: input.figmaAccessToken } }),
719
+ };
720
+ }
721
+ async function verifySetupCandidate(input) {
552
722
  // Defence-in-depth: never send the credential to a candidate URL that has not passed the same
553
723
  // scheme/credential/loopback validation as the originally submitted base URL.
554
- validateBaseUrl(baseUrl, "candidate");
555
- const validationRawConfig = buildRawConfig(baseUrl, apiKey, ["setup-validation"], {
556
- apiKeyHeaderName,
557
- imageInputModelIds,
558
- });
559
- const validationConfig = parseGatewayConfig(withInheritedEgress(validationRawConfig, egress), env);
560
- const candidateModelIds = deploymentNames.length > 0
561
- ? deploymentNames
562
- : await discovery(baseUrl, apiKey, apiKeyHeaderName, validationConfig.egress);
563
- const smokeTimeoutMs = deploymentNames.length > 0 ? DEPLOYMENT_SMOKE_TIMEOUT_MS : DISCOVERED_MODEL_SMOKE_TIMEOUT_MS;
564
- const candidateRawConfig = buildRawConfig(baseUrl, apiKey, candidateModelIds, {
565
- apiKeyHeaderName,
724
+ validateBaseUrl(input.baseUrl, "candidate");
725
+ const validationConfig = validationConfigForSetup(input);
726
+ const candidateModelIds = await candidateModelIdsForSetup(input, validationConfig);
727
+ const smokeTimeoutMs = input.deploymentNames.length > 0
728
+ ? DEPLOYMENT_SMOKE_TIMEOUT_MS
729
+ : DISCOVERED_MODEL_SMOKE_TIMEOUT_MS;
730
+ const candidateRawConfig = buildRawConfig(input.baseUrl, input.apiKey, candidateModelIds, {
731
+ apiKeyHeaderName: input.apiKeyHeaderName,
566
732
  timeoutMs: smokeTimeoutMs,
567
733
  maxRetries: 0,
568
- imageInputModelIds,
569
- });
570
- const candidateConfig = parseGatewayConfig(withInheritedEgress(candidateRawConfig, egress), env);
571
- const testedModelIds = await tester(candidateConfig, candidateModelIds);
572
- assertImageInputModelsWereTested(imageInputModelIds, testedModelIds);
573
- const embeddingModelIds = embeddingModelIdsFromDeployments(deploymentNames);
574
- const configuredModelIds = mergeChatAndEmbeddingModelIds(testedModelIds, deploymentNames);
575
- const rawConfig = buildRawConfig(baseUrl, apiKey, configuredModelIds, {
576
- apiKeyHeaderName,
577
- imageInputModelIds,
578
- embeddingModelIds,
734
+ imageInputModelIds: input.imageInputModelIds,
579
735
  });
580
- const config = parseGatewayConfig(withInheritedEgress(rawConfig, egress), env);
581
- return { rawConfig, config, testedModelIds };
736
+ const candidateConfig = parseGatewayConfig(withInheritedEgress(candidateRawConfig, input.egress), input.env);
737
+ const testedModelIds = await input.tester(candidateConfig, candidateModelIds);
738
+ assertImageInputModelsWereTested(input.imageInputModelIds, testedModelIds);
739
+ const rawConfigWithOptionalBlocks = finalRawConfigForSetup(input, testedModelIds);
740
+ const config = parseGatewayConfig(withInheritedEgress(rawConfigWithOptionalBlocks, input.egress), input.env);
741
+ return { rawConfig: rawConfigWithOptionalBlocks, config, testedModelIds };
582
742
  }
583
743
  function setupSuccessResult(config, testedModelIds) {
584
744
  const testedModelId = testedModelIds[0] ?? "unknown";
@@ -600,6 +760,45 @@ function setupFailureResult(errors) {
600
760
  body: errorBody("GATEWAY_SETUP_FAILED", `Credentials could not be verified. ${errors.join(" ")}`),
601
761
  };
602
762
  }
763
+ function figmaFailureStatus(code) {
764
+ switch (code) {
765
+ case "FIGMA_TOKEN_INVALID":
766
+ case "FIGMA_TOKEN_EXPIRED":
767
+ case "FIGMA_TOKEN_REVOKED":
768
+ case "FIGMA_INSUFFICIENT_SCOPE":
769
+ case "FIGMA_CONSENT_REQUIRED":
770
+ return 400;
771
+ case "FIGMA_RATE_LIMITED":
772
+ return 429;
773
+ default:
774
+ return 502;
775
+ }
776
+ }
777
+ function figmaCredentialFailureResult(error, request) {
778
+ if (error instanceof FigmaConnectorError) {
779
+ return {
780
+ status: figmaFailureStatus(error.code),
781
+ body: errorBody(error.code, error.message),
782
+ };
783
+ }
784
+ return {
785
+ status: 502,
786
+ body: errorBody("FIGMA_EGRESS_FAILED", safeError(error, [request.figmaAccessToken, request.apiKey, request.baseUrl])),
787
+ };
788
+ }
789
+ async function verifySubmittedFigmaCredential(request, deps) {
790
+ if (!request.verifyFigmaCredential || request.figmaAccessToken === undefined) {
791
+ return undefined;
792
+ }
793
+ const tester = deps.figmaCredentialTester ?? defaultFigmaCredentialTester;
794
+ try {
795
+ await tester(request.figmaAccessToken, currentGatewayEgressConfig(deps));
796
+ return undefined;
797
+ }
798
+ catch (error) {
799
+ return figmaCredentialFailureResult(error, request);
800
+ }
801
+ }
603
802
  function deploymentNamesRequiredResult() {
604
803
  return {
605
804
  status: 400,
@@ -633,39 +832,60 @@ function gatewayUnavailableResult() {
633
832
  body: errorBody("GATEWAY_SETUP_UNAVAILABLE", "Gateway setup is unavailable."),
634
833
  };
635
834
  }
636
- async function trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery) {
637
- const verified = await verifySetupCandidate(baseUrl, request.apiKey, request.apiKeyHeaderName, request.deploymentNames, request.imageInputModelIds, tester, discovery, deps.env, currentGatewayEgressConfig(deps));
835
+ async function trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery, current) {
836
+ const verified = await verifySetupCandidate({
837
+ baseUrl,
838
+ apiKey: request.apiKey,
839
+ apiKeyHeaderName: request.apiKeyHeaderName,
840
+ deploymentNames: request.deploymentNames,
841
+ imageInputModelIds: request.imageInputModelIds,
842
+ tester,
843
+ discovery,
844
+ env: deps.env,
845
+ egress: currentGatewayEgressConfig(deps),
846
+ figmaAccessToken: request.figmaAccessToken,
847
+ current,
848
+ });
638
849
  savePrivateJson(gatewayConfig.storagePath, verified.rawConfig);
639
850
  gatewayConfig.set(verified.config, true);
640
851
  return setupSuccessResult(verified.config, verified.testedModelIds);
641
852
  }
642
853
  function setupCandidateError(error, request, baseUrl) {
643
- return safeError(error, [request.apiKey, request.baseUrl, baseUrl]);
854
+ return safeError(error, [request.apiKey, request.baseUrl, baseUrl, request.figmaAccessToken]);
644
855
  }
645
- export async function handleGatewaySetup(ctx, deps) {
646
- if (deps.gatewayConfig === undefined) {
647
- return gatewayUnavailableResult();
648
- }
649
- const { gatewayConfig } = deps;
650
- const bodyResult = await readJsonSetupBody(ctx);
651
- if ("status" in bodyResult) {
652
- return bodyResult;
653
- }
654
- const request = readSetupRequest(bodyResult.parsed, deps.env);
655
- if ("status" in request) {
656
- return request;
856
+ function saveExistingConfigUpdate(request, current, deps, gatewayConfig) {
857
+ const rawConfig = rawConfigFromCurrent(current, request.figmaAccessToken);
858
+ const config = parseGatewayConfig(withInheritedEgress(rawConfig, currentGatewayEgressConfig(deps)), deps.env);
859
+ savePrivateJson(gatewayConfig.storagePath, rawConfig);
860
+ gatewayConfig.set(config, true);
861
+ return setupSuccessResult(config, config.providers.map((provider) => provider.modelId));
862
+ }
863
+ async function verifyAndSaveExistingConfigUpdate(request, current, deps, gatewayConfig) {
864
+ const figmaFailure = await verifySubmittedFigmaCredential(request, deps);
865
+ if (figmaFailure !== undefined) {
866
+ return figmaFailure;
657
867
  }
868
+ return saveExistingConfigUpdate(request, current, deps, gatewayConfig);
869
+ }
870
+ function shouldRequireDeploymentNames(request, baseUrlCandidates) {
871
+ return (request.deploymentNames.length === 0 &&
872
+ baseUrlCandidates.some((baseUrl) => isAzureFoundryBaseUrl(baseUrl)));
873
+ }
874
+ async function verifyAndSaveGatewaySetup(request, current, deps, gatewayConfig) {
658
875
  const tester = deps.gatewaySetupTester ?? defaultGatewaySetupTester;
659
876
  const discovery = deps.gatewayModelDiscovery ?? defaultGatewayModelDiscovery;
877
+ const figmaFailure = await verifySubmittedFigmaCredential(request, deps);
878
+ if (figmaFailure !== undefined) {
879
+ return figmaFailure;
880
+ }
660
881
  const baseUrlCandidates = candidateBaseUrls(request.baseUrl);
661
- if (request.deploymentNames.length === 0 &&
662
- baseUrlCandidates.some((baseUrl) => isAzureFoundryBaseUrl(baseUrl))) {
882
+ if (shouldRequireDeploymentNames(request, baseUrlCandidates)) {
663
883
  return deploymentNamesRequiredResult();
664
884
  }
665
885
  const errors = [];
666
886
  for (const baseUrl of baseUrlCandidates) {
667
887
  try {
668
- return await trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery);
888
+ return await trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery, current);
669
889
  }
670
890
  catch (error) {
671
891
  errors.push(`candidate ${String(errors.length + 1)}: ${setupCandidateError(error, request, baseUrl)}`);
@@ -673,3 +893,22 @@ export async function handleGatewaySetup(ctx, deps) {
673
893
  }
674
894
  return setupFailureResult(errors);
675
895
  }
896
+ export async function handleGatewaySetup(ctx, deps) {
897
+ if (deps.gatewayConfig === undefined) {
898
+ return gatewayUnavailableResult();
899
+ }
900
+ const { gatewayConfig } = deps;
901
+ const current = currentGatewayConfig(deps);
902
+ const bodyResult = await readJsonSetupBody(ctx);
903
+ if ("status" in bodyResult) {
904
+ return bodyResult;
905
+ }
906
+ const request = readSetupRequest(bodyResult.parsed, deps.env, current);
907
+ if ("status" in request) {
908
+ return request;
909
+ }
910
+ if (!request.verifyGateway && current !== undefined) {
911
+ return verifyAndSaveExistingConfigUpdate(request, current, deps, gatewayConfig);
912
+ }
913
+ return verifyAndSaveGatewaySetup(request, current, deps, gatewayConfig);
914
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"memory-conv-handlers.d.ts","sourceRoot":"","sources":["../src/memory-conv-handlers.ts"],"names":[],"mappings":"AA0BA,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,sCAAsC,CAAC;AAe9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA6G7D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,eAAe,CAezE;AA8FD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CAyCtB;AAkED,wBAAsB,mCAAmC,CACvD,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CA0BtB"}
1
+ {"version":3,"file":"memory-conv-handlers.d.ts","sourceRoot":"","sources":["../src/memory-conv-handlers.ts"],"names":[],"mappings":"AA0BA,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,sCAAsC,CAAC;AAgB9C,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAkH7D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,GAAG,eAAe,CAezE;AAgJD,wBAAsB,2BAA2B,CAC/C,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CAwCtB;AAkED,wBAAsB,mCAAmC,CACvD,GAAG,EAAE,YAAY,EACjB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,WAAW,CAAC,CA0BtB"}
@@ -23,7 +23,7 @@
23
23
  // File budget: keep under 400 LOC per coordinator quality rules.
24
24
  import { randomUUID } from "node:crypto";
25
25
  import { retrieveMemoryContext, } from "@oscharko-dev/keiko-memory-retrieval";
26
- import { extractCandidatesFromUserText, } from "@oscharko-dev/keiko-memory-capture";
26
+ import { extractCandidatesFromUserText, memoryTextEgressRejectionReason, } from "@oscharko-dev/keiko-memory-capture";
27
27
  import { MEMORY_TYPES } from "@oscharko-dev/keiko-contracts";
28
28
  import { errorBody } from "./routes.js";
29
29
  import { createMemoryTargetResolver } from "./memory-target-resolver.js";
@@ -31,6 +31,7 @@ import { conversationMemoryScopes, resolveConversationMemoryContext, } from "./m
31
31
  import { recordMemoryAudit } from "./memory-audit-handler.js";
32
32
  import { buildMemoryRecordFromProposal } from "./memory-record-builders.js";
33
33
  import { enforcePersistableMemoryOutcome, isPersistableMemoryCandidate, memoryCapturePolicyForDeps, } from "./memory-capture-policy.js";
34
+ import { buildConversationRetrievalSignals, conversationFusionMode, } from "./memory-retrieval-signals.js";
34
35
  // ─── Constants ────────────────────────────────────────────────────────────────
35
36
  const MAX_BODY_BYTES = 64_000;
36
37
  // ─── Body reading (mirrors memory-handlers.ts pattern) ────────────────────────
@@ -197,11 +198,12 @@ function parseContextInput(raw) {
197
198
  budgetTokens: budgetTokens ?? undefined,
198
199
  };
199
200
  }
200
- function buildRetrievalRequest(scopes, input) {
201
+ function buildRetrievalRequest(scopes, input, nowMs, signals, fusion) {
201
202
  // exactOptionalPropertyTypes: omit undefined fields instead of assigning them.
202
203
  const req = {
203
204
  scopes,
204
- nowMs: Date.now(),
205
+ nowMs,
206
+ fusion,
205
207
  };
206
208
  if (input.queryText !== undefined)
207
209
  req.queryText = input.queryText;
@@ -209,8 +211,36 @@ function buildRetrievalRequest(scopes, input) {
209
211
  req.types = input.types;
210
212
  if (input.budgetTokens !== undefined)
211
213
  req.budgetTokens = input.budgetTokens;
214
+ // Embedding-cosine (#204, O-F4), reinforcement (O-P1), and MMR-diversity (O-F3) signals, same as
215
+ // the chat path. Passed only when present so a vault with no embeddings / no access history ranks
216
+ // byte-identically.
217
+ if (signals.semanticById !== undefined)
218
+ req.semanticById = signals.semanticById;
219
+ if (signals.strengthById.size > 0)
220
+ req.strengthById = signals.strengthById;
221
+ if (signals.embeddingById.size > 0)
222
+ req.embeddingById = signals.embeddingById;
212
223
  return req;
213
224
  }
225
+ // Builds the embedding + reinforcement signals, runs scoped retrieval, and records the reinforcement
226
+ // reflex — the same pipeline the chat path uses. Extracted so the route handler stays a thin
227
+ // parse/dispatch/audit shell.
228
+ async function retrieveConversationMemory(deps, vault, scopes, input) {
229
+ const port = vaultAsQueryPort(vault);
230
+ const nowMs = Date.now();
231
+ // Embedding egress gate (#204, O-F4): only send the query to the secondary embedding model when it
232
+ // is not secret-shaped — matching the chat path's safeForSecondaryModel guard.
233
+ const safeForSecondaryModel = input.queryText === undefined ||
234
+ memoryTextEgressRejectionReason(input.queryText, memoryCapturePolicyForDeps(deps)) === null;
235
+ const signals = await buildConversationRetrievalSignals(deps, vault, input.queryText, scopes, nowMs, safeForSecondaryModel);
236
+ const result = retrieveMemoryContext(buildRetrievalRequest(scopes, input, nowMs, signals, conversationFusionMode(deps)), port);
237
+ // Reinforcement reflex (#204, O-P1): every recall is an access, same as the chat path.
238
+ const accessedIds = result.included.map((item) => item.memoryId);
239
+ if (accessedIds.length > 0) {
240
+ vault.recordAccess(accessedIds, Date.now());
241
+ }
242
+ return result;
243
+ }
214
244
  export async function handleMemoryRetrieveContext(ctx, deps) {
215
245
  const vault = resolveVault(deps);
216
246
  if (isRouteResult(vault))
@@ -225,8 +255,7 @@ export async function handleMemoryRetrieveContext(ctx, deps) {
225
255
  if (isRouteResult(context))
226
256
  return context;
227
257
  const scopes = conversationMemoryScopes(context);
228
- const port = vaultAsQueryPort(vault);
229
- const result = retrieveMemoryContext(buildRetrievalRequest(scopes, input), port);
258
+ const result = await retrieveConversationMemory(deps, vault, scopes, input);
230
259
  if (result.included.length > 0) {
231
260
  const event = {
232
261
  schemaVersion: "1",
@@ -1,6 +1,6 @@
1
1
  import { type GatewayConfig, type OpenAIEmbeddingOutcome, type OpenAIEmbeddingRequest } from "@oscharko-dev/keiko-model-gateway";
2
- import type { MemoryId } from "@oscharko-dev/keiko-contracts/memory";
3
- import type { MemoryEmbeddingInput, MemoryVaultStore } from "@oscharko-dev/keiko-memory-vault";
2
+ import type { MemoryId, MemoryRecord } from "@oscharko-dev/keiko-contracts/memory";
3
+ import type { MemoryEmbeddingInput, MemoryEmbeddingRow, MemoryVaultStore } from "@oscharko-dev/keiko-memory-vault";
4
4
  import { type UiHandlerDeps } from "./deps.js";
5
5
  export declare function selectMemoryEmbeddingModelId(config: GatewayConfig | undefined): string | undefined;
6
6
  export type MemoryEmbedder = (text: string) => Promise<MemoryEmbeddingInput | null>;
@@ -8,4 +8,14 @@ export declare function createMemoryEmbedder(config: GatewayConfig | undefined,
8
8
  export declare function embedMemoryText(deps: UiHandlerDeps, text: string): Promise<MemoryEmbeddingInput | null>;
9
9
  export declare function embedAndStoreMemory(deps: UiHandlerDeps, vault: MemoryVaultStore, memoryId: MemoryId, text: string): Promise<void>;
10
10
  export declare function cosineSimilarity(a: Float32Array, b: Float32Array): number;
11
+ export declare const SEMANTIC_DEDUP_COSINE_THRESHOLD = 0.95;
12
+ export declare function findSemanticDuplicate(candidate: MemoryEmbeddingInput | null, neighbors: ReadonlyMap<MemoryId, MemoryEmbeddingRow>, threshold?: number): MemoryId | null;
13
+ export declare const RELATED_LINK_COSINE_THRESHOLD = 0.82;
14
+ export declare const MAX_AUTO_LINKS = 3;
15
+ export declare function findRelatedNeighbors(candidate: MemoryEmbeddingInput | null, neighbors: ReadonlyMap<MemoryId, MemoryEmbeddingRow>, lower?: number, upper?: number, maxLinks?: number): readonly MemoryId[];
16
+ export interface NoveltyInsertResult {
17
+ readonly inserted: MemoryRecord | null;
18
+ readonly mergedInto: MemoryId | null;
19
+ }
20
+ export declare function insertSalienceMemoryWithNoveltyGate(deps: UiHandlerDeps, vault: MemoryVaultStore, record: MemoryRecord): Promise<NoveltyInsertResult>;
11
21
  //# sourceMappingURL=memory-embedding.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"memory-embedding.d.ts","sourceRoot":"","sources":["../src/memory-embedding.ts"],"names":[],"mappings":"AAgBA,OAAO,EAEL,KAAK,aAAa,EAGlB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,mCAAmC,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AACrE,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAC/F,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAIrE,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,MAAM,GAAG,SAAS,CAEpB;AAyDD,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;AAKpF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,WAAW,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,sBAAsB,CAAC,GAChF,cAAc,GAAG,IAAI,CAuBvB;AAKD,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAItC;AAKD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAQf;AAKD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAgBzE"}
1
+ {"version":3,"file":"memory-embedding.d.ts","sourceRoot":"","sources":["../src/memory-embedding.ts"],"names":[],"mappings":"AAgBA,OAAO,EAEL,KAAK,aAAa,EAGlB,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,EAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,KAAK,EAEV,QAAQ,EACR,YAAY,EAEb,MAAM,sCAAsC,CAAC;AAC9C,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,kCAAkC,CAAC;AAC1C,OAAO,EAAwB,KAAK,aAAa,EAAE,MAAM,WAAW,CAAC;AAIrE,wBAAgB,4BAA4B,CAC1C,MAAM,EAAE,aAAa,GAAG,SAAS,GAChC,MAAM,GAAG,SAAS,CAEpB;AAyDD,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAAC;AAKpF,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,aAAa,GAAG,SAAS,EACjC,WAAW,EAAE,CAAC,OAAO,EAAE,sBAAsB,KAAK,OAAO,CAAC,sBAAsB,CAAC,GAChF,cAAc,GAAG,IAAI,CAuBvB;AAKD,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC,CAItC;AAKD,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,gBAAgB,EACvB,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,IAAI,CAAC,CAQf;AAKD,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,YAAY,GAAG,MAAM,CAgBzE;AAiBD,eAAO,MAAM,+BAA+B,OAAO,CAAC;AAKpD,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,oBAAoB,GAAG,IAAI,EACtC,SAAS,EAAE,WAAW,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EACpD,SAAS,GAAE,MAAwC,GAClD,QAAQ,GAAG,IAAI,CAYjB;AAeD,eAAO,MAAM,6BAA6B,OAAO,CAAC;AAGlD,eAAO,MAAM,cAAc,IAAI,CAAC;AAMhC,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,oBAAoB,GAAG,IAAI,EACtC,SAAS,EAAE,WAAW,CAAC,QAAQ,EAAE,kBAAkB,CAAC,EACpD,KAAK,GAAE,MAAsC,EAC7C,KAAK,GAAE,MAAwC,EAC/C,QAAQ,GAAE,MAAuB,GAChC,SAAS,QAAQ,EAAE,CAWrB;AA+CD,MAAM,WAAW,mBAAmB;IAElC,QAAQ,CAAC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAC;IAEvC,QAAQ,CAAC,UAAU,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtC;AAOD,wBAAsB,mCAAmC,CACvD,IAAI,EAAE,aAAa,EACnB,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,mBAAmB,CAAC,CAoB9B"}