@oscharko-dev/keiko 0.2.0-beta.6 → 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 +348 -64
- 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/{fQMXe8UmV01bh25WOoIt3 → Ppze_8n_i3yc1FS_Qdj0I}/_buildManifest.js +0 -0
- /package/dist/ui/static/_next/static/{fQMXe8UmV01bh25WOoIt3 → Ppze_8n_i3yc1FS_Qdj0I}/_clientMiddlewareManifest.js +0 -0
- /package/dist/ui/static/_next/static/{fQMXe8UmV01bh25WOoIt3 → 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,8 +20,11 @@ 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"]);
|
|
27
|
+
const EMBEDDING_ID_PATTERN = /(?:^|[-_/. ])(?:text-)?embed(?:ding)?s?(?:[-_/. ]|$)|ada-002(?:$|[-_/. ])/i;
|
|
23
28
|
class BodyTooLargeError extends Error {
|
|
24
29
|
constructor() {
|
|
25
30
|
super("request body too large");
|
|
@@ -99,7 +104,9 @@ function isAzureFoundryBaseUrl(baseUrl) {
|
|
|
99
104
|
}
|
|
100
105
|
}
|
|
101
106
|
function providerRaw(modelId, baseUrl, apiKey, options = {}) {
|
|
102
|
-
const defaultCapability =
|
|
107
|
+
const defaultCapability = options.embeddingModelIds?.includes(modelId) === true
|
|
108
|
+
? createDefaultEmbeddingCapabilityForSetup(modelId)
|
|
109
|
+
: createDefaultChatCapability(modelId);
|
|
103
110
|
return {
|
|
104
111
|
modelId,
|
|
105
112
|
baseUrl,
|
|
@@ -110,15 +117,80 @@ function providerRaw(modelId, baseUrl, apiKey, options = {}) {
|
|
|
110
117
|
: defaultCapability,
|
|
111
118
|
timeoutMs: options.timeoutMs ?? 30_000,
|
|
112
119
|
maxRetries: options.maxRetries ?? 2,
|
|
113
|
-
retryBaseDelayMs: 500,
|
|
120
|
+
retryBaseDelayMs: options.retryBaseDelayMs ?? 500,
|
|
114
121
|
};
|
|
115
122
|
}
|
|
123
|
+
function isLikelyEmbeddingModelId(modelId) {
|
|
124
|
+
return EMBEDDING_ID_PATTERN.test(modelId);
|
|
125
|
+
}
|
|
126
|
+
function createDefaultEmbeddingCapabilityForSetup(modelId) {
|
|
127
|
+
return {
|
|
128
|
+
id: modelId,
|
|
129
|
+
kind: "embedding",
|
|
130
|
+
contextWindow: 8_191,
|
|
131
|
+
maxOutputTokens: 0,
|
|
132
|
+
toolCalling: false,
|
|
133
|
+
structuredOutput: false,
|
|
134
|
+
streaming: false,
|
|
135
|
+
supportsImageInput: false,
|
|
136
|
+
supportsDocumentInput: false,
|
|
137
|
+
workflowEligible: false,
|
|
138
|
+
costClass: "low",
|
|
139
|
+
latencyClass: "fast",
|
|
140
|
+
throughputHint: "runtime-configured embedding endpoint",
|
|
141
|
+
preferredUseCases: ["Embeddings"],
|
|
142
|
+
knownLimitations: [
|
|
143
|
+
"Runtime-configured capability; validate against the target endpoint before production use",
|
|
144
|
+
],
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
function mergeChatAndEmbeddingModelIds(chatModelIds, deploymentNames) {
|
|
148
|
+
const merged = [...chatModelIds];
|
|
149
|
+
const seen = new Set(merged);
|
|
150
|
+
for (const modelId of deploymentNames) {
|
|
151
|
+
if (!isLikelyEmbeddingModelId(modelId) || seen.has(modelId)) {
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
seen.add(modelId);
|
|
155
|
+
merged.push(modelId);
|
|
156
|
+
}
|
|
157
|
+
return merged;
|
|
158
|
+
}
|
|
159
|
+
function embeddingModelIdsFromDeployments(deploymentNames) {
|
|
160
|
+
return deploymentNames.filter(isLikelyEmbeddingModelId);
|
|
161
|
+
}
|
|
116
162
|
function buildRawConfig(baseUrl, apiKey, modelIds, options = {}) {
|
|
117
163
|
return {
|
|
118
164
|
providers: modelIds.map((modelId) => providerRaw(modelId, baseUrl, apiKey, options)),
|
|
119
165
|
circuitBreaker: { failureThreshold: 5, cooldownMs: 30_000, halfOpenProbes: 2 },
|
|
120
166
|
};
|
|
121
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
|
+
}
|
|
122
194
|
function withInheritedEgress(rawConfig, egress) {
|
|
123
195
|
if (egress === undefined || Object.hasOwn(rawConfig, "egress")) {
|
|
124
196
|
return rawConfig;
|
|
@@ -382,6 +454,46 @@ async function defaultGatewaySetupTester(config, candidateModelIds) {
|
|
|
382
454
|
});
|
|
383
455
|
}, SETUP_SMOKE_CONCURRENCY);
|
|
384
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
|
+
}
|
|
385
497
|
function savePrivateJson(path, raw) {
|
|
386
498
|
const resolvedPath = resolve(path);
|
|
387
499
|
const dir = dirname(resolvedPath);
|
|
@@ -456,39 +568,111 @@ function readSetupModelLists(raw) {
|
|
|
456
568
|
}
|
|
457
569
|
return { deploymentNames, imageInputModelIds };
|
|
458
570
|
}
|
|
459
|
-
function
|
|
460
|
-
if (
|
|
461
|
-
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;
|
|
462
589
|
}
|
|
463
|
-
|
|
464
|
-
|
|
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;
|
|
611
|
+
}
|
|
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);
|
|
465
618
|
if (baseUrl.length === 0 || apiKey.length === 0) {
|
|
466
619
|
return { status: 400, body: errorBody("BAD_REQUEST", "baseUrl and apiKey are required.") };
|
|
467
620
|
}
|
|
468
|
-
const
|
|
621
|
+
const apiKeyHeaderSource = setupApiKeyHeaderSource(raw, provider, preserveExisting);
|
|
622
|
+
const apiKeyHeaderName = normalizeSetupApiKeyHeaderName(apiKeyHeaderSource);
|
|
469
623
|
if (isRouteResult(apiKeyHeaderName)) {
|
|
470
624
|
return apiKeyHeaderName;
|
|
471
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
|
+
}
|
|
472
660
|
const modelLists = readSetupModelLists(raw);
|
|
473
661
|
if (isRouteResult(modelLists)) {
|
|
474
662
|
return modelLists;
|
|
475
663
|
}
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
body: errorBody("BAD_REQUEST", "Figma access tokens must be configured server-side, not through gateway setup."),
|
|
480
|
-
};
|
|
481
|
-
}
|
|
482
|
-
const invalidConnection = validateSetupConnection(baseUrl, apiKey, apiKeyHeaderName, env);
|
|
483
|
-
if (invalidConnection !== undefined) {
|
|
484
|
-
return invalidConnection;
|
|
664
|
+
const figmaAccessToken = optionalSetupSecret(raw.figmaAccessToken, "figmaAccessToken");
|
|
665
|
+
if (isRouteResult(figmaAccessToken)) {
|
|
666
|
+
return figmaAccessToken;
|
|
485
667
|
}
|
|
668
|
+
const resolvedModelLists = resolveSetupModelLists(modelLists, current, preserveExisting);
|
|
486
669
|
return {
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
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,
|
|
492
676
|
};
|
|
493
677
|
}
|
|
494
678
|
function safeError(error, secrets) {
|
|
@@ -506,34 +690,55 @@ function assertImageInputModelsWereTested(imageInputModelIds, testedModelIds) {
|
|
|
506
690
|
throw new Error("imageInputModelIds must match tested chat-callable model ids.");
|
|
507
691
|
}
|
|
508
692
|
}
|
|
509
|
-
|
|
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) {
|
|
510
722
|
// Defence-in-depth: never send the credential to a candidate URL that has not passed the same
|
|
511
723
|
// scheme/credential/loopback validation as the originally submitted base URL.
|
|
512
|
-
validateBaseUrl(baseUrl, "candidate");
|
|
513
|
-
const
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
const
|
|
519
|
-
|
|
520
|
-
: await discovery(baseUrl, apiKey, apiKeyHeaderName, validationConfig.egress);
|
|
521
|
-
const smokeTimeoutMs = deploymentNames.length > 0 ? DEPLOYMENT_SMOKE_TIMEOUT_MS : DISCOVERED_MODEL_SMOKE_TIMEOUT_MS;
|
|
522
|
-
const candidateRawConfig = buildRawConfig(baseUrl, apiKey, candidateModelIds, {
|
|
523
|
-
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,
|
|
524
732
|
timeoutMs: smokeTimeoutMs,
|
|
525
733
|
maxRetries: 0,
|
|
526
|
-
imageInputModelIds,
|
|
527
|
-
});
|
|
528
|
-
const candidateConfig = parseGatewayConfig(withInheritedEgress(candidateRawConfig, egress), env);
|
|
529
|
-
const testedModelIds = await tester(candidateConfig, candidateModelIds);
|
|
530
|
-
assertImageInputModelsWereTested(imageInputModelIds, testedModelIds);
|
|
531
|
-
const rawConfig = buildRawConfig(baseUrl, apiKey, testedModelIds, {
|
|
532
|
-
apiKeyHeaderName,
|
|
533
|
-
imageInputModelIds,
|
|
734
|
+
imageInputModelIds: input.imageInputModelIds,
|
|
534
735
|
});
|
|
535
|
-
const
|
|
536
|
-
|
|
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 };
|
|
537
742
|
}
|
|
538
743
|
function setupSuccessResult(config, testedModelIds) {
|
|
539
744
|
const testedModelId = testedModelIds[0] ?? "unknown";
|
|
@@ -555,6 +760,45 @@ function setupFailureResult(errors) {
|
|
|
555
760
|
body: errorBody("GATEWAY_SETUP_FAILED", `Credentials could not be verified. ${errors.join(" ")}`),
|
|
556
761
|
};
|
|
557
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
|
+
}
|
|
558
802
|
function deploymentNamesRequiredResult() {
|
|
559
803
|
return {
|
|
560
804
|
status: 400,
|
|
@@ -588,39 +832,60 @@ function gatewayUnavailableResult() {
|
|
|
588
832
|
body: errorBody("GATEWAY_SETUP_UNAVAILABLE", "Gateway setup is unavailable."),
|
|
589
833
|
};
|
|
590
834
|
}
|
|
591
|
-
async function trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery) {
|
|
592
|
-
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
|
+
});
|
|
593
849
|
savePrivateJson(gatewayConfig.storagePath, verified.rawConfig);
|
|
594
850
|
gatewayConfig.set(verified.config, true);
|
|
595
851
|
return setupSuccessResult(verified.config, verified.testedModelIds);
|
|
596
852
|
}
|
|
597
853
|
function setupCandidateError(error, request, baseUrl) {
|
|
598
|
-
return safeError(error, [request.apiKey, request.baseUrl, baseUrl]);
|
|
854
|
+
return safeError(error, [request.apiKey, request.baseUrl, baseUrl, request.figmaAccessToken]);
|
|
599
855
|
}
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
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;
|
|
612
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) {
|
|
613
875
|
const tester = deps.gatewaySetupTester ?? defaultGatewaySetupTester;
|
|
614
876
|
const discovery = deps.gatewayModelDiscovery ?? defaultGatewayModelDiscovery;
|
|
877
|
+
const figmaFailure = await verifySubmittedFigmaCredential(request, deps);
|
|
878
|
+
if (figmaFailure !== undefined) {
|
|
879
|
+
return figmaFailure;
|
|
880
|
+
}
|
|
615
881
|
const baseUrlCandidates = candidateBaseUrls(request.baseUrl);
|
|
616
|
-
if (request
|
|
617
|
-
baseUrlCandidates.some((baseUrl) => isAzureFoundryBaseUrl(baseUrl))) {
|
|
882
|
+
if (shouldRequireDeploymentNames(request, baseUrlCandidates)) {
|
|
618
883
|
return deploymentNamesRequiredResult();
|
|
619
884
|
}
|
|
620
885
|
const errors = [];
|
|
621
886
|
for (const baseUrl of baseUrlCandidates) {
|
|
622
887
|
try {
|
|
623
|
-
return await trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery);
|
|
888
|
+
return await trySetupCandidate(baseUrl, request, deps, gatewayConfig, tester, discovery, current);
|
|
624
889
|
}
|
|
625
890
|
catch (error) {
|
|
626
891
|
errors.push(`candidate ${String(errors.length + 1)}: ${setupCandidateError(error, request, baseUrl)}`);
|
|
@@ -628,3 +893,22 @@ export async function handleGatewaySetup(ctx, deps) {
|
|
|
628
893
|
}
|
|
629
894
|
return setupFailureResult(errors);
|
|
630
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"}
|