darabos commited on
Commit
dcedc35
·
1 Parent(s): 94f083f

Run Open WebUI against LynxScribe in LynxKite.

Browse files
README.md CHANGED
@@ -7,16 +7,13 @@ original LynxKite. The primary goals of this rewrite are:
7
  - More extensible backend. Make it easy to add new LynxKite boxes. Make it easy to use our frontend for other purposes,
8
  configuring and executing other pipelines.
9
 
10
- Current status: **PROTOTYPE**
11
-
12
  ## Installation
13
 
14
  To run the backend:
15
 
16
  ```bash
17
- pip install -r requirements.txt
18
- PYTHONPATH=. pydantic2ts --module server.workspace --output ./web/src/apiTypes.ts
19
- uvicorn server.main:app --reload
20
  ```
21
 
22
  To run the frontend:
@@ -26,3 +23,9 @@ cd web
26
  npm i
27
  npm run dev
28
  ```
 
 
 
 
 
 
 
7
  - More extensible backend. Make it easy to add new LynxKite boxes. Make it easy to use our frontend for other purposes,
8
  configuring and executing other pipelines.
9
 
 
 
10
  ## Installation
11
 
12
  To run the backend:
13
 
14
  ```bash
15
+ PYTHONPATH=. uv run pydantic2ts --module server.workspace --output ./web/src/apiTypes.ts --json2ts-cmd "npm exec --prefix web json2ts"
16
+ uv run fastapi run server/main.py --reload
 
17
  ```
18
 
19
  To run the frontend:
 
23
  npm i
24
  npm run dev
25
  ```
26
+
27
+ To run a chat UI for LynxScribe workspaces:
28
+
29
+ ```bash
30
+ WEBUI_AUTH=false OPENAI_API_BASE_URL=http://localhost:8000/api/service/server.lynxscribe_ops uvx open-webui serve
31
+ ```
server/executors/one_by_one.py CHANGED
@@ -127,12 +127,13 @@ async def execute(ws, catalog, cache=None):
127
  results = []
128
  for task in ts:
129
  try:
130
- inputs = [
131
- batch_inputs[(n, i.name)]
132
- if i.position in "top or bottom"
133
- else task
134
- for i in op.inputs.values()
135
- ]
 
136
  if cache is not None:
137
  key = make_cache_key((inputs, params))
138
  if key not in cache:
 
127
  results = []
128
  for task in ts:
129
  try:
130
+ inputs = []
131
+ for i in op.inputs.values():
132
+ if i.position in "top or bottom":
133
+ assert (n, i.name) in batch_inputs, f"{i.name} is missing"
134
+ inputs.append(batch_inputs[(n, i.name)])
135
+ else:
136
+ inputs.append(task)
137
  if cache is not None:
138
  key = make_cache_key((inputs, params))
139
  if key not in cache:
server/llm_ops.py CHANGED
@@ -13,7 +13,7 @@ from .executors import one_by_one
13
  chat_client = openai.OpenAI(base_url="http://localhost:8080/v1")
14
  embedding_client = openai.OpenAI(base_url="http://localhost:7997/")
15
  jinja = jinja2.Environment()
16
- chroma_client = chromadb.Client()
17
  LLM_CACHE = {}
18
  ENV = "LLM logic"
19
  one_by_one.register(ENV)
@@ -178,12 +178,15 @@ def rag(
178
  num_matches: int = 10,
179
  _ctx: one_by_one.Context,
180
  ):
 
181
  if engine == RagEngine.Chroma:
182
  last = _ctx.last_result
183
  if last:
184
  collection = last["_collection"]
185
  else:
186
  collection_name = _ctx.node.id.replace(" ", "_")
 
 
187
  for c in chroma_client.list_collections():
188
  if c.name == collection_name:
189
  chroma_client.delete_collection(name=collection_name)
 
13
  chat_client = openai.OpenAI(base_url="http://localhost:8080/v1")
14
  embedding_client = openai.OpenAI(base_url="http://localhost:7997/")
15
  jinja = jinja2.Environment()
16
+ chroma_client = None
17
  LLM_CACHE = {}
18
  ENV = "LLM logic"
19
  one_by_one.register(ENV)
 
178
  num_matches: int = 10,
179
  _ctx: one_by_one.Context,
180
  ):
181
+ global chroma_client
182
  if engine == RagEngine.Chroma:
183
  last = _ctx.last_result
184
  if last:
185
  collection = last["_collection"]
186
  else:
187
  collection_name = _ctx.node.id.replace(" ", "_")
188
+ if chroma_client is None:
189
+ chroma_client = chromadb.Client()
190
  for c in chroma_client.list_collections():
191
  if c.name == collection_name:
192
  chroma_client.delete_collection(name=collection_name)
