genlayer 0.10.2 → 0.11.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
 
2
2
 
3
+ ## 0.11.1 (2025-02-05)
4
+
5
+ ## 0.11.0 (2025-01-31)
6
+
7
+
8
+ ### Features
9
+
10
+ * Enhance Ollama Command Workflow and Default Model Handling ([#171](https://github.com/yeagerai/genlayer-cli/issues/171)) ([3dc7a96](https://github.com/yeagerai/genlayer-cli/commit/3dc7a9673ada8116b1fb99e089439a75e06237ec))
11
+
3
12
  ## 0.10.2 (2025-01-30)
4
13
 
5
14
 
package/dist/index.js CHANGED
@@ -54537,7 +54537,7 @@ var {
54537
54537
  } = import_index.default;
54538
54538
 
54539
54539
  // package.json
54540
- var version = "0.10.2";
54540
+ var version = "0.11.1";
54541
54541
  var package_default = {
54542
54542
  name: "genlayer",
54543
54543
  version,
@@ -57581,13 +57581,50 @@ var OllamaAction = class {
57581
57581
  this.docker = new import_dockerode2.default();
57582
57582
  }
57583
57583
  async updateModel(modelName) {
57584
- await this.executeModelCommand("pull", modelName, `Model "${modelName}" updated successfully`);
57584
+ const providersAndModels = await rpcClient.request({
57585
+ method: "sim_getProvidersAndModels",
57586
+ params: []
57587
+ });
57588
+ const existingOllamaProvider = providersAndModels.result.find(
57589
+ (entry) => entry.plugin === "ollama"
57590
+ );
57591
+ if (!existingOllamaProvider) {
57592
+ throw new Error("No existing 'ollama' provider found. Unable to add/update a model.");
57593
+ }
57594
+ await this.executeModelCommand(
57595
+ "pull",
57596
+ modelName,
57597
+ `Model "${modelName}" updated successfully`
57598
+ );
57599
+ const existingModel = providersAndModels.result.some(
57600
+ (entry) => entry.plugin === "ollama" && entry.model === modelName
57601
+ );
57602
+ if (!existingModel) {
57603
+ console.log(`Model "${modelName}" not found in Provider Presets. Adding...`);
57604
+ const newModelConfig = {
57605
+ config: existingOllamaProvider.config,
57606
+ model: modelName,
57607
+ plugin: "ollama",
57608
+ plugin_config: existingOllamaProvider.plugin_config,
57609
+ provider: "ollama"
57610
+ };
57611
+ await rpcClient.request({
57612
+ method: "sim_addProvider",
57613
+ params: [newModelConfig]
57614
+ });
57615
+ console.log(`Model "${modelName}" added successfully.`);
57616
+ }
57585
57617
  }
57586
57618
  async removeModel(modelName) {
57587
- await this.executeModelCommand("rm", modelName, `Model "${modelName}" removed successfully`);
57619
+ await this.executeModelCommand(
57620
+ "rm",
57621
+ modelName,
57622
+ `Model "${modelName}" removed successfully`
57623
+ );
57588
57624
  }
57589
57625
  async executeModelCommand(command, modelName, successMessage) {
57590
57626
  try {
57627
+ let success = false;
57591
57628
  const ollamaContainer = this.docker.getContainer("ollama");
57592
57629
  const exec2 = await ollamaContainer.exec({
57593
57630
  Cmd: ["ollama", command, modelName],
@@ -57596,10 +57633,20 @@ var OllamaAction = class {
57596
57633
  });
57597
57634
  const stream = await exec2.start({ Detach: false, Tty: false });
57598
57635
  stream.on("data", (chunk) => {
57599
- console.log(chunk.toString());
57636
+ const chunkStr = chunk.toString();
57637
+ console.log(chunkStr);
57638
+ if (chunkStr.includes("success") || chunkStr.includes("deleted")) {
57639
+ success = true;
57640
+ }
57600
57641
  });
57601
57642
  await new Promise((resolve2, reject) => {
57602
- stream.on("end", resolve2);
57643
+ stream.on("end", () => {
57644
+ if (success) {
57645
+ resolve2();
57646
+ } else {
57647
+ reject("internal error");
57648
+ }
57649
+ });
57603
57650
  stream.on("error", reject);
57604
57651
  });
57605
57652
  console.log(successMessage);
@@ -57705,7 +57752,7 @@ async function initAction(options, simulatorService) {
57705
57752
  {
57706
57753
  type: "confirm",
57707
57754
  name: "confirmReset",
57708
- message: `This command is going to reset GenLayer docker images and containers, providers API Keys, and GenLayer database (accounts, transactions, and validators). Do you want to continue?`,
57755
+ message: `This command is going to reset GenLayer docker images and containers, providers API Keys, and GenLayer database (accounts, transactions, validators and logs). Contract code (gpy files) will be kept. Do you want to continue?`,
57709
57756
  default: true
57710
57757
  }
57711
57758
  ]);
@@ -57793,7 +57840,11 @@ async function initAction(options, simulatorService) {
57793
57840
  const ollamaAction = new OllamaAction();
57794
57841
  const configManager = new ConfigFileManager();
57795
57842
  const config = configManager.getConfig();
57796
- let ollamaModel = config.defaultOllamaModel || "llama3";
57843
+ let ollamaModel = config.defaultOllamaModel;
57844
+ if (!config.defaultOllamaModel) {
57845
+ configManager.writeConfig("defaultOllamaModel", "llama3");
57846
+ ollamaModel = "llama3";
57847
+ }
57797
57848
  console.log(`Pulling ${ollamaModel} from Ollama...`);
57798
57849
  await ollamaAction.updateModel(ollamaModel);
57799
57850
  }
@@ -87044,7 +87095,9 @@ function initializeValidatorCommands(program2) {
87044
87095
  function initializeUpdateCommands(program2) {
87045
87096
  const updateCommand = program2.command("update").description("Update resources like models or configurations");
87046
87097
  updateCommand.command("ollama").description("Manage Ollama models (update or remove)").option("--model [model-name]", "Specify the model to update or remove").option("--remove", "Remove the specified model instead of updating").action(async (options) => {
87047
- const modelName = options.model || "default-model";
87098
+ const configManager = new ConfigFileManager();
87099
+ const config = configManager.getConfig();
87100
+ const modelName = options.model || config.defaultOllamaModel;
87048
87101
  const ollamaAction = new OllamaAction();
87049
87102
  if (options.remove) {
87050
87103
  await ollamaAction.removeModel(modelName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "genlayer",
3
- "version": "0.10.2",
3
+ "version": "0.11.1",
4
4
  "description": "GenLayer Command Line Tool",
5
5
  "main": "src/index.ts",
6
6
  "bin": {
@@ -77,7 +77,7 @@ export async function initAction(options: InitActionOptions, simulatorService: I
77
77
  {
78
78
  type: "confirm",
79
79
  name: "confirmReset",
80
- message: `This command is going to reset GenLayer docker images and containers, providers API Keys, and GenLayer database (accounts, transactions, and validators). Do you want to continue?`,
80
+ message: `This command is going to reset GenLayer docker images and containers, providers API Keys, and GenLayer database (accounts, transactions, validators and logs). Contract code (gpy files) will be kept. Do you want to continue?`,
81
81
  default: true,
82
82
  },
83
83
  ]);
@@ -184,8 +184,12 @@ export async function initAction(options: InitActionOptions, simulatorService: I
184
184
  const ollamaAction = new OllamaAction();
185
185
  const configManager = new ConfigFileManager();
186
186
  const config = configManager.getConfig()
187
+ let ollamaModel = config.defaultOllamaModel;
187
188
 
188
- let ollamaModel = config.defaultOllamaModel || 'llama3';
189
+ if(!config.defaultOllamaModel){
190
+ configManager.writeConfig('defaultOllamaModel', 'llama3');
191
+ ollamaModel = 'llama3'
192
+ }
189
193
 
190
194
  console.log(`Pulling ${ollamaModel} from Ollama...`);
191
195
 
@@ -1,5 +1,6 @@
1
1
  import { Command } from "commander";
2
2
  import { OllamaAction } from "./ollama";
3
+ import { ConfigFileManager } from "../../lib/config/ConfigFileManager";
3
4
 
4
5
  export function initializeUpdateCommands(program: Command) {
5
6
  const updateCommand = program
@@ -12,7 +13,10 @@ export function initializeUpdateCommands(program: Command) {
12
13
  .option("--model [model-name]", "Specify the model to update or remove")
13
14
  .option("--remove", "Remove the specified model instead of updating")
14
15
  .action(async (options) => {
15
- const modelName = options.model || "default-model";
16
+ const configManager = new ConfigFileManager();
17
+ const config = configManager.getConfig()
18
+
19
+ const modelName = options.model || config.defaultOllamaModel;
16
20
  const ollamaAction = new OllamaAction();
17
21
 
18
22
  if (options.remove) {
@@ -1,4 +1,5 @@
1
- import Docker from "dockerode"
1
+ import Docker from "dockerode";
2
+ import { rpcClient } from "../../lib/clients/jsonRpcClient";
2
3
 
3
4
  export class OllamaAction {
4
5
  private docker: Docker;
@@ -8,34 +9,94 @@ export class OllamaAction {
8
9
  }
9
10
 
10
11
  async updateModel(modelName: string) {
11
- await this.executeModelCommand("pull", modelName, `Model "${modelName}" updated successfully`);
12
+ const providersAndModels = await rpcClient.request({
13
+ method: "sim_getProvidersAndModels",
14
+ params: [],
15
+ });
16
+
17
+ const existingOllamaProvider = providersAndModels.result.find(
18
+ (entry: any) => entry.plugin === "ollama"
19
+ );
20
+
21
+ if (!existingOllamaProvider) {
22
+ throw new Error("No existing 'ollama' provider found. Unable to add/update a model.");
23
+ }
24
+
25
+ await this.executeModelCommand(
26
+ "pull",
27
+ modelName,
28
+ `Model "${modelName}" updated successfully`
29
+ );
30
+
31
+ const existingModel = providersAndModels.result.some(
32
+ (entry: any) =>
33
+ entry.plugin === "ollama" && entry.model === modelName
34
+ );
35
+
36
+ if (!existingModel) {
37
+ console.log(`Model "${modelName}" not found in Provider Presets. Adding...`);
38
+
39
+ const newModelConfig = {
40
+ config: existingOllamaProvider.config,
41
+ model: modelName,
42
+ plugin: "ollama",
43
+ plugin_config: existingOllamaProvider.plugin_config,
44
+ provider: "ollama",
45
+ };
46
+
47
+ await rpcClient.request({
48
+ method: "sim_addProvider",
49
+ params: [newModelConfig],
50
+ });
51
+
52
+ console.log(`Model "${modelName}" added successfully.`);
53
+ }
12
54
  }
13
55
 
14
56
  async removeModel(modelName: string) {
15
- await this.executeModelCommand("rm", modelName, `Model "${modelName}" removed successfully`);
57
+ await this.executeModelCommand(
58
+ "rm",
59
+ modelName,
60
+ `Model "${modelName}" removed successfully`
61
+ );
16
62
  }
17
63
 
18
- private async executeModelCommand(command: string, modelName: string, successMessage: string) {
64
+ private async executeModelCommand(
65
+ command: string,
66
+ modelName: string,
67
+ successMessage: string
68
+ ) {
19
69
  try {
70
+ let success = false;
20
71
  const ollamaContainer = this.docker.getContainer("ollama");
21
72
  const exec = await ollamaContainer.exec({
22
73
  Cmd: ["ollama", command, modelName],
23
74
  AttachStdout: true,
24
75
  AttachStderr: true,
25
76
  });
26
- const stream = await exec.start({ Detach: false, Tty: false });
77
+ const stream = await exec.start({Detach: false, Tty: false});
27
78
 
28
79
  stream.on("data", (chunk: any) => {
29
- console.log(chunk.toString());
80
+ const chunkStr = chunk.toString();
81
+ console.log(chunkStr);
82
+ if (chunkStr.includes("success") || chunkStr.includes("deleted")) {
83
+ success = true;
84
+ }
30
85
  });
31
86
 
32
87
  await new Promise<void>((resolve, reject) => {
33
- stream.on("end", resolve);
88
+ stream.on("end", () => {
89
+ if (success) {
90
+ resolve();
91
+ } else {
92
+ reject('internal error');
93
+ }
94
+ });
34
95
  stream.on("error", reject);
35
96
  });
36
97
 
37
98
  console.log(successMessage);
38
- } catch (error) {
99
+ }catch (error) {
39
100
  console.error(`Error executing command "${command}" on model "${modelName}":`, error);
40
101
  }
41
102
  }
@@ -9,11 +9,13 @@ import fs from "fs";
9
9
  import * as dotenv from "dotenv";
10
10
  import {localnetCompatibleVersion} from "../../src/lib/config/simulator";
11
11
  import { OllamaAction } from "../../src/commands/update/ollama";
12
+ import { ConfigFileManager } from "../../src/lib/config/ConfigFileManager";
12
13
 
13
14
 
14
15
  vi.mock("fs");
15
16
  vi.mock("dotenv");
16
17
  vi.mock("../../src/commands/update/ollama")
18
+ vi.mock("../../src/lib/config/ConfigFileManager");
17
19
 
18
20
 
19
21
  const tempDir = mkdtempSync(join(tmpdir(), "test-initAction-"));
@@ -278,7 +280,7 @@ describe("init action", () => {
278
280
  simServDeleteAllValidators.mockResolvedValue(true);
279
281
  simServResetDockerContainers.mockResolvedValue(true);
280
282
  simServResetDockerImages.mockResolvedValue(true);
281
- vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({}));
283
+ vi.mocked(ConfigFileManager.prototype.getConfig).mockReturnValue({});
282
284
 
283
285
  await initAction(defaultActionOptions, simulatorService);
284
286
 
@@ -310,7 +312,7 @@ describe("init action", () => {
310
312
  simServDeleteAllValidators.mockResolvedValue(true);
311
313
  simServResetDockerContainers.mockResolvedValue(true);
312
314
  simServResetDockerImages.mockResolvedValue(true);
313
- vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({defaultOllamaModel: ollamaModel}));
315
+ vi.mocked(ConfigFileManager.prototype.getConfig).mockReturnValue({defaultOllamaModel: ollamaModel});
314
316
 
315
317
  await initAction(defaultActionOptions, simulatorService);
316
318
 
@@ -318,6 +320,39 @@ describe("init action", () => {
318
320
  expect(OllamaAction.prototype.updateModel).toHaveBeenCalled();
319
321
  });
320
322
 
323
+ test("should set defaultOllamaModel to llama 3 if no defaultOllamaModel is provided", async () => {
324
+
325
+ inquirerPrompt.mockResolvedValue({
326
+ confirmReset: true,
327
+ confirmDownload: true,
328
+ selectedLlmProviders: ["openai", "heuristai", "ollama"],
329
+ openai: "API_KEY1",
330
+ heuristai: "API_KEY2",
331
+ ollama: "API_KEY3",
332
+ });
333
+ simServgetAiProvidersOptions.mockReturnValue([
334
+ { name: "OpenAI", value: "openai" },
335
+ { name: "Heurist", value: "heuristai" },
336
+ { name: "Ollama", value: "ollama" },
337
+ ]);
338
+
339
+ vi.mocked(ConfigFileManager.prototype.getConfig).mockResolvedValueOnce({})
340
+ vi.mocked(OllamaAction.prototype.updateModel).mockResolvedValueOnce(undefined);
341
+
342
+ simServRunSimulator.mockResolvedValue(true);
343
+ simServWaitForSimulator.mockResolvedValue({ initialized: true });
344
+ simServDeleteAllValidators.mockResolvedValue(true);
345
+ simServResetDockerContainers.mockResolvedValue(true);
346
+ simServResetDockerImages.mockResolvedValue(true);
347
+ vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify({}));
348
+
349
+ await initAction(defaultActionOptions, simulatorService);
350
+
351
+ expect(ConfigFileManager.prototype.writeConfig).toHaveBeenCalledWith('defaultOllamaModel', 'llama3')
352
+ expect(log).toHaveBeenCalledWith(`Pulling llama3 from Ollama...`);
353
+ expect(OllamaAction.prototype.updateModel).toHaveBeenCalled();
354
+ });
355
+
321
356
  test("logs error if checkVersionRequirements throws", async () => {
322
357
  simServCheckInstallRequirements.mockResolvedValue({ git: true, docker: true });
323
358
  const errorMsg = new Error("checkVersionRequirements error");
@@ -1,8 +1,11 @@
1
- import {describe, test, vi, beforeEach, afterEach, expect, Mock} from "vitest";
1
+ import { describe, test, vi, beforeEach, afterEach, expect, Mock } from "vitest";
2
2
  import { OllamaAction } from "../../src/commands/update/ollama";
3
+ import { rpcClient } from "../../src/lib/clients/jsonRpcClient";
4
+
3
5
  import Docker from "dockerode";
4
6
 
5
7
  vi.mock("dockerode");
8
+ vi.mock("../../src/lib/clients/jsonRpcClient");
6
9
 
7
10
  describe("OllamaAction", () => {
8
11
  let ollamaAction: OllamaAction;
@@ -41,9 +44,22 @@ describe("OllamaAction", () => {
41
44
  });
42
45
 
43
46
  test("should update the model using 'pull'", async () => {
44
- mockStream.on.mockImplementation((event: any, callback:any) => {
45
- if (event === "data") callback(Buffer.from("Mocked output"));
46
- if (event === "end") callback();
47
+ const mockProvider = {
48
+ plugin: "ollama",
49
+ config: { key: "value" },
50
+ plugin_config: { pluginKey: "pluginValue" },
51
+ };
52
+ vi.mocked(rpcClient.request).mockResolvedValueOnce({
53
+ result: [mockProvider],
54
+ });
55
+
56
+ mockStream.on.mockImplementation((event: any, callback: any) => {
57
+ if (event === "data") {
58
+ callback(Buffer.from("Mocked output success"));
59
+ }
60
+ if (event === "end") {
61
+ callback();
62
+ }
47
63
  });
48
64
 
49
65
  console.log = vi.fn();
@@ -59,14 +75,18 @@ describe("OllamaAction", () => {
59
75
  expect(mockStart).toHaveBeenCalledWith({ Detach: false, Tty: false });
60
76
  expect(mockStream.on).toHaveBeenCalledWith("data", expect.any(Function));
61
77
  expect(mockStream.on).toHaveBeenCalledWith("end", expect.any(Function));
62
- expect(console.log).toHaveBeenCalledWith("Mocked output");
78
+ expect(console.log).toHaveBeenCalledWith("Mocked output success");
63
79
  expect(console.log).toHaveBeenCalledWith('Model "mocked_model" updated successfully');
64
80
  });
65
81
 
66
82
  test("should remove the model using 'rm'", async () => {
67
- mockStream.on.mockImplementation((event:any, callback:any) => {
68
- if (event === "data") callback(Buffer.from("Mocked output"));
69
- if (event === "end") callback();
83
+ mockStream.on.mockImplementation((event: any, callback: any) => {
84
+ if (event === "data") {
85
+ callback(Buffer.from("Mocked output success"));
86
+ }
87
+ if (event === "end") {
88
+ callback();
89
+ }
70
90
  });
71
91
 
72
92
  console.log = vi.fn();
@@ -82,11 +102,20 @@ describe("OllamaAction", () => {
82
102
  expect(mockStart).toHaveBeenCalledWith({ Detach: false, Tty: false });
83
103
  expect(mockStream.on).toHaveBeenCalledWith("data", expect.any(Function));
84
104
  expect(mockStream.on).toHaveBeenCalledWith("end", expect.any(Function));
85
- expect(console.log).toHaveBeenCalledWith("Mocked output");
105
+ expect(console.log).toHaveBeenCalledWith("Mocked output success");
86
106
  expect(console.log).toHaveBeenCalledWith('Model "mocked_model" removed successfully');
87
107
  });
88
108
 
89
109
  test("should log an error if an exception occurs during 'pull'", async () => {
110
+ const mockProvider = {
111
+ plugin: "ollama",
112
+ config: { key: "value" },
113
+ plugin_config: { pluginKey: "pluginValue" },
114
+ };
115
+ vi.mocked(rpcClient.request).mockResolvedValueOnce({
116
+ result: [mockProvider],
117
+ });
118
+
90
119
  const error = new Error("Mocked error");
91
120
  mockGetContainer.mockReturnValueOnce(
92
121
  {
@@ -126,4 +155,54 @@ describe("OllamaAction", () => {
126
155
  error
127
156
  );
128
157
  });
158
+
159
+ test("should throw an error if no 'ollama' provider exists during updateModel", async () => {
160
+ vi.mocked(rpcClient.request).mockResolvedValueOnce({
161
+ result: [],
162
+ });
163
+
164
+ const modelName = "mocked_model";
165
+
166
+ await expect(ollamaAction.updateModel(modelName)).rejects.toThrowError(
167
+ "No existing 'ollama' provider found. Unable to add/update a model."
168
+ );
169
+
170
+ expect(rpcClient.request).toHaveBeenCalledWith({
171
+ method: "sim_getProvidersAndModels",
172
+ params: [],
173
+ });
174
+ });
175
+
176
+ test("should reject with an error if success is not set to true", async () => {
177
+ console.error = vi.fn();
178
+
179
+ const mockProvider = {
180
+ plugin: "ollama",
181
+ config: { key: "value" },
182
+ plugin_config: { pluginKey: "pluginValue" },
183
+ };
184
+
185
+ vi.mocked(rpcClient.request).mockResolvedValueOnce({
186
+ result: [mockProvider],
187
+ });
188
+
189
+ mockStream.on.mockImplementation((event: any, callback: any) => {
190
+ if (event === "data") {
191
+ callback(Buffer.from("Mocked output failure"));
192
+ }
193
+ if (event === "end") {
194
+ callback();
195
+ }
196
+ });
197
+
198
+ console.log = vi.fn();
199
+ console.error = vi.fn();
200
+
201
+ await ollamaAction.updateModel("mocked_model");
202
+
203
+ expect(console.error).toHaveBeenCalledWith(
204
+ 'Error executing command "pull" on model "mocked_model":', 'internal error'
205
+ );
206
+ });
207
+
129
208
  });
@@ -2,8 +2,10 @@ import { Command } from "commander";
2
2
  import { vi, describe, beforeEach, afterEach, test, expect } from "vitest";
3
3
  import { initializeUpdateCommands } from "../../src/commands/update";
4
4
  import { OllamaAction } from "../../src/commands/update/ollama";
5
+ import { ConfigFileManager } from "../../src/lib/config/ConfigFileManager";
5
6
 
6
7
  vi.mock("../../src/commands/update/ollama");
8
+ vi.mock("../../src/lib/config/ConfigFileManager");
7
9
 
8
10
  describe("ollama command", () => {
9
11
  let program: Command;
@@ -11,6 +13,9 @@ describe("ollama command", () => {
11
13
  beforeEach(() => {
12
14
  program = new Command();
13
15
  initializeUpdateCommands(program);
16
+
17
+ const mockConfig = { defaultOllamaModel: "default-model" };
18
+ vi.mocked(ConfigFileManager.prototype.getConfig).mockReturnValue(mockConfig);
14
19
  });
15
20
 
16
21
  afterEach(() => {