@remnic/core 9.69.66 → 9.69.67
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/access-admin-ops-surface.js +27 -26
- package/dist/access-audit.js +2 -2
- package/dist/access-authorization-probe.js +28 -27
- package/dist/access-boundary.js +27 -26
- package/dist/access-cli.js +78 -77
- package/dist/access-cli.js.map +1 -1
- package/dist/access-extraction-force-flush.js +27 -26
- package/dist/access-http-briefing.js +28 -27
- package/dist/access-http-query.js +29 -28
- package/dist/access-http.js +47 -46
- package/dist/access-identity-continuity-surface.js +27 -26
- package/dist/access-lcm-surface.js +27 -26
- package/dist/access-mcp.js +37 -36
- package/dist/access-namespace-preflight.js +27 -26
- package/dist/access-observe-write-surface.js +27 -26
- package/dist/access-operations-batch.js +29 -28
- package/dist/access-operations.js +36 -35
- package/dist/access-recall-concurrency.js +27 -26
- package/dist/access-recall-response.js +27 -26
- package/dist/access-recall-surface.js +27 -26
- package/dist/access-service.js +27 -26
- package/dist/access-surface-catalog.js +29 -28
- package/dist/access-surface-catalog.js.map +1 -1
- package/dist/active-recall.js +8 -8
- package/dist/adapters/index.js +4 -4
- package/dist/adapters/registry.js +2 -2
- package/dist/briefing.js +7 -7
- package/dist/causal-consolidation.js +8 -8
- package/dist/{chunk-CFCAFAJC.js → chunk-266NJ2YF.js} +2 -2
- package/dist/{chunk-LQ4OSM5V.js → chunk-2LT2GSTI.js} +6 -6
- package/dist/{chunk-YGJMMMPN.js → chunk-2VV3XLZB.js} +2 -2
- package/dist/{chunk-B2JE56NB.js → chunk-3R34HFBY.js} +2 -2
- package/dist/{chunk-MUGLJAZ3.js → chunk-4M375K73.js} +2 -2
- package/dist/{chunk-WZ33AIOP.js → chunk-5ID5RTHY.js} +2 -2
- package/dist/{chunk-WUUGE7QC.js → chunk-5TC6MQOW.js} +4 -4
- package/dist/{chunk-PSGRZFBH.js → chunk-A5IRUJMX.js} +11 -11
- package/dist/{chunk-X2NFFBTO.js → chunk-A7GQBJP5.js} +4 -4
- package/dist/{chunk-OCEIHKH5.js → chunk-ADZLUBNE.js} +3 -3
- package/dist/{chunk-ITLFUILH.js → chunk-AJEUESNJ.js} +2 -2
- package/dist/{chunk-D433RXFJ.js → chunk-AYDU5MJC.js} +2 -2
- package/dist/{chunk-II4TIQCU.js → chunk-B2FMRNHA.js} +2 -2
- package/dist/{chunk-I4IKTNZP.js → chunk-B6RTKSOT.js} +3 -3
- package/dist/{chunk-C2W6JKQQ.js → chunk-BGBW4H7C.js} +2 -2
- package/dist/{chunk-5C765XYU.js → chunk-BSCR5TEN.js} +2 -2
- package/dist/{chunk-CZM4MHZF.js → chunk-C7K7YV65.js} +31 -31
- package/dist/{chunk-7L747CFR.js → chunk-CMAGVPS2.js} +2 -2
- package/dist/{chunk-U6GKPSZH.js → chunk-D5F2Z6WO.js} +2 -2
- package/dist/{chunk-ZX5N5D6M.js → chunk-DAOMWGO2.js} +4 -4
- package/dist/{chunk-L4HT5QZ5.js → chunk-DDNML3YE.js} +2 -2
- package/dist/{chunk-6YTL3JYX.js → chunk-DQEM4LDV.js} +2 -2
- package/dist/{chunk-O7QF3TCV.js → chunk-DUWNHPZ2.js} +25 -25
- package/dist/{chunk-XJNSOI23.js → chunk-FN6E373Q.js} +2 -2
- package/dist/{chunk-NYN4ZMPL.js → chunk-FZ4BU3WD.js} +2 -2
- package/dist/{chunk-2PKGJPQL.js → chunk-G3QJVHFG.js} +4 -4
- package/dist/{chunk-LI4IWBLN.js → chunk-GNC5X3J7.js} +5 -5
- package/dist/{chunk-GZLSIPYU.js → chunk-GUWH5SOO.js} +2 -2
- package/dist/{chunk-FO5NDQZH.js → chunk-HRQWSXNB.js} +3 -3
- package/dist/{chunk-62JTOLEX.js → chunk-I53NAHZ4.js} +14 -65
- package/dist/chunk-I53NAHZ4.js.map +1 -0
- package/dist/{chunk-AQ6IBVFQ.js → chunk-JDBZSRUA.js} +2 -2
- package/dist/{chunk-E7SKAUEW.js → chunk-JX2NWPQ4.js} +8 -8
- package/dist/{chunk-EK4MOTHM.js → chunk-MQTCNXTG.js} +4 -4
- package/dist/{chunk-2ZVSQPAA.js → chunk-MZQ2MBET.js} +19 -19
- package/dist/{chunk-3S4R2HA5.js → chunk-NEARGPN7.js} +2 -2
- package/dist/{chunk-ZSXSMVW6.js → chunk-NPA73KGP.js} +2 -2
- package/dist/{chunk-3NG5OOCX.js → chunk-NZUHZVHF.js} +2 -2
- package/dist/{chunk-5WXJE5TV.js → chunk-OAOBL6OY.js} +2 -2
- package/dist/{chunk-TO3G56GM.js → chunk-OVO545UE.js} +2 -2
- package/dist/{chunk-QMWKENNK.js → chunk-Q4AUIFUA.js} +4 -4
- package/dist/{chunk-Y3AFTYK4.js → chunk-RDWVTUXZ.js} +2 -2
- package/dist/{chunk-OBD77TYC.js → chunk-RG7ZWG3M.js} +2 -2
- package/dist/{chunk-DT33WNG2.js → chunk-S4W66FQ7.js} +3 -3
- package/dist/{chunk-JLU7WK22.js → chunk-SUI5JQVE.js} +2 -2
- package/dist/{chunk-YIDBKTZJ.js → chunk-SYBHLTFW.js} +2 -2
- package/dist/{chunk-IOUQUXHO.js → chunk-TRLPF7ZP.js} +2 -2
- package/dist/chunk-U4LUIE6Y.js +76 -0
- package/dist/chunk-U4LUIE6Y.js.map +1 -0
- package/dist/{chunk-ZPPWW576.js → chunk-UBCVHKZQ.js} +2 -2
- package/dist/{chunk-IJQEVNEF.js → chunk-VQJ7UAKA.js} +1 -1
- package/dist/{chunk-M3TMVHQ2.js → chunk-VVKLAB3Y.js} +2 -2
- package/dist/{chunk-755VRFBS.js → chunk-WJPRWNZN.js} +2 -2
- package/dist/{chunk-IULYVB5X.js → chunk-WTD4JHFP.js} +5 -5
- package/dist/{chunk-5AABWM72.js → chunk-WXPIEWQW.js} +3 -3
- package/dist/{chunk-XGLBVYEA.js → chunk-XY25CPAO.js} +8 -8
- package/dist/{chunk-4RWPQZYD.js → chunk-YED2GFH6.js} +2 -2
- package/dist/{chunk-XDIFADVN.js → chunk-YZH4O4NA.js} +2 -2
- package/dist/{chunk-BE4GMH45.js → chunk-ZDTG7ALZ.js} +2 -2
- package/dist/{chunk-DDY7LJMP.js → chunk-ZMU7UK2Q.js} +2 -2
- package/dist/cli.js +62 -61
- package/dist/coding/export-okf-codegraph.js +6 -6
- package/dist/compounding/engine.js +7 -7
- package/dist/config.js +8 -8
- package/dist/connectors/codex-materialize-runner.js +7 -7
- package/dist/connectors/index.js +7 -7
- package/dist/convergence-refresh.js +9 -9
- package/dist/corpus-watermark.js +9 -9
- package/dist/deep-recall.js +2 -2
- package/dist/entity-retrieval.js +7 -7
- package/dist/external-wiki-access.js +28 -27
- package/dist/extraction.js +10 -9
- package/dist/harmonic-retrieval.js +1 -1
- package/dist/index.js +84 -83
- package/dist/lcm/engine.js +2 -2
- package/dist/lcm/index.js +4 -4
- package/dist/local-llm-servers.d.ts +23 -0
- package/dist/local-llm-servers.d.ts.map +1 -0
- package/dist/local-llm-servers.js +10 -0
- package/dist/local-llm-servers.js.map +1 -0
- package/dist/local-llm.d.ts +8 -7
- package/dist/local-llm.d.ts.map +1 -1
- package/dist/local-llm.js +2 -1
- package/dist/location/index.js +9 -9
- package/dist/maintenance/memory-governance.js +7 -7
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +7 -7
- package/dist/maintenance/rebuild-memory-projection.js +8 -8
- package/dist/memory-browse-operations.js +28 -27
- package/dist/namespaces/migrate.js +8 -8
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.js +7 -7
- package/dist/operator-doctor-corpus.js +10 -10
- package/dist/operator-toolkit.js +17 -17
- package/dist/orchestration/maintenance.js +17 -16
- package/dist/orchestrator.js +78 -77
- package/dist/recall-navigation-operations.js +28 -27
- package/dist/recall-navigation.js +27 -26
- package/dist/resume-bundles.js +9 -9
- package/dist/search/factory.js +3 -3
- package/dist/search/index.js +7 -7
- package/dist/semantic-consolidation.js +8 -8
- package/dist/semantic-rule-promotion.js +7 -7
- package/dist/semantic-rule-verifier.js +7 -7
- package/dist/source-agent-qualifier.js +7 -7
- package/dist/standup/build.js +7 -7
- package/dist/storage.js +6 -6
- package/dist/summarizer.js +3 -2
- package/dist/support-passport/index.js +30 -29
- package/dist/transfer/export-okf.js +7 -7
- package/dist/verified-recall.js +7 -7
- package/dist/who-knows-cli.js +8 -8
- package/dist/who-knows.js +7 -7
- package/package.json +2 -2
- package/src/local-llm-probe-litellm.test.ts +116 -0
- package/src/local-llm-servers.ts +104 -0
- package/src/local-llm.ts +25 -85
- package/dist/chunk-62JTOLEX.js.map +0 -1
- /package/dist/{chunk-CFCAFAJC.js.map → chunk-266NJ2YF.js.map} +0 -0
- /package/dist/{chunk-LQ4OSM5V.js.map → chunk-2LT2GSTI.js.map} +0 -0
- /package/dist/{chunk-YGJMMMPN.js.map → chunk-2VV3XLZB.js.map} +0 -0
- /package/dist/{chunk-B2JE56NB.js.map → chunk-3R34HFBY.js.map} +0 -0
- /package/dist/{chunk-MUGLJAZ3.js.map → chunk-4M375K73.js.map} +0 -0
- /package/dist/{chunk-WZ33AIOP.js.map → chunk-5ID5RTHY.js.map} +0 -0
- /package/dist/{chunk-WUUGE7QC.js.map → chunk-5TC6MQOW.js.map} +0 -0
- /package/dist/{chunk-PSGRZFBH.js.map → chunk-A5IRUJMX.js.map} +0 -0
- /package/dist/{chunk-X2NFFBTO.js.map → chunk-A7GQBJP5.js.map} +0 -0
- /package/dist/{chunk-OCEIHKH5.js.map → chunk-ADZLUBNE.js.map} +0 -0
- /package/dist/{chunk-ITLFUILH.js.map → chunk-AJEUESNJ.js.map} +0 -0
- /package/dist/{chunk-D433RXFJ.js.map → chunk-AYDU5MJC.js.map} +0 -0
- /package/dist/{chunk-II4TIQCU.js.map → chunk-B2FMRNHA.js.map} +0 -0
- /package/dist/{chunk-I4IKTNZP.js.map → chunk-B6RTKSOT.js.map} +0 -0
- /package/dist/{chunk-C2W6JKQQ.js.map → chunk-BGBW4H7C.js.map} +0 -0
- /package/dist/{chunk-5C765XYU.js.map → chunk-BSCR5TEN.js.map} +0 -0
- /package/dist/{chunk-CZM4MHZF.js.map → chunk-C7K7YV65.js.map} +0 -0
- /package/dist/{chunk-7L747CFR.js.map → chunk-CMAGVPS2.js.map} +0 -0
- /package/dist/{chunk-U6GKPSZH.js.map → chunk-D5F2Z6WO.js.map} +0 -0
- /package/dist/{chunk-ZX5N5D6M.js.map → chunk-DAOMWGO2.js.map} +0 -0
- /package/dist/{chunk-L4HT5QZ5.js.map → chunk-DDNML3YE.js.map} +0 -0
- /package/dist/{chunk-6YTL3JYX.js.map → chunk-DQEM4LDV.js.map} +0 -0
- /package/dist/{chunk-O7QF3TCV.js.map → chunk-DUWNHPZ2.js.map} +0 -0
- /package/dist/{chunk-XJNSOI23.js.map → chunk-FN6E373Q.js.map} +0 -0
- /package/dist/{chunk-NYN4ZMPL.js.map → chunk-FZ4BU3WD.js.map} +0 -0
- /package/dist/{chunk-2PKGJPQL.js.map → chunk-G3QJVHFG.js.map} +0 -0
- /package/dist/{chunk-LI4IWBLN.js.map → chunk-GNC5X3J7.js.map} +0 -0
- /package/dist/{chunk-GZLSIPYU.js.map → chunk-GUWH5SOO.js.map} +0 -0
- /package/dist/{chunk-FO5NDQZH.js.map → chunk-HRQWSXNB.js.map} +0 -0
- /package/dist/{chunk-AQ6IBVFQ.js.map → chunk-JDBZSRUA.js.map} +0 -0
- /package/dist/{chunk-E7SKAUEW.js.map → chunk-JX2NWPQ4.js.map} +0 -0
- /package/dist/{chunk-EK4MOTHM.js.map → chunk-MQTCNXTG.js.map} +0 -0
- /package/dist/{chunk-2ZVSQPAA.js.map → chunk-MZQ2MBET.js.map} +0 -0
- /package/dist/{chunk-3S4R2HA5.js.map → chunk-NEARGPN7.js.map} +0 -0
- /package/dist/{chunk-ZSXSMVW6.js.map → chunk-NPA73KGP.js.map} +0 -0
- /package/dist/{chunk-3NG5OOCX.js.map → chunk-NZUHZVHF.js.map} +0 -0
- /package/dist/{chunk-5WXJE5TV.js.map → chunk-OAOBL6OY.js.map} +0 -0
- /package/dist/{chunk-TO3G56GM.js.map → chunk-OVO545UE.js.map} +0 -0
- /package/dist/{chunk-QMWKENNK.js.map → chunk-Q4AUIFUA.js.map} +0 -0
- /package/dist/{chunk-Y3AFTYK4.js.map → chunk-RDWVTUXZ.js.map} +0 -0
- /package/dist/{chunk-OBD77TYC.js.map → chunk-RG7ZWG3M.js.map} +0 -0
- /package/dist/{chunk-DT33WNG2.js.map → chunk-S4W66FQ7.js.map} +0 -0
- /package/dist/{chunk-JLU7WK22.js.map → chunk-SUI5JQVE.js.map} +0 -0
- /package/dist/{chunk-YIDBKTZJ.js.map → chunk-SYBHLTFW.js.map} +0 -0
- /package/dist/{chunk-IOUQUXHO.js.map → chunk-TRLPF7ZP.js.map} +0 -0
- /package/dist/{chunk-ZPPWW576.js.map → chunk-UBCVHKZQ.js.map} +0 -0
- /package/dist/{chunk-IJQEVNEF.js.map → chunk-VQJ7UAKA.js.map} +0 -0
- /package/dist/{chunk-M3TMVHQ2.js.map → chunk-VVKLAB3Y.js.map} +0 -0
- /package/dist/{chunk-755VRFBS.js.map → chunk-WJPRWNZN.js.map} +0 -0
- /package/dist/{chunk-IULYVB5X.js.map → chunk-WTD4JHFP.js.map} +0 -0
- /package/dist/{chunk-5AABWM72.js.map → chunk-WXPIEWQW.js.map} +0 -0
- /package/dist/{chunk-XGLBVYEA.js.map → chunk-XY25CPAO.js.map} +0 -0
- /package/dist/{chunk-4RWPQZYD.js.map → chunk-YED2GFH6.js.map} +0 -0
- /package/dist/{chunk-XDIFADVN.js.map → chunk-YZH4O4NA.js.map} +0 -0
- /package/dist/{chunk-BE4GMH45.js.map → chunk-ZDTG7ALZ.js.map} +0 -0
- /package/dist/{chunk-DDY7LJMP.js.map → chunk-ZMU7UK2Q.js.map} +0 -0
|
@@ -4,33 +4,33 @@ import {
|
|
|
4
4
|
exportOkfBundle,
|
|
5
5
|
firstHeading,
|
|
6
6
|
parseIncludeStatus
|
|
7
|
-
} from "../chunk-
|
|
7
|
+
} from "../chunk-5ID5RTHY.js";
|
|
8
8
|
import {
|
|
9
9
|
OKF_EXPORT_VERSION
|
|
10
10
|
} from "../chunk-UJX4I26O.js";
|
|
11
11
|
import "../chunk-D24OXEPB.js";
|
|
12
12
|
import "../chunk-3UXOZBHV.js";
|
|
13
|
-
import "../chunk-
|
|
13
|
+
import "../chunk-GNC5X3J7.js";
|
|
14
14
|
import "../chunk-46WM6JX2.js";
|
|
15
15
|
import "../chunk-UHVXE24Y.js";
|
|
16
16
|
import "../chunk-D5F7TKMH.js";
|
|
17
|
-
import "../chunk-
|
|
18
|
-
import "../chunk-
|
|
17
|
+
import "../chunk-BGBW4H7C.js";
|
|
18
|
+
import "../chunk-MQTCNXTG.js";
|
|
19
|
+
import "../chunk-T3FMRLWQ.js";
|
|
19
20
|
import "../chunk-7VO6E5UD.js";
|
|
20
21
|
import "../chunk-Z4TXB4K7.js";
|
|
21
22
|
import "../chunk-S7LWX2PQ.js";
|
|
22
23
|
import "../chunk-T2YX56QI.js";
|
|
23
|
-
import "../chunk-CYEPCZN5.js";
|
|
24
|
-
import "../chunk-T3FMRLWQ.js";
|
|
25
24
|
import "../chunk-4O6WRBGE.js";
|
|
26
25
|
import "../chunk-GUMZC2BO.js";
|
|
26
|
+
import "../chunk-CYEPCZN5.js";
|
|
27
27
|
import "../chunk-TFA6HPOA.js";
|
|
28
28
|
import "../chunk-F4TWWUMP.js";
|
|
29
29
|
import "../chunk-72A4L5JJ.js";
|
|
30
30
|
import "../chunk-A7Q43EUZ.js";
|
|
31
31
|
import "../chunk-S2V7RUCL.js";
|
|
32
|
-
import "../chunk-MRPOZBJC.js";
|
|
33
32
|
import "../chunk-S2HLHAZ4.js";
|
|
33
|
+
import "../chunk-MRPOZBJC.js";
|
|
34
34
|
import "../chunk-DM2T26WE.js";
|
|
35
35
|
import "../chunk-LDXUBPMO.js";
|
|
36
36
|
import "../chunk-FF6N7BXC.js";
|
package/dist/verified-recall.js
CHANGED
|
@@ -1,29 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
compareVerifiedEpisodeResults,
|
|
3
3
|
searchVerifiedEpisodes
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-DDNML3YE.js";
|
|
5
5
|
import "./chunk-B7RWBZXW.js";
|
|
6
|
-
import "./chunk-
|
|
6
|
+
import "./chunk-GNC5X3J7.js";
|
|
7
7
|
import "./chunk-46WM6JX2.js";
|
|
8
8
|
import "./chunk-UHVXE24Y.js";
|
|
9
9
|
import "./chunk-D5F7TKMH.js";
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
10
|
+
import "./chunk-BGBW4H7C.js";
|
|
11
|
+
import "./chunk-MQTCNXTG.js";
|
|
12
|
+
import "./chunk-T3FMRLWQ.js";
|
|
12
13
|
import "./chunk-7VO6E5UD.js";
|
|
13
14
|
import "./chunk-Z4TXB4K7.js";
|
|
14
15
|
import "./chunk-S7LWX2PQ.js";
|
|
15
16
|
import "./chunk-T2YX56QI.js";
|
|
16
|
-
import "./chunk-CYEPCZN5.js";
|
|
17
|
-
import "./chunk-T3FMRLWQ.js";
|
|
18
17
|
import "./chunk-4O6WRBGE.js";
|
|
19
18
|
import "./chunk-GUMZC2BO.js";
|
|
19
|
+
import "./chunk-CYEPCZN5.js";
|
|
20
20
|
import "./chunk-TFA6HPOA.js";
|
|
21
21
|
import "./chunk-F4TWWUMP.js";
|
|
22
22
|
import "./chunk-72A4L5JJ.js";
|
|
23
23
|
import "./chunk-A7Q43EUZ.js";
|
|
24
24
|
import "./chunk-S2V7RUCL.js";
|
|
25
|
-
import "./chunk-MRPOZBJC.js";
|
|
26
25
|
import "./chunk-S2HLHAZ4.js";
|
|
26
|
+
import "./chunk-MRPOZBJC.js";
|
|
27
27
|
import "./chunk-DM2T26WE.js";
|
|
28
28
|
import "./chunk-LDXUBPMO.js";
|
|
29
29
|
import "./chunk-FF6N7BXC.js";
|
package/dist/who-knows-cli.js
CHANGED
|
@@ -4,29 +4,29 @@ import {
|
|
|
4
4
|
renderWhoKnows,
|
|
5
5
|
renderWhoKnowsJson,
|
|
6
6
|
renderWhoKnowsText
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-
|
|
9
|
-
import "./chunk-
|
|
7
|
+
} from "./chunk-RG7ZWG3M.js";
|
|
8
|
+
import "./chunk-CMAGVPS2.js";
|
|
9
|
+
import "./chunk-GNC5X3J7.js";
|
|
10
10
|
import "./chunk-46WM6JX2.js";
|
|
11
11
|
import "./chunk-UHVXE24Y.js";
|
|
12
12
|
import "./chunk-D5F7TKMH.js";
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-BGBW4H7C.js";
|
|
14
|
+
import "./chunk-MQTCNXTG.js";
|
|
15
|
+
import "./chunk-T3FMRLWQ.js";
|
|
15
16
|
import "./chunk-7VO6E5UD.js";
|
|
16
17
|
import "./chunk-Z4TXB4K7.js";
|
|
17
18
|
import "./chunk-S7LWX2PQ.js";
|
|
18
19
|
import "./chunk-T2YX56QI.js";
|
|
19
|
-
import "./chunk-CYEPCZN5.js";
|
|
20
|
-
import "./chunk-T3FMRLWQ.js";
|
|
21
20
|
import "./chunk-4O6WRBGE.js";
|
|
22
21
|
import "./chunk-GUMZC2BO.js";
|
|
22
|
+
import "./chunk-CYEPCZN5.js";
|
|
23
23
|
import "./chunk-TFA6HPOA.js";
|
|
24
24
|
import "./chunk-F4TWWUMP.js";
|
|
25
25
|
import "./chunk-72A4L5JJ.js";
|
|
26
26
|
import "./chunk-A7Q43EUZ.js";
|
|
27
27
|
import "./chunk-S2V7RUCL.js";
|
|
28
|
-
import "./chunk-MRPOZBJC.js";
|
|
29
28
|
import "./chunk-S2HLHAZ4.js";
|
|
29
|
+
import "./chunk-MRPOZBJC.js";
|
|
30
30
|
import "./chunk-DM2T26WE.js";
|
|
31
31
|
import "./chunk-LDXUBPMO.js";
|
|
32
32
|
import "./chunk-FF6N7BXC.js";
|
package/dist/who-knows.js
CHANGED
|
@@ -9,28 +9,28 @@ import {
|
|
|
9
9
|
loadWhoKnowsEntities,
|
|
10
10
|
tokenizeTopic,
|
|
11
11
|
validateWhoKnowsInput
|
|
12
|
-
} from "./chunk-
|
|
13
|
-
import "./chunk-
|
|
12
|
+
} from "./chunk-CMAGVPS2.js";
|
|
13
|
+
import "./chunk-GNC5X3J7.js";
|
|
14
14
|
import "./chunk-46WM6JX2.js";
|
|
15
15
|
import "./chunk-UHVXE24Y.js";
|
|
16
16
|
import "./chunk-D5F7TKMH.js";
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
17
|
+
import "./chunk-BGBW4H7C.js";
|
|
18
|
+
import "./chunk-MQTCNXTG.js";
|
|
19
|
+
import "./chunk-T3FMRLWQ.js";
|
|
19
20
|
import "./chunk-7VO6E5UD.js";
|
|
20
21
|
import "./chunk-Z4TXB4K7.js";
|
|
21
22
|
import "./chunk-S7LWX2PQ.js";
|
|
22
23
|
import "./chunk-T2YX56QI.js";
|
|
23
|
-
import "./chunk-CYEPCZN5.js";
|
|
24
|
-
import "./chunk-T3FMRLWQ.js";
|
|
25
24
|
import "./chunk-4O6WRBGE.js";
|
|
26
25
|
import "./chunk-GUMZC2BO.js";
|
|
26
|
+
import "./chunk-CYEPCZN5.js";
|
|
27
27
|
import "./chunk-TFA6HPOA.js";
|
|
28
28
|
import "./chunk-F4TWWUMP.js";
|
|
29
29
|
import "./chunk-72A4L5JJ.js";
|
|
30
30
|
import "./chunk-A7Q43EUZ.js";
|
|
31
31
|
import "./chunk-S2V7RUCL.js";
|
|
32
|
-
import "./chunk-MRPOZBJC.js";
|
|
33
32
|
import "./chunk-S2HLHAZ4.js";
|
|
33
|
+
import "./chunk-MRPOZBJC.js";
|
|
34
34
|
import "./chunk-DM2T26WE.js";
|
|
35
35
|
import "./chunk-LDXUBPMO.js";
|
|
36
36
|
import "./chunk-FF6N7BXC.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/core",
|
|
3
|
-
"version": "9.69.
|
|
3
|
+
"version": "9.69.67",
|
|
4
4
|
"description": "Framework-agnostic Remnic memory engine — orchestrator, storage, extraction, search, trust zones",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -3317,7 +3317,7 @@
|
|
|
3317
3317
|
"core"
|
|
3318
3318
|
],
|
|
3319
3319
|
"peerDependencies": {
|
|
3320
|
-
"@remnic/coding-graph": "^9.69.
|
|
3320
|
+
"@remnic/coding-graph": "^9.69.67"
|
|
3321
3321
|
},
|
|
3322
3322
|
"peerDependenciesMeta": {
|
|
3323
3323
|
"@remnic/coding-graph": {
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
import type { AddressInfo } from "node:net";
|
|
4
|
+
import test from "node:test";
|
|
5
|
+
|
|
6
|
+
import { LocalLlmClient } from "./local-llm.js";
|
|
7
|
+
import { orderedLocalServers } from "./local-llm-servers.js";
|
|
8
|
+
import type { PluginConfig } from "./types.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A LiteLLM proxy answers `GET /` with the JSON string "LiteLLM: RUNNING" and
|
|
12
|
+
* runs a live completion against every deployment in its pool on `GET /health`.
|
|
13
|
+
* The availability probe must classify LiteLLM from `/` and never reach
|
|
14
|
+
* `/health`; before this test the once-a-minute probe was the largest load
|
|
15
|
+
* source on the pool behind the proxy.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
function createConfig(localLlmUrl: string): PluginConfig {
|
|
19
|
+
return {
|
|
20
|
+
localLlmEnabled: true,
|
|
21
|
+
localLlmModel: "test-local-model",
|
|
22
|
+
localLlmUrl,
|
|
23
|
+
localLlmTimeoutMs: 1_000,
|
|
24
|
+
localLlmRetry5xxCount: 0,
|
|
25
|
+
localLlmRetryBackoffMs: 1,
|
|
26
|
+
localLlmHeaders: {},
|
|
27
|
+
localLlmApiKey: undefined,
|
|
28
|
+
localLlmAuthHeader: false,
|
|
29
|
+
localLlm400TripThreshold: 3,
|
|
30
|
+
localLlm400CooldownMs: 60_000,
|
|
31
|
+
debug: false,
|
|
32
|
+
localLlmReasoningEffort: "none",
|
|
33
|
+
slowLogEnabled: false,
|
|
34
|
+
slowLogThresholdMs: 1_000,
|
|
35
|
+
} as unknown as PluginConfig;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function startServer(
|
|
39
|
+
handle: (path: string, res: http.ServerResponse) => void,
|
|
40
|
+
): Promise<{ url: string; paths: string[]; close(): Promise<void> }> {
|
|
41
|
+
const paths: string[] = [];
|
|
42
|
+
const server = http.createServer((req, res) => {
|
|
43
|
+
const path = req.url ?? "";
|
|
44
|
+
paths.push(path);
|
|
45
|
+
handle(path, res);
|
|
46
|
+
});
|
|
47
|
+
await new Promise<void>((resolve) => server.listen(0, "127.0.0.1", resolve));
|
|
48
|
+
const { port } = server.address() as AddressInfo;
|
|
49
|
+
return {
|
|
50
|
+
url: `http://127.0.0.1:${port}/v1`,
|
|
51
|
+
paths,
|
|
52
|
+
close: () => new Promise<void>((resolve) => server.close(() => resolve())),
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function json(res: http.ServerResponse, body: unknown): void {
|
|
57
|
+
res.writeHead(200, { "content-type": "application/json" });
|
|
58
|
+
res.end(JSON.stringify(body));
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function startLiteLlmShapedServer() {
|
|
62
|
+
return startServer((path, res) => {
|
|
63
|
+
if (path === "/") return json(res, "LiteLLM: RUNNING");
|
|
64
|
+
if (path === "/v1/models") return json(res, { data: [{ id: "test-local-model" }] });
|
|
65
|
+
json(res, { healthy_endpoints: [], unhealthy_endpoints: [] });
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
test("a LiteLLM proxy is detected from GET / and /health is never probed", async () => {
|
|
70
|
+
const server = await startLiteLlmShapedServer();
|
|
71
|
+
try {
|
|
72
|
+
const client = new LocalLlmClient(createConfig(server.url));
|
|
73
|
+
assert.equal(await client.checkAvailability(), true);
|
|
74
|
+
assert.equal(client.getDetectedType(), "litellm");
|
|
75
|
+
assert.ok(!server.paths.includes("/health"), `probe hit /health: ${server.paths.join(", ")}`);
|
|
76
|
+
assert.equal(server.paths.filter((p) => p === "/").length, 1, "GET / must be fetched once per pass");
|
|
77
|
+
} finally {
|
|
78
|
+
await server.close();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
test("LiteLLM is probed before any /health probe on every port; other orders are unchanged", () => {
|
|
83
|
+
for (const port of [8080, 8000, 11434, 1234, 4000, null]) {
|
|
84
|
+
const url = port === null ? "http://127.0.0.1/v1" : `http://127.0.0.1:${port}/v1`;
|
|
85
|
+
const order = orderedLocalServers(url);
|
|
86
|
+
const types = order.map((s) => s.type);
|
|
87
|
+
const litellmAt = types.indexOf("litellm");
|
|
88
|
+
const firstHealth = order.findIndex((s) => s.healthEndpoint === "/health");
|
|
89
|
+
assert.ok(litellmAt !== -1 && litellmAt < firstHealth, `${url}: ${types.join(" > ")}`);
|
|
90
|
+
}
|
|
91
|
+
// Port-matched shapes with harmless probes keep the lead they had before.
|
|
92
|
+
assert.equal(orderedLocalServers("http://127.0.0.1:1234/v1")[0]?.type, "lmstudio");
|
|
93
|
+
assert.equal(orderedLocalServers("http://127.0.0.1:11434/v1")[0]?.type, "ollama");
|
|
94
|
+
// LiteLLM displaces the port-matched llama.cpp / vLLM /health probes.
|
|
95
|
+
assert.deepEqual(orderedLocalServers("http://127.0.0.1:8080/v1").map((s) => s.type).slice(0, 3), ["litellm", "llamacpp", "mlx"]);
|
|
96
|
+
assert.deepEqual(orderedLocalServers("http://127.0.0.1:8000/v1").map((s) => s.type).slice(0, 2), ["litellm", "vllm"]);
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
test("a root response is fetched once even when a later detector matches it", async () => {
|
|
100
|
+
const server = await startServer((path, res) => {
|
|
101
|
+
if (path === "/") {
|
|
102
|
+
res.writeHead(200, { "content-type": "text/plain" });
|
|
103
|
+
res.end("Ollama is running");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
json(res, {});
|
|
107
|
+
});
|
|
108
|
+
try {
|
|
109
|
+
const client = new LocalLlmClient(createConfig(server.url));
|
|
110
|
+
assert.equal(await client.checkAvailability(), true);
|
|
111
|
+
assert.equal(client.getDetectedType(), "ollama");
|
|
112
|
+
assert.equal(server.paths.filter((p) => p === "/").length, 1, `paths: ${server.paths.join(", ")}`);
|
|
113
|
+
} finally {
|
|
114
|
+
await server.close();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server shapes the local-LLM availability probe can recognise, and the order
|
|
3
|
+
* in which they are tried for a configured base URL. Split from local-llm.ts
|
|
4
|
+
* (file-size ratchet) — no runtime dependency on the client.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export type LocalLlmType = "litellm" | "lmstudio" | "ollama" | "mlx" | "vllm" | "llamacpp" | "generic";
|
|
8
|
+
|
|
9
|
+
export interface LocalServerConfig {
|
|
10
|
+
type: LocalLlmType;
|
|
11
|
+
defaultPort: number;
|
|
12
|
+
healthEndpoint: string;
|
|
13
|
+
modelsEndpoint: string;
|
|
14
|
+
detectFn: (response: unknown) => boolean;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function isObjectRecord(value: unknown): value is Record<string, unknown> {
|
|
18
|
+
return typeof value === "object" && value !== null;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function explicitPortFromUrl(s: string): number | null {
|
|
22
|
+
try {
|
|
23
|
+
const parsed = new URL(s);
|
|
24
|
+
if (!parsed.port) return null;
|
|
25
|
+
const port = Number(parsed.port);
|
|
26
|
+
return Number.isInteger(port) ? port : null;
|
|
27
|
+
} catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// LiteLLM must be recognised before the llama.cpp / vLLM probes: on a LiteLLM
|
|
33
|
+
// proxy `GET /health` runs a live completion against EVERY deployment in its
|
|
34
|
+
// pool, so a once-a-minute 2 s probe turns into a permanent load generator on
|
|
35
|
+
// the backends (4,600 probe completions in 12 h observed). `GET /` is
|
|
36
|
+
// auth-gated on LiteLLM and answers the JSON string "LiteLLM: RUNNING".
|
|
37
|
+
// Not part of LOCAL_SERVERS: `orderedLocalServers` positions it explicitly.
|
|
38
|
+
const LITELLM_SERVER: LocalServerConfig = {
|
|
39
|
+
type: "litellm",
|
|
40
|
+
defaultPort: 4000,
|
|
41
|
+
healthEndpoint: "/",
|
|
42
|
+
modelsEndpoint: "/v1/models",
|
|
43
|
+
detectFn: (resp) => typeof resp === "string" && resp.includes("LiteLLM"),
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
const LOCAL_SERVERS: LocalServerConfig[] = [
|
|
47
|
+
{
|
|
48
|
+
type: "ollama",
|
|
49
|
+
defaultPort: 11434,
|
|
50
|
+
healthEndpoint: "/",
|
|
51
|
+
modelsEndpoint: "/api/tags",
|
|
52
|
+
detectFn: (resp) => typeof resp === "string" && resp.includes("Ollama"),
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
type: "llamacpp",
|
|
56
|
+
defaultPort: 8080,
|
|
57
|
+
healthEndpoint: "/health",
|
|
58
|
+
modelsEndpoint: "/v1/models",
|
|
59
|
+
detectFn: (resp) => isObjectRecord(resp) && resp.status === "ok",
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: "mlx",
|
|
63
|
+
defaultPort: 8080,
|
|
64
|
+
healthEndpoint: "/v1/models",
|
|
65
|
+
modelsEndpoint: "/v1/models",
|
|
66
|
+
detectFn: (resp) => isObjectRecord(resp) && Array.isArray(resp.data),
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
type: "lmstudio",
|
|
70
|
+
defaultPort: 1234,
|
|
71
|
+
healthEndpoint: "/v1/models",
|
|
72
|
+
modelsEndpoint: "/v1/models",
|
|
73
|
+
detectFn: (resp) => isObjectRecord(resp) && Array.isArray(resp.data),
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
type: "vllm",
|
|
77
|
+
defaultPort: 8000,
|
|
78
|
+
healthEndpoint: "/health",
|
|
79
|
+
modelsEndpoint: "/v1/models",
|
|
80
|
+
detectFn: (resp) => resp === "" || (isObjectRecord(resp) && !("status" in resp)),
|
|
81
|
+
},
|
|
82
|
+
];
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Probe order for a configured base URL. Entries whose default port matches
|
|
86
|
+
* the URL's explicit port go first, in the same order as before; the LiteLLM
|
|
87
|
+
* entry is placed immediately ahead of the first entry that would probe
|
|
88
|
+
* `GET /health`, so that request never reaches a LiteLLM proxy on any port.
|
|
89
|
+
* LM Studio / Ollama / MLX probes are harmless on LiteLLM and keep their spot.
|
|
90
|
+
*/
|
|
91
|
+
export function orderedLocalServers(configuredBaseUrl: string): LocalServerConfig[] {
|
|
92
|
+
const configuredPort = explicitPortFromUrl(configuredBaseUrl);
|
|
93
|
+
const matching = configuredPort === null
|
|
94
|
+
? []
|
|
95
|
+
: LOCAL_SERVERS.filter((serverConfig) => serverConfig.defaultPort === configuredPort);
|
|
96
|
+
const matchingTypes = new Set(matching.map((serverConfig) => serverConfig.type));
|
|
97
|
+
const ordered = [
|
|
98
|
+
...matching,
|
|
99
|
+
...LOCAL_SERVERS.filter((serverConfig) => !matchingTypes.has(serverConfig.type)),
|
|
100
|
+
];
|
|
101
|
+
const firstHealthProbe = ordered.findIndex((serverConfig) => serverConfig.healthEndpoint === "/health");
|
|
102
|
+
ordered.splice(firstHealthProbe === -1 ? ordered.length : firstHealthProbe, 0, LITELLM_SERVER);
|
|
103
|
+
return ordered;
|
|
104
|
+
}
|
package/src/local-llm.ts
CHANGED
|
@@ -22,6 +22,13 @@ import {
|
|
|
22
22
|
type LocalLlmChatCompletionOptions,
|
|
23
23
|
type LocalLlmChatCompletionResult,
|
|
24
24
|
} from "./local-llm-helpers.js";
|
|
25
|
+
import {
|
|
26
|
+
isObjectRecord,
|
|
27
|
+
orderedLocalServers,
|
|
28
|
+
type LocalLlmType,
|
|
29
|
+
} from "./local-llm-servers.js";
|
|
30
|
+
|
|
31
|
+
export type { LocalLlmType } from "./local-llm-servers.js";
|
|
25
32
|
|
|
26
33
|
/** Trim trailing slash characters without backtracking regex. */
|
|
27
34
|
function trimTrailingSlashes(s: string): string {
|
|
@@ -34,21 +41,6 @@ function stripTrailingV1Path(s: string): string {
|
|
|
34
41
|
return s.endsWith("/v1") ? s.slice(0, -3) : s;
|
|
35
42
|
}
|
|
36
43
|
|
|
37
|
-
function explicitPortFromUrl(s: string): number | null {
|
|
38
|
-
try {
|
|
39
|
-
const parsed = new URL(s);
|
|
40
|
-
if (!parsed.port) return null;
|
|
41
|
-
const port = Number(parsed.port);
|
|
42
|
-
return Number.isInteger(port) ? port : null;
|
|
43
|
-
} catch {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function isObjectRecord(value: unknown): value is Record<string, unknown> {
|
|
49
|
-
return typeof value === "object" && value !== null;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
44
|
function isLlamaCppPropsResponse(value: unknown): boolean {
|
|
53
45
|
return (
|
|
54
46
|
isObjectRecord(value) &&
|
|
@@ -118,15 +110,6 @@ function isLmStudioNativeModelsResponse(value: unknown): boolean {
|
|
|
118
110
|
return isLmStudioApiV1ModelsResponse(value) || isLmStudioApiV0ModelsResponse(value);
|
|
119
111
|
}
|
|
120
112
|
|
|
121
|
-
/**
|
|
122
|
-
* Local LLM client for OpenAI-compatible endpoints (LM Studio, Ollama, MLX, etc.)
|
|
123
|
-
*
|
|
124
|
-
* Based on openclaw-tactician's provider detection patterns for consistency.
|
|
125
|
-
* Provides privacy-preserving, cost-effective LLM operations with
|
|
126
|
-
* graceful fallback to cloud providers when local LLM is unavailable.
|
|
127
|
-
*/
|
|
128
|
-
export type LocalLlmType = "lmstudio" | "ollama" | "mlx" | "vllm" | "llamacpp" | "generic";
|
|
129
|
-
|
|
130
113
|
/**
|
|
131
114
|
* Backends known to honor `chat_template_kwargs: { enable_thinking: false }`
|
|
132
115
|
* on OpenAI-compatible `/v1/chat/completions`. LM Studio, vLLM, and
|
|
@@ -160,66 +143,6 @@ const THINKING_SUPPRESSED_OPERATIONS: ReadonlySet<string> = new Set([
|
|
|
160
143
|
"hourly_summary_extended",
|
|
161
144
|
]);
|
|
162
145
|
|
|
163
|
-
interface LocalServerConfig {
|
|
164
|
-
type: LocalLlmType;
|
|
165
|
-
defaultPort: number;
|
|
166
|
-
healthEndpoint: string;
|
|
167
|
-
modelsEndpoint: string;
|
|
168
|
-
detectFn: (response: unknown) => boolean;
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
const LOCAL_SERVERS: LocalServerConfig[] = [
|
|
172
|
-
{
|
|
173
|
-
type: "ollama",
|
|
174
|
-
defaultPort: 11434,
|
|
175
|
-
healthEndpoint: "/",
|
|
176
|
-
modelsEndpoint: "/api/tags",
|
|
177
|
-
detectFn: (resp) => typeof resp === "string" && resp.includes("Ollama"),
|
|
178
|
-
},
|
|
179
|
-
{
|
|
180
|
-
type: "llamacpp",
|
|
181
|
-
defaultPort: 8080,
|
|
182
|
-
healthEndpoint: "/health",
|
|
183
|
-
modelsEndpoint: "/v1/models",
|
|
184
|
-
detectFn: (resp) => isObjectRecord(resp) && resp.status === "ok",
|
|
185
|
-
},
|
|
186
|
-
{
|
|
187
|
-
type: "mlx",
|
|
188
|
-
defaultPort: 8080,
|
|
189
|
-
healthEndpoint: "/v1/models",
|
|
190
|
-
modelsEndpoint: "/v1/models",
|
|
191
|
-
detectFn: (resp) => isObjectRecord(resp) && Array.isArray(resp.data),
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
type: "lmstudio",
|
|
195
|
-
defaultPort: 1234,
|
|
196
|
-
healthEndpoint: "/v1/models",
|
|
197
|
-
modelsEndpoint: "/v1/models",
|
|
198
|
-
detectFn: (resp) => isObjectRecord(resp) && Array.isArray(resp.data),
|
|
199
|
-
},
|
|
200
|
-
{
|
|
201
|
-
type: "vllm",
|
|
202
|
-
defaultPort: 8000,
|
|
203
|
-
healthEndpoint: "/health",
|
|
204
|
-
modelsEndpoint: "/v1/models",
|
|
205
|
-
detectFn: (resp) => resp === "" || (isObjectRecord(resp) && !("status" in resp)),
|
|
206
|
-
},
|
|
207
|
-
];
|
|
208
|
-
|
|
209
|
-
function orderedLocalServers(configuredBaseUrl: string): LocalServerConfig[] {
|
|
210
|
-
const configuredPort = explicitPortFromUrl(configuredBaseUrl);
|
|
211
|
-
if (configuredPort === null) return LOCAL_SERVERS;
|
|
212
|
-
const matching = LOCAL_SERVERS.filter(
|
|
213
|
-
(serverConfig) => serverConfig.defaultPort === configuredPort,
|
|
214
|
-
);
|
|
215
|
-
if (matching.length === 0) return LOCAL_SERVERS;
|
|
216
|
-
const matchingTypes = new Set(matching.map((serverConfig) => serverConfig.type));
|
|
217
|
-
return [
|
|
218
|
-
...matching,
|
|
219
|
-
...LOCAL_SERVERS.filter((serverConfig) => !matchingTypes.has(serverConfig.type)),
|
|
220
|
-
];
|
|
221
|
-
}
|
|
222
|
-
|
|
223
146
|
export interface LocalModelInfo {
|
|
224
147
|
id: string;
|
|
225
148
|
contextWindow?: number;
|
|
@@ -244,6 +167,13 @@ type LocalLlmBackendState = {
|
|
|
244
167
|
untilMs: number;
|
|
245
168
|
reason: string;
|
|
246
169
|
};
|
|
170
|
+
/**
|
|
171
|
+
* Local LLM client for OpenAI-compatible endpoints (LM Studio, Ollama, MLX, etc.)
|
|
172
|
+
*
|
|
173
|
+
* Based on openclaw-tactician's provider detection patterns for consistency.
|
|
174
|
+
* Provides privacy-preserving, cost-effective LLM operations with
|
|
175
|
+
* graceful fallback to cloud providers when local LLM is unavailable.
|
|
176
|
+
*/
|
|
247
177
|
export class LocalLlmClient {
|
|
248
178
|
private config: PluginConfig;
|
|
249
179
|
private isAvailable: boolean | null = null;
|
|
@@ -435,6 +365,16 @@ export class LocalLlmClient {
|
|
|
435
365
|
// is down (issue #2210). Tracked separately so a loaded daemon cannot cache
|
|
436
366
|
// itself into a blackout.
|
|
437
367
|
let sawAbortedProbe = false;
|
|
368
|
+
// Several server shapes share a probe URL (LiteLLM and Ollama both use
|
|
369
|
+
// `/`); fetch each URL once per pass.
|
|
370
|
+
const probed = new Map<string, ProbeFetchResult>();
|
|
371
|
+
const probeOnce = async (url: string): Promise<ProbeFetchResult> => {
|
|
372
|
+
const cached = probed.get(url);
|
|
373
|
+
if (cached) return cached;
|
|
374
|
+
const result = await this.fetchWithTimeout(url, 2000, undefined, signal);
|
|
375
|
+
probed.set(url, result);
|
|
376
|
+
return result;
|
|
377
|
+
};
|
|
438
378
|
|
|
439
379
|
// Try to detect which server type is running
|
|
440
380
|
if (signal?.aborted) return false;
|
|
@@ -442,7 +382,7 @@ export class LocalLlmClient {
|
|
|
442
382
|
const healthUrl = `${probeBaseUrl}${serverConfig.healthEndpoint}`;
|
|
443
383
|
log.debug(`checking ${serverConfig.type} at ${healthUrl}`);
|
|
444
384
|
|
|
445
|
-
const result = await
|
|
385
|
+
const result = await probeOnce(healthUrl);
|
|
446
386
|
if (result.aborted) sawAbortedProbe = true;
|
|
447
387
|
if (signal?.aborted) return false;
|
|
448
388
|
if (result.ok && serverConfig.detectFn(result.data)) {
|