server/lynxkite_ops.py CHANGED
@@ -218,7 +218,7 @@ def sql(bundle: Bundle, *, query: ops.LongStr, save_as: str = "result"):
218
  # TODO: Currently `collect()` moves the data from cuDF to Polars. Then we convert it to Pandas,
219
  # which (hopefully) puts it back into cuDF. Hopefully we will be able to keep it in cuDF.
220
  else:
221
- res = pl.SQLContext(bundle.dfs).execute(query)
222
  bundle.dfs[save_as] = res
223
  return bundle
224
 
 
218
  # TODO: Currently `collect()` moves the data from cuDF to Polars. Then we convert it to Pandas,
219
  # which (hopefully) puts it back into cuDF. Hopefully we will be able to keep it in cuDF.
220
  else:
221
+ res = pl.SQLContext(bundle.dfs).execute(query).collect().to_pandas()
222
  bundle.dfs[save_as] = res
223
  return bundle
224
 
server/main.py CHANGED
@@ -1,3 +1,6 @@
 
 
 
1
  import dataclasses
2
  import fastapi
3
  import importlib
@@ -87,8 +90,15 @@ def make_dir(req: dict):
87
  return list_dir(path.parent)
88
 
89
 
90
- @app.post("/api/service")
91
- async def service(req: dict):
92
  """Executors can provide extra HTTP APIs through the /api/service endpoint."""
93
- module = lynxkite_modules[req["module"]]
94
- return await module.api_service(req)
 
 
 
 
 
 
 
 
1
+ # TODO: Make this conditional. Until then just comment/uncomment it to use cuDF Pandas.
2
+ # import cudf.pandas
3
+ # cudf.pandas.install()
4
  import dataclasses
5
  import fastapi
6
  import importlib
 
90
  return list_dir(path.parent)
91
 
92
 
93
+ @app.get("/api/service/{module_path:path}")
94
+ async def service_get(req: fastapi.Request, module_path: str):
95
  """Executors can provide extra HTTP APIs through the /api/service endpoint."""
96
+ module = lynxkite_modules[module_path.split("/")[0]]
97
+ return await module.api_service_get(req)
98
+
99
+
100
+ @app.post("/api/service/{module_path:path}")
101
+ async def service_post(req: fastapi.Request, module_path: str):
102
+ """Executors can provide extra HTTP APIs through the /api/service endpoint."""
103
+ module = lynxkite_modules[module_path.split("/")[0]]
104
+ return await module.api_service_post(req)
web/package-lock.json CHANGED
@@ -20,6 +20,7 @@
20
  "daisyui": "^4.12.20",
21
  "echarts": "^5.5.1",
22
  "fuse.js": "^7.0.0",
 
23
  "react": "^18.3.1",
24
  "react-dom": "^18.3.1",
25
  "react-markdown": "^9.0.1",
@@ -97,6 +98,23 @@
97
  "url": "https://github.com/sponsors/antfu"
98
  }
99
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
100
  "node_modules/@babel/code-frame": {
101
  "version": "7.26.2",
102
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
@@ -687,6 +705,12 @@
687
  "@jridgewell/sourcemap-codec": "^1.4.14"
688
  }
689
  },
 
 
 
 
 
 
690
  "node_modules/@nodelib/fs.scandir": {
691
  "version": "2.1.5",
692
  "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
@@ -1333,7 +1357,12 @@
1333
  "version": "7.0.15",
1334
  "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
1335
  "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
1336
- "dev": true,
 
 
 
 
 
1337
  "license": "MIT"
1338
  },
