@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.
- package/dist/ui/csp-hashes.json +14 -14
- package/dist/ui/static/404.html +1 -1
- package/dist/ui/static/__next.__PAGE__.txt +2 -2
- package/dist/ui/static/__next._full.txt +3 -3
- package/dist/ui/static/__next._head.txt +1 -1
- package/dist/ui/static/__next._index.txt +2 -2
- package/dist/ui/static/__next._tree.txt +2 -2
- package/dist/ui/static/_next/static/chunks/0i3jzgrj42so8.css +1 -0
- package/dist/ui/static/_next/static/chunks/1ru_021szp0u7.js +1 -0
- package/dist/ui/static/_next/static/chunks/1t7vb5d9ed2e7.js +1 -0
- package/dist/ui/static/_next/static/chunks/23o2c6pyjq92z.js +109 -0
- package/dist/ui/static/_not-found/__next._full.txt +2 -2
- package/dist/ui/static/_not-found/__next._head.txt +1 -1
- package/dist/ui/static/_not-found/__next._index.txt +2 -2
- package/dist/ui/static/_not-found/__next._not-found.__PAGE__.txt +1 -1
- package/dist/ui/static/_not-found/__next._not-found.txt +1 -1
- package/dist/ui/static/_not-found/__next._tree.txt +2 -2
- package/dist/ui/static/_not-found.html +1 -1
- package/dist/ui/static/_not-found.txt +2 -2
- package/dist/ui/static/fonts/OFL.txt +93 -0
- package/dist/ui/static/fonts/jetbrains-mono-latin-wght-normal.woff2 +0 -0
- package/dist/ui/static/index.html +1 -1
- package/dist/ui/static/index.txt +3 -3
- package/dist/ui/static/launch/__next._full.txt +3 -3
- package/dist/ui/static/launch/__next._head.txt +1 -1
- package/dist/ui/static/launch/__next._index.txt +2 -2
- package/dist/ui/static/launch/__next._tree.txt +2 -2
- package/dist/ui/static/launch/__next.launch.__PAGE__.txt +2 -2
- package/dist/ui/static/launch/__next.launch.txt +1 -1
- package/dist/ui/static/launch.html +1 -1
- package/dist/ui/static/launch.txt +3 -3
- package/dist/ui/static/local-knowledge/__next._full.txt +3 -3
- package/dist/ui/static/local-knowledge/__next._head.txt +1 -1
- package/dist/ui/static/local-knowledge/__next._index.txt +2 -2
- package/dist/ui/static/local-knowledge/__next._tree.txt +2 -2
- package/dist/ui/static/local-knowledge/__next.local-knowledge.__PAGE__.txt +2 -2
- package/dist/ui/static/local-knowledge/__next.local-knowledge.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule/__next._full.txt +3 -3
- package/dist/ui/static/local-knowledge/capsule/__next._head.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule/__next._index.txt +2 -2
- package/dist/ui/static/local-knowledge/capsule/__next._tree.txt +2 -2
- package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.__PAGE__.txt +2 -2
- package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.capsule.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule/__next.local-knowledge.txt +1 -1
- package/dist/ui/static/local-knowledge/capsule.html +1 -1
- package/dist/ui/static/local-knowledge/capsule.txt +3 -3
- package/dist/ui/static/local-knowledge.html +1 -1
- package/dist/ui/static/local-knowledge.txt +3 -3
- package/dist/ui/static/memoriaviva/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/__next.memoriaviva.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/consolidation/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/consolidation/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.consolidation.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/consolidation.html +1 -1
- package/dist/ui/static/memoriaviva/consolidation.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/detail/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.detail.txt +1 -1
- package/dist/ui/static/memoriaviva/detail/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/detail.html +1 -1
- package/dist/ui/static/memoriaviva/detail.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next._full.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next._head.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue/__next._index.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next._tree.txt +2 -2
- package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.__PAGE__.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.review-queue.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue/__next.memoriaviva.txt +1 -1
- package/dist/ui/static/memoriaviva/review-queue.html +1 -1
- package/dist/ui/static/memoriaviva/review-queue.txt +2 -2
- package/dist/ui/static/memoriaviva.html +1 -1
- package/dist/ui/static/memoriaviva.txt +2 -2
- package/dist/ui/static/sw.js +7 -3
- package/node_modules/@oscharko-dev/keiko-cli/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-cli/dist/memory.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-cli/dist/memory.js +4 -5
- package/node_modules/@oscharko-dev/keiko-cli/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/index.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/dist/index.js +1 -1
- package/node_modules/@oscharko-dev/keiko-contracts/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-evaluations/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-evaluations/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts +5 -0
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-evidence/dist/qualityIntelligence/figmaSnapshot/store.js +16 -0
- package/node_modules/@oscharko-dev/keiko-evidence/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-harness/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-harness/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/pdf-parser.js +0 -10
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.d.ts +2 -2
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-local-knowledge/dist/parsers/types.js +3 -3
- package/node_modules/@oscharko-dev/keiko-local-knowledge/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-capture/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-consolidation/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/index.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/index.js +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/maintenance.d.ts +2 -16
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/maintenance.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/maintenance.js +49 -48
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/retention.d.ts +2 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/retention.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-governance/dist/retention.js +15 -0
- package/node_modules/@oscharko-dev/keiko-memory-governance/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/decay.d.ts +2 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/decay.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/decay.js +22 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/diversity.d.ts +8 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/diversity.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/diversity.js +87 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/index.d.ts +4 -2
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/index.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/index.js +4 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/ranking.d.ts +5 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/ranking.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/ranking.js +140 -21
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/recency.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/recency.js +4 -10
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/retrieve.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/retrieve.js +11 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/strength.d.ts +9 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/strength.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/strength.js +51 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/types.d.ts +11 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/types.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/dist/types.js +7 -0
- package/node_modules/@oscharko-dev/keiko-memory-retrieval/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/access.d.ts +3 -0
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/access.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/access.js +31 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/schema.d.ts +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/schema.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/schema.js +16 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/types.d.ts +1 -0
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/types.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/vault.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/dist/vault.js +4 -1
- package/node_modules/@oscharko-dev/keiko-memory-vault/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-model-gateway/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-model-gateway/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-quality-intelligence/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-sdk/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-sdk/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-security/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-security/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/chat-handlers.js +44 -65
- package/node_modules/@oscharko-dev/keiko-server/dist/deps.d.ts +2 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/deps.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/deps.js +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/gateway-setup.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/gateway-setup.js +305 -66
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-conv-handlers.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-conv-handlers.js +34 -5
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-embedding.d.ts +12 -2
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-embedding.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-embedding.js +127 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-handlers.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-handlers.js +40 -11
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-maintenance-handlers.d.ts +16 -3
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-maintenance-handlers.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-maintenance-handlers.js +72 -50
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-retrieval-signals.d.ts +12 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-retrieval-signals.d.ts.map +1 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-retrieval-signals.js +84 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-salience.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/memory-salience.js +11 -6
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts +15 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/qualityIntelligence/figmaSnapshotRoutes.js +105 -0
- package/node_modules/@oscharko-dev/keiko-server/dist/routes.d.ts.map +1 -1
- package/node_modules/@oscharko-dev/keiko-server/dist/routes.js +2 -1
- package/node_modules/@oscharko-dev/keiko-server/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-tools/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-tools/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-verification/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-verification/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-workflows/package.json +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/dist/.tsbuildinfo +1 -1
- package/node_modules/@oscharko-dev/keiko-workspace/package.json +1 -1
- package/package.json +2 -1
- package/dist/ui/static/_next/static/chunks/0-qhhdvxg2j_y.js +0 -1
- package/dist/ui/static/_next/static/chunks/0ke4ratkgvcxo.css +0 -1
- package/dist/ui/static/_next/static/chunks/3vf3oh2-sl2nc.js +0 -1
- package/dist/ui/static/_next/static/chunks/3wmd4-2vznp2g.js +0 -106
- /package/dist/ui/static/_next/static/{frhs0YcUqCPLHal-wHjDP → Ppze_8n_i3yc1FS_Qdj0I}/_buildManifest.js +0 -0
- /package/dist/ui/static/_next/static/{frhs0YcUqCPLHal-wHjDP → Ppze_8n_i3yc1FS_Qdj0I}/_clientMiddlewareManifest.js +0 -0
- /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
|
|
502
|
-
if (
|
|
503
|
-
return
|
|
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
|
-
|
|
506
|
-
|
|
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
|
|
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
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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
|
-
|
|
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
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
const
|
|
561
|
-
|
|
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
|
|
581
|
-
|
|
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(
|
|
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
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
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
|
|
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;
|
|
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
|
|
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
|
|
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;
|
|
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"}
|