lynkr 9.14.15 → 9.14.17
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/config/difficulty-anchors.json +12 -0
- package/package.json +2 -2
- package/src/api/router.js +45 -1
- package/src/cache/embeddings.js +30 -3
- package/src/clients/cursor-utils.js +791 -0
- package/src/clients/databricks.js +143 -11
- package/src/clients/health-probe.js +10 -0
- package/src/config/index.js +10 -0
- package/src/orchestrator/index.js +8 -0
- package/src/orchestrator/sse-transformer.js +37 -3
- package/src/routing/capabilities.js +6 -0
- package/src/routing/complexity-analyzer.js +8 -4
- package/src/routing/harness-envelope.js +71 -0
- package/src/routing/index.js +27 -6
- package/src/routing/intent-score.js +23 -4
- package/src/routing/jev-router.js +3 -0
- package/src/routing/model-registry.js +6 -3
- package/src/routing/model-tiers.js +2 -0
- package/src/routing/passthrough-route.js +20 -1
- package/src/routing/risk-analyzer.js +8 -1
- package/src/routing/shortfall.js +12 -6
- package/src/routing/vision.js +1 -1
|
@@ -28,5 +28,17 @@
|
|
|
28
28
|
"design a horizontally scalable architecture for this service with failure-mode analysis",
|
|
29
29
|
"Compare how databricks.js and openai-format.js each handle non-2xx upstream responses, then propose a unified error-normalization helper both could share",
|
|
30
30
|
"Code review the PR #84 routing hardening changes"
|
|
31
|
+
],
|
|
32
|
+
"frontier": [
|
|
33
|
+
"Prove the correctness of this lock-free queue implementation and identify any ABA hazards",
|
|
34
|
+
"Design a novel conflict-free replicated data type for collaborative rich-text editing and argue its convergence from first principles",
|
|
35
|
+
"Derive the optimal cache eviction policy for this access distribution and prove its competitive ratio",
|
|
36
|
+
"Diagnose this heisenbug: a race that only reproduces under load across three services, given these interleaved logs",
|
|
37
|
+
"Design a Byzantine-fault-tolerant consensus protocol variant that tolerates f faults with 2f+1 replicas by weakening liveness, and analyze exactly which guarantees are lost",
|
|
38
|
+
"Formally verify that this state machine can never deadlock, or produce a counterexample trace",
|
|
39
|
+
"Given these profiler traces, determine whether the tail latency is queueing-theoretic or GC-driven, and prove which by constructing a discriminating experiment",
|
|
40
|
+
"Reason through the security of this key-rotation scheme under an adversary who can observe but not modify traffic, and find the weakest assumption it relies on",
|
|
41
|
+
"Work out the exact memory ordering constraints this concurrent hashmap needs on ARM, and justify each barrier from the C++ memory model",
|
|
42
|
+
"Given this failing distributed transaction trace, determine whether the anomaly is write skew or lost update, and design the minimal isolation-level change that eliminates it"
|
|
31
43
|
]
|
|
32
44
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lynkr",
|
|
3
|
-
"version": "9.14.
|
|
3
|
+
"version": "9.14.17",
|
|
4
4
|
"files": [
|
|
5
5
|
"index.js",
|
|
6
6
|
"install.sh",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"start:supervised": "while true; do node index.js 2>&1 | npx pino-pretty --sync; code=$?; echo \"[supervisor] lynkr exited ($code) — restarting in 3s\"; sleep 3; done",
|
|
39
39
|
"lint": "eslint src index.js",
|
|
40
40
|
"test": "npm run test:unit && npm run test:performance",
|
|
41
|
-
"test:unit": "LYNKR_KNN_DIR=/tmp/lynkr-test-knn DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com LOG_FILE_ENABLED=false node --test test/routing.test.js test/hybrid-routing-integration.test.js test/retry-logic.test.js test/sse-transformer.test.js test/passthrough-stream.test.js test/passthrough-mode.test.js test/openrouter-error-resilience.test.js test/format-conversion.test.js test/azure-openai-config.test.js test/azure-openai-format-conversion.test.js test/azure-openai-routing.test.js test/azure-openai-streaming.test.js test/azure-openai-error-resilience.test.js test/azure-openai-integration.test.js test/openai-integration.test.js test/atlas-integration.test.js test/toon-compression.test.js test/gcf-compression.test.js test/llamacpp-integration.test.js test/resilience.test.js test/telemetry-routing.test.js test/memory/store.test.js test/memory/surprise.test.js test/memory/extractor.test.js test/memory/search.test.js test/memory/retriever.test.js test/memory/distiller.test.js test/memory/distiller-freeze.test.js test/memory/wiki.test.js test/memory/skills-cache.test.js test/memory/tencentdb-launcher.test.js test/distill.test.js test/large-payload.test.js test/prompt-cache-injection.test.js test/risk-analyzer.test.js test/interaction-block.test.js test/preflight.test.js test/token-reduction.test.js test/session-affinity.test.js test/cache-state.test.js test/cache-switch-cost.test.js test/lens-recommendations.test.js test/model-registry-cost.test.js test/output-format-guard.test.js test/tier-fallback.test.js test/wrap.test.js test/init.test.js test/tool-call-response-metadata.test.js test/degradation.test.js test/routing-telemetry-columns.test.js test/sticky-routing.test.js test/knn-ambiguous-escalate.test.js test/deescalator.test.js test/client-profiles.test.js test/strip-internal-fields.test.js test/complexity-tool-subtraction.test.js test/bandit.test.js test/routing-propensity.test.js test/reward-pipeline.test.js test/knn-cold-start.test.js test/calibration.test.js test/feedback-loop.test.js test/session-fingerprint.test.js test/side-request-guards.test.js test/verifier.test.js test/intent-score.test.js test/difficulty-classifier.test.js test/classifier-setup.test.js test/usage-stats.test.js test/loop-guard.test.js test/moonshot-model-mapping.test.js test/baidu-model-mapping.test.js test/tenant-policy-ingress-parity.test.js test/decide.test.js test/embeddings-degradation.test.js test/health-probe.test.js test/stuck-detector.test.js test/onnx-embedder.test.js test/ope.test.js test/hierarchical-budget.test.js test/token-rate-limit.test.js test/otel-export.test.js test/mcp-broker.test.js test/compression-budget.test.js test/gpt-utils.test.js test/dedup-observe-only.test.js test/context-window-header.test.js test/token-budget-auto.test.js test/opencode-setup.test.js test/auth-mode-first-party.test.js test/task-ledger.test.js test/jev-router.test.js test/jev-routing.test.js test/force-patterns.test.js test/upstream-fidelity.test.js test/tool-schema-compression.test.js test/passthrough-route.test.js test/quota-ledger.test.js",
|
|
41
|
+
"test:unit": "LYNKR_KNN_DIR=/tmp/lynkr-test-knn DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com LOG_FILE_ENABLED=false node --test test/routing.test.js test/hybrid-routing-integration.test.js test/retry-logic.test.js test/sse-transformer.test.js test/passthrough-stream.test.js test/passthrough-mode.test.js test/openrouter-error-resilience.test.js test/format-conversion.test.js test/azure-openai-config.test.js test/azure-openai-format-conversion.test.js test/azure-openai-routing.test.js test/azure-openai-streaming.test.js test/azure-openai-error-resilience.test.js test/azure-openai-integration.test.js test/openai-integration.test.js test/atlas-integration.test.js test/toon-compression.test.js test/gcf-compression.test.js test/llamacpp-integration.test.js test/resilience.test.js test/telemetry-routing.test.js test/memory/store.test.js test/memory/surprise.test.js test/memory/extractor.test.js test/memory/search.test.js test/memory/retriever.test.js test/memory/distiller.test.js test/memory/distiller-freeze.test.js test/memory/wiki.test.js test/memory/skills-cache.test.js test/memory/tencentdb-launcher.test.js test/distill.test.js test/large-payload.test.js test/prompt-cache-injection.test.js test/risk-analyzer.test.js test/interaction-block.test.js test/preflight.test.js test/token-reduction.test.js test/session-affinity.test.js test/cache-state.test.js test/cache-switch-cost.test.js test/lens-recommendations.test.js test/model-registry-cost.test.js test/output-format-guard.test.js test/tier-fallback.test.js test/wrap.test.js test/init.test.js test/tool-call-response-metadata.test.js test/degradation.test.js test/routing-telemetry-columns.test.js test/sticky-routing.test.js test/knn-ambiguous-escalate.test.js test/deescalator.test.js test/client-profiles.test.js test/strip-internal-fields.test.js test/complexity-tool-subtraction.test.js test/bandit.test.js test/routing-propensity.test.js test/reward-pipeline.test.js test/knn-cold-start.test.js test/calibration.test.js test/feedback-loop.test.js test/session-fingerprint.test.js test/side-request-guards.test.js test/verifier.test.js test/intent-score.test.js test/difficulty-classifier.test.js test/classifier-setup.test.js test/usage-stats.test.js test/loop-guard.test.js test/moonshot-model-mapping.test.js test/baidu-model-mapping.test.js test/tenant-policy-ingress-parity.test.js test/decide.test.js test/embeddings-degradation.test.js test/health-probe.test.js test/stuck-detector.test.js test/onnx-embedder.test.js test/ope.test.js test/hierarchical-budget.test.js test/token-rate-limit.test.js test/otel-export.test.js test/mcp-broker.test.js test/compression-budget.test.js test/gpt-utils.test.js test/dedup-observe-only.test.js test/context-window-header.test.js test/token-budget-auto.test.js test/opencode-setup.test.js test/auth-mode-first-party.test.js test/harness-envelope.test.js test/task-ledger.test.js test/jev-router.test.js test/jev-routing.test.js test/force-patterns.test.js test/upstream-fidelity.test.js test/tool-schema-compression.test.js test/passthrough-route.test.js test/quota-ledger.test.js",
|
|
42
42
|
"test:memory": "LYNKR_KNN_DIR=/tmp/lynkr-test-knn DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node --test test/memory/store.test.js test/memory/surprise.test.js test/memory/extractor.test.js test/memory/search.test.js test/memory/retriever.test.js test/memory/distiller.test.js test/memory/distiller-freeze.test.js test/memory/wiki.test.js test/memory/skills-cache.test.js test/memory/tencentdb-launcher.test.js",
|
|
43
43
|
"test:new-features": "LYNKR_KNN_DIR=/tmp/lynkr-test-knn DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node --test test/passthrough-mode.test.js test/openrouter-error-resilience.test.js test/format-conversion.test.js",
|
|
44
44
|
"test:performance": "LYNKR_KNN_DIR=/tmp/lynkr-test-knn DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node test/hybrid-routing-performance.test.js && DATABRICKS_API_KEY=test-key DATABRICKS_API_BASE=http://test.com node test/performance-tests.js",
|
package/src/api/router.js
CHANGED
|
@@ -10,6 +10,7 @@ const providersRouter = require("./providers-handler");
|
|
|
10
10
|
const claudeDesktopGatewayRouter = require("./claude-desktop-gateway");
|
|
11
11
|
const { getRoutingHeaders, getRoutingStats, analyzeComplexity, getModelTierSelector, analyzeRisk, checkSessionPin, writeSessionPin, checkPinScoreDrift } = require("../routing");
|
|
12
12
|
const { resolveTierForModelId } = require("../routing/model-slots");
|
|
13
|
+
const { stripHarnessEnvelope } = require("../routing/harness-envelope");
|
|
13
14
|
|
|
14
15
|
// Upstream streams can die without a clean end (reader.read() never
|
|
15
16
|
// resolves on a dropped socket), hanging the client forever. Every
|
|
@@ -1409,7 +1410,11 @@ router.post("/v1/messages", rateLimiter, async (req, res, next) => {
|
|
|
1409
1410
|
}
|
|
1410
1411
|
return '';
|
|
1411
1412
|
})();
|
|
1413
|
+
// Suggestion-mode detection reads the RAW text (the marker is itself
|
|
1414
|
+
// wrapper text); the force/risk probes below get envelope-stripped text
|
|
1415
|
+
// so Cursor's <user_info>/<rules> blocks can't fire triggers on "Hi".
|
|
1412
1416
|
const isSuggestionMode = _lastUserText.includes('[SUGGESTION MODE:');
|
|
1417
|
+
const _lastUserAskClean = stripHarnessEnvelope(_lastUserText);
|
|
1413
1418
|
// Tool-lessness alone is NOT harness evidence: generic API clients
|
|
1414
1419
|
// (curl, benchmarks, SDKs) legitimately send bare messages and must get
|
|
1415
1420
|
// full routing — live regression 2026-07-08: a benchmark's security-
|
|
@@ -1535,7 +1540,7 @@ router.post("/v1/messages", rateLimiter, async (req, res, next) => {
|
|
|
1535
1540
|
let _pinForceBypass = null;
|
|
1536
1541
|
if (!sideTier && pinCheck.serve && pinCheck.reason === 'guards_passed' && !isSideRequest) {
|
|
1537
1542
|
try {
|
|
1538
|
-
const _probe = { messages: [{ role: 'user', content:
|
|
1543
|
+
const _probe = { messages: [{ role: 'user', content: _lastUserAskClean || '' }] };
|
|
1539
1544
|
const ca = require("../routing/complexity-analyzer");
|
|
1540
1545
|
if (_lastUserText && ca.shouldForceReasoning(_probe)) _pinForceBypass = 'force_reasoning';
|
|
1541
1546
|
else if (_lastUserText && ca.shouldForceCloud(_probe)) _pinForceBypass = 'force_cloud';
|
|
@@ -1883,6 +1888,15 @@ router.post("/v1/messages", rateLimiter, async (req, res, next) => {
|
|
|
1883
1888
|
tierMethod: tier?.method || null,
|
|
1884
1889
|
tierPinned: tier?.pinned ?? null,
|
|
1885
1890
|
cacheState: _pinCacheState,
|
|
1891
|
+
// Mid tool-exchange frames must keep serving the in-flight model
|
|
1892
|
+
// (same invariant as the orchestrator's tool_history pin serves).
|
|
1893
|
+
hasToolHistory: (() => {
|
|
1894
|
+
try { return require("../routing/session-affinity").payloadHasToolHistory(req.body); }
|
|
1895
|
+
catch { return false; }
|
|
1896
|
+
})(),
|
|
1897
|
+
// This branch IS the flat-fee subscription: the gate's dollar
|
|
1898
|
+
// break-even leg has no premium to amortize here.
|
|
1899
|
+
flatRate: true,
|
|
1886
1900
|
// Quota pressure shortens the hold horizon inside the gate (high
|
|
1887
1901
|
// sustained burn → descents clear sooner). Zero when the ledger has
|
|
1888
1902
|
// no history — the gate behaves exactly as before.
|
|
@@ -1919,6 +1933,36 @@ router.post("/v1/messages", rateLimiter, async (req, res, next) => {
|
|
|
1919
1933
|
logger.debug({ err: err.message }, '[Routing] Pin-hold restore failed (non-fatal)');
|
|
1920
1934
|
}
|
|
1921
1935
|
}
|
|
1936
|
+
// Upgrades must persist the SERVED model into the pin, mirroring the
|
|
1937
|
+
// pin_hold restore above — the write at the fresh-decision site stored
|
|
1938
|
+
// the pre-rewrite tier model, and a pin that forgets the upgrade lets
|
|
1939
|
+
// later frames descend below what actually served. Unlike pin_hold,
|
|
1940
|
+
// an upgrade usually happens with no prior pin, so the payload comes
|
|
1941
|
+
// from the fresh tier object. Floored (+continuation_inherit) and
|
|
1942
|
+
// risk-lifted tiers stay unpinned (writeSessionPin re-checks, but the
|
|
1943
|
+
// method is overridden to 'session_pin' here, so guard at the source).
|
|
1944
|
+
if (
|
|
1945
|
+
_passthroughRoute.action === 'upgrade'
|
|
1946
|
+
&& _passthroughRoute.model
|
|
1947
|
+
&& pinCheck?.sessionId
|
|
1948
|
+
&& tier?.provider
|
|
1949
|
+
&& !String(tier?.method || '').includes('+continuation_inherit')
|
|
1950
|
+
&& tier?.escalation_source !== 'risk'
|
|
1951
|
+
) {
|
|
1952
|
+
try {
|
|
1953
|
+
const { writeSessionPin } = require("../routing/index");
|
|
1954
|
+
writeSessionPin(pinCheck.sessionId, {
|
|
1955
|
+
provider: tier.provider,
|
|
1956
|
+
model: _passthroughRoute.model,
|
|
1957
|
+
tier: tier.tier,
|
|
1958
|
+
score: tier.score ?? null,
|
|
1959
|
+
method: 'session_pin',
|
|
1960
|
+
reason: 'passthrough_upgrade',
|
|
1961
|
+
}, req.body);
|
|
1962
|
+
} catch (err) {
|
|
1963
|
+
logger.debug({ err: err.message }, '[Routing] Upgrade pin persist failed (non-fatal)');
|
|
1964
|
+
}
|
|
1965
|
+
}
|
|
1922
1966
|
if (_passthroughRoute.action !== 'verbatim' && _passthroughRoute.model) {
|
|
1923
1967
|
logger.info({
|
|
1924
1968
|
from: _passthroughClientModel,
|
package/src/cache/embeddings.js
CHANGED
|
@@ -145,6 +145,9 @@ const STRICT = process.env.LYNKR_EMBEDDINGS_STRICT === 'true';
|
|
|
145
145
|
function _noteFallback(providerName, err) {
|
|
146
146
|
fallbackCount += 1;
|
|
147
147
|
lastProviderError = err?.message || String(err);
|
|
148
|
+
// Cooldown counts from the LAST failed dial, not the first attempt's start —
|
|
149
|
+
// the in-place retry delay must not eat into the cooldown window.
|
|
150
|
+
lastProviderAttempt = Date.now();
|
|
148
151
|
if (embeddingProviderAvailable !== false) {
|
|
149
152
|
embeddingProviderAvailable = false;
|
|
150
153
|
degradedSince = Date.now();
|
|
@@ -168,6 +171,14 @@ function _noteRecovery(providerName) {
|
|
|
168
171
|
degradedSince = null;
|
|
169
172
|
}
|
|
170
173
|
|
|
174
|
+
// One in-place retry before tripping degradation: a single transient failure
|
|
175
|
+
// (Ollama cold-loading the model at boot, a blip mid-restart) was flipping
|
|
176
|
+
// the WHOLE provider to hash embeddings for a full cooldown after every
|
|
177
|
+
// server start (recurring live incident, last 2026-09-26). A short backoff
|
|
178
|
+
// absorbs the blip; a provider that is actually down fails twice and
|
|
179
|
+
// degrades exactly as before.
|
|
180
|
+
const TRANSIENT_RETRY_DELAY_MS = 1500;
|
|
181
|
+
|
|
171
182
|
function _wrapProvider(providerName, providerFn) {
|
|
172
183
|
return async (text) => {
|
|
173
184
|
// While degraded, only re-attempt the provider after the cooldown; serve
|
|
@@ -184,9 +195,25 @@ function _wrapProvider(providerName, providerFn) {
|
|
|
184
195
|
const result = await providerFn(text);
|
|
185
196
|
_noteRecovery(providerName);
|
|
186
197
|
return result;
|
|
187
|
-
} catch (
|
|
188
|
-
|
|
189
|
-
|
|
198
|
+
} catch (firstErr) {
|
|
199
|
+
// Already-degraded providers get no second chance (this attempt WAS the
|
|
200
|
+
// post-cooldown probe); healthy ones earn one retry before the flip.
|
|
201
|
+
if (embeddingProviderAvailable !== false) {
|
|
202
|
+
await new Promise((r) => setTimeout(r, TRANSIENT_RETRY_DELAY_MS));
|
|
203
|
+
try {
|
|
204
|
+
const result = await providerFn(text);
|
|
205
|
+
_noteRecovery(providerName);
|
|
206
|
+
logger.debug({ provider: providerName, error: firstErr?.message },
|
|
207
|
+
'[Embeddings] Transient provider failure absorbed by retry');
|
|
208
|
+
return result;
|
|
209
|
+
} catch (secondErr) {
|
|
210
|
+
_noteFallback(providerName, secondErr);
|
|
211
|
+
if (STRICT) throw secondErr;
|
|
212
|
+
return generateHashEmbedding(text);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
_noteFallback(providerName, firstErr);
|
|
216
|
+
if (STRICT) throw firstErr;
|
|
190
217
|
return generateHashEmbedding(text);
|
|
191
218
|
}
|
|
192
219
|
};
|