1339
  "node_modules/@types/mdast": {
@@ -3339,7 +3368,6 @@
3339
  "version": "2.1.1",
3340
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
3341
  "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
3342
- "dev": true,
3343
  "license": "MIT",
3344
  "engines": {
3345
  "node": ">=0.10.0"
@@ -3359,7 +3387,6 @@
3359
  "version": "4.0.3",
3360
  "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
3361
  "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
3362
- "dev": true,
3363
  "license": "MIT",
3364
  "dependencies": {
3365
  "is-extglob": "^2.1.1"
@@ -3486,6 +3513,29 @@
3486
  "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
3487
  "license": "MIT"
3488
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3489
  "node_modules/json-schema-traverse": {
3490
  "version": "0.4.1",
3491
  "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
@@ -3760,6 +3810,12 @@
3760
  "url": "https://github.com/sponsors/sindresorhus"
3761
  }
3762
  },
 
 
 
 
 
 
3763
  "node_modules/lodash.debounce": {
3764
  "version": "4.0.8",
3765
  "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
@@ -4452,6 +4508,15 @@
4452
  "node": "*"
4453
  }
4454
  },
 
 
 
 
 
 
 
 
 
4455
  "node_modules/minipass": {
4456
  "version": "7.1.2",
4457
  "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
@@ -4985,6 +5050,21 @@
4985
  "node": ">= 0.8.0"
4986
  }
4987
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
4988
  "node_modules/property-information": {
4989
  "version": "6.5.0",
4990
  "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz",
@@ -5695,6 +5775,45 @@
5695
  "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
5696
  "license": "MIT"
5697
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5698
  "node_modules/to-regex-range": {
5699
  "version": "5.0.1",
5700
  "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
 
20
  "daisyui": "^4.12.20",
21
  "echarts": "^5.5.1",
22
  "fuse.js": "^7.0.0",
23
+ "json-schema-to-typescript": "^15.0.3",
24
  "react": "^18.3.1",
25
  "react-dom": "^18.3.1",
26
  "react-markdown": "^9.0.1",
 
98
  "url": "https://github.com/sponsors/antfu"
99
  }
100
  },
101
+ "node_modules/@apidevtools/json-schema-ref-parser": {
102
+ "version": "11.7.3",
103
+ "resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.7.3.tgz",
104
+ "integrity": "sha512-WApSdLdXEBb/1FUPca2lteASewEfpjEYJ8oXZP+0gExK5qSfsEKBKcA+WjY6Q4wvXwyv0+W6Kvc372pSceib9w==",
105
+ "license": "MIT",
106
+ "dependencies": {
107
+ "@jsdevtools/ono": "^7.1.3",
108
+ "@types/json-schema": "^7.0.15",
109
+ "js-yaml": "^4.1.0"
110
+ },
111
+ "engines": {
112
+ "node": ">= 16"
113
+ },
114
+ "funding": {
115
+ "url": "https://github.com/sponsors/philsturgeon"
116
+ }
117
+ },
118
  "node_modules/@babel/code-frame": {
119
  "version": "7.26.2",
120
  "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
 
705
  "@jridgewell/sourcemap-codec": "^1.4.14"
706
  }
707
  },
708
+ "node_modules/@jsdevtools/ono": {
709
+ "version": "7.1.3",
710
+ "resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
711
+ "integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
712
+ "license": "MIT"
713
+ },
714
  "node_modules/@nodelib/fs.scandir": {
715
  "version": "2.1.5",
716
  "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
 
1357
  "version": "7.0.15",
1358
  "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
1359
  "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
1360
+ "license": "MIT"
1361
+ },
1362
+ "node_modules/@types/lodash": {
1363
+ "version": "4.17.14",
1364
+ "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.14.tgz",
1365
+ "integrity": "sha512-jsxagdikDiDBeIRaPYtArcT8my4tN1og7MtMRquFT3XNA6axxyHDRUemqDz/taRDdOUn0GnGHRCuff4q48sW9A==",
1366
  "license": "MIT"
1367
  },
1368
  "node_modules/@types/mdast": {
 
3368
  "version": "2.1.1",
3369
  "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
3370
  "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
 
3371
  "license": "MIT",
3372
  "engines": {
3373
  "node": ">=0.10.0"
 
3387
  "version": "4.0.3",
3388
  "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
3389
  "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
 
3390
  "license": "MIT",
3391
  "dependencies": {
3392
  "is-extglob": "^2.1.1"
 
3513
  "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==",
3514
  "license": "MIT"
3515
  },
3516
+ "node_modules/json-schema-to-typescript": {
3517
+ "version": "15.0.3",
3518
+ "resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.3.tgz",
3519
+ "integrity": "sha512-iOKdzTUWEVM4nlxpFudFsWyUiu/Jakkga4OZPEt7CGoSEsAsUgdOZqR6pcgx2STBek9Gm4hcarJpXSzIvZ/hKA==",
3520
+ "license": "MIT",
3521
+ "dependencies": {
3522
+ "@apidevtools/json-schema-ref-parser": "^11.5.5",
3523
+ "@types/json-schema": "^7.0.15",
3524
+ "@types/lodash": "^4.17.7",
3525
+ "is-glob": "^4.0.3",
3526
+ "js-yaml": "^4.1.0",
3527
+ "lodash": "^4.17.21",
3528
+ "minimist": "^1.2.8",
3529
+ "prettier": "^3.2.5",
3530
+ "tinyglobby": "^0.2.9"
3531
+ },
3532
+ "bin": {
3533
+ "json2ts": "dist/src/cli.js"
3534
+ },
3535
+ "engines": {
3536
+ "node": ">=16.0.0"
3537
+ }
3538
+ },
3539
  "node_modules/json-schema-traverse": {
3540
  "version": "0.4.1",
3541
  "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
 
3810
  "url": "https://github.com/sponsors/sindresorhus"
3811
  }
3812
  },
3813
+ "node_modules/lodash": {
3814
+ "version": "4.17.21",
3815
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
3816
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
3817
+ "license": "MIT"
3818
+ },
3819
  "node_modules/lodash.debounce": {
3820
  "version": "4.0.8",
3821
  "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
 
4508
  "node": "*"
4509
  }
4510
  },
4511
+ "node_modules/minimist": {
4512
+ "version": "1.2.8",
4513
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
4514
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
4515
+ "license": "MIT",
4516
+ "funding": {
4517
+ "url": "https://github.com/sponsors/ljharb"
4518
+ }
4519
+ },
4520
  "node_modules/minipass": {
4521
  "version": "7.1.2",
4522
  "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
 
5050
  "node": ">= 0.8.0"
5051
  }
5052
  },
5053
+ "node_modules/prettier": {
5054
+ "version": "3.4.2",
5055
+ "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz",
5056
+ "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==",
5057
+ "license": "MIT",
5058
+ "bin": {
5059
+ "prettier": "bin/prettier.cjs"
5060
+ },
5061
+ "engines": {
5062
+ "node": ">=14"
5063
+ },
5064
+ "funding": {
5065
+ "url": "https://github.com/prettier/prettier?sponsor=1"
5066
+ }
5067
+ },
5068
  "node_modules/property-information": {
5069
  "version": "6.5.0",
5070
  "resolved": "https://registry.npmjs.org/property-information/-/property-information-6.5.0.tgz",
 
5775
  "integrity": "sha512-WiCJLEECkO18gwqIp6+hJg0//p23HXp4S+gGtAKu3mI2F2/sXC4FvHvXvB0zJVVaTPhx1/tOwdbRsa1sOBIKqQ==",
5776
  "license": "MIT"
5777
  },
5778
+ "node_modules/tinyglobby": {
5779
+ "version": "0.2.10",
5780
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz",
5781
+ "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==",
5782
+ "license": "MIT",
5783
+ "dependencies": {
5784
+ "fdir": "^6.4.2",
5785
+ "picomatch": "^4.0.2"
5786
+ },
5787
+ "engines": {
5788
+ "node": ">=12.0.0"
5789
+ }
5790
+ },
5791
+ "node_modules/tinyglobby/node_modules/fdir": {
5792
+ "version": "6.4.2",
5793
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.2.tgz",
5794
+ "integrity": "sha512-KnhMXsKSPZlAhp7+IjUkRZKPb4fUyccpDrdFXbi4QL1qkmFh9kVY09Yox+n4MaOb3lHZ1Tv829C3oaaXoMYPDQ==",
5795
+ "license": "MIT",
5796
+ "peerDependencies": {
5797
+ "picomatch": "^3 || ^4"
5798
+ },
5799
+ "peerDependenciesMeta": {
5800
+ "picomatch": {
5801
+ "optional": true
5802
+ }
5803
+ }
5804
+ },
5805
+ "node_modules/tinyglobby/node_modules/picomatch": {
5806
+ "version": "4.0.2",
5807
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
5808
+ "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
5809
+ "license": "MIT",
5810
+ "engines": {
5811
+ "node": ">=12"
5812
+ },
5813
+ "funding": {
5814
+ "url": "https://github.com/sponsors/jonschlinkert"
5815
+ }
5816
+ },
5817
  "node_modules/to-regex-range": {
5818
  "version": "5.0.1",
5819
  "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
web/package.json CHANGED
@@ -22,6 +22,7 @@
22
  "daisyui": "^4.12.20",
23
  "echarts": "^5.5.1",
24
  "fuse.js": "^7.0.0",
 
25
  "react": "^18.3.1",
26
  "react-dom": "^18.3.1",
27
  "react-markdown": "^9.0.1",
 
22
  "daisyui": "^4.12.20",
23
  "echarts": "^5.5.1",
24
  "fuse.js": "^7.0.0",
25
+ "json-schema-to-typescript": "^15.0.3",
26
  "react": "^18.3.1",
27
  "react-dom": "^18.3.1",
28
  "react-markdown": "^9.0.1",
web/src/apiTypes.ts CHANGED
@@ -5,6 +5,13 @@
5
  /* Do not modify it by hand - just update the pydantic models and then re-run the script
6
  */
7
 
 
 
 
 
 
 
 
8
  export interface BaseConfig {
9
  [k: string]: unknown;
10
  }
 
5
  /* Do not modify it by hand - just update the pydantic models and then re-run the script
6
  */
7
 
8
+ /* eslint-disable */
9
+ /**
10
+ * This file was automatically generated by json-schema-to-typescript.
11
+ * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
12
+ * and run json-schema-to-typescript to regenerate this file.
13
+ */
14
+
15
  export interface BaseConfig {
16
  [k: string]: unknown;
17
  }