symmetry-cli 1.0.3 → 1.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- import { SymmetryClient } from "../src/client";
1
+ import { SymmetryProvider } from "../src/provider";
2
2
  import yaml from "js-yaml";
3
3
 
4
4
  jest.mock("hyperswarm", () => {
@@ -33,7 +33,7 @@ jest.mock("js-yaml", () => ({
33
33
 
34
34
 
35
35
  describe("Symmetry", () => {
36
- let writer: SymmetryClient;
36
+ let writer: SymmetryProvider;
37
37
  const mockConfig = {
38
38
  path: "/test/path",
39
39
  temperature: 1,
@@ -47,12 +47,13 @@ describe("Symmetry", () => {
47
47
  name: "test",
48
48
  public: true,
49
49
  serverKey: "test-server-key",
50
+ systemMessage: "test-system-message",
50
51
  };
51
52
 
52
53
  beforeEach(() => {
53
54
  jest.clearAllMocks();
54
55
  (yaml.load as jest.Mock).mockReturnValue(mockConfig);
55
- writer = new SymmetryClient("mock-config.yaml");
56
+ writer = new SymmetryProvider("mock-config.yaml");
56
57
  });
57
58
 
58
59
  test("init method sets up the writer correctly", async () => {
package/dist/provider.js CHANGED
@@ -149,7 +149,14 @@ class SymmetryProvider {
149
149
  }
150
150
  async handleInferenceRequest(data, peer) {
151
151
  const emitterKey = data.data.key;
152
+ const messages = data === null || data === void 0 ? void 0 : data.data.messages;
152
153
  const req = this.buildStreamRequest(data === null || data === void 0 ? void 0 : data.data.messages);
154
+ if (messages.length === 2) {
155
+ messages.unshift({
156
+ role: "system",
157
+ content: this._config.get("systemMessage"),
158
+ });
159
+ }
153
160
  if (!req)
154
161
  return;
155
162
  const { requestOptions, requestBody } = req;
@@ -192,10 +199,7 @@ class SymmetryProvider {
192
199
  });
193
200
  await Promise.resolve(peerPipeline);
194
201
  peer.write((0, utils_1.createMessage)(constants_1.serverMessageKeys.inferenceEnded, data === null || data === void 0 ? void 0 : data.data.key));
195
- if (this._config.get("dataCollectionEnabled") &&
196
- data.data.key === constants_1.serverMessageKeys.inference) {
197
- this.saveCompletion(completion, peer, data.data.messages);
198
- }
202
+ this.saveCompletion(completion, peer, data.data.messages);
199
203
  }
200
204
  catch (error) {
201
205
  let errorMessage = "An error occurred during inference";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "symmetry-cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.5",
4
4
  "description": "",
5
5
  "main": "dist/symmetry.js",
6
6
  "bin": "dist/symmetry.js",
package/readme.md CHANGED
@@ -1,63 +1,66 @@
1
- # Symmetry
1
+ # Symmetry
2
2
 
3
- In the vast lands of the Internet, where bits and bytes flow like the rivers of old, there arose a tool of great power and purpose. Symmetry the enchanted mirror. With Symmetry, users of the digital realm could offer their computational strength to others, allowing seekers of knowledge to tap into the wisdom of distant machines.
3
+ Use this repository to become an inference provider on the Symmetry network.
4
+
5
+ Symmetry is a decentralized peer-to-peer network tool that allows users to share computational resources for AI inference. It enables users to connect directly and securely with each other, offering or seeking computational power for various AI tasks.
4
6
 
5
7
  ## Features
6
8
 
7
- - **Network**: A decentralized network, of interconnected peers.
8
- - **Configuration**: A scroll of YAML, easily inscribed to bend Symmetry to one's will.
9
- - **Privacy**: A choice between openness and secrecy.
10
- - **Data collection**: An option to gather tales of interactions, should the provider wish it so.
9
+ - Decentralized peer-to-peer network
10
+ - YAML-based configuration
11
+ - Privacy options
12
+ - Optional data collection for providers
13
+ - Compatible with various AI inference providers
11
14
 
12
15
  ## Installation
13
16
 
14
- To call forth Symmetry into your realm, speak these words of power:
17
+ To install Symmetry, use the following commands:
15
18
 
16
- Linux and MacOs
17
- ```
19
+ For Linux and macOS:
20
+ ```bash
18
21
  curl -fsSL https://raw.githubusercontent.com/twinnydotdev/symmetry/master/install.sh | sh
19
22
  ```
20
23
 
21
- Windows
22
- ```
24
+ For Windows:
25
+ ```powershell
23
26
  iwr -useb https://raw.githubusercontent.com/twinnydotdev/symmetry/master/install.ps1 | iex
24
27
  ```
25
28
 
26
29
  ## Usage
27
30
 
28
- To awaken Symmetry, utter this command:
31
+ To start Symmetry, run:
29
32
 
30
- ```
33
+ ```bash
31
34
  symmetry-cli
32
35
  ```
33
36
 
34
- Symmetry will seek its tome of knowledge in the halls of `~/.config/symmetry/provider.yaml`. Should you wish to direct it to another scroll, speak thus:
37
+ By default, Symmetry looks for its configuration file at `~/.config/symmetry/provider.yaml`. To use a different configuration file, use:
35
38
 
36
- ```
37
- symmetry -c /path/to/your/sacred/provider.yaml
39
+ ```bash
40
+ symmetry-cli -c /path/to/your/provider.yaml
38
41
  ```
39
42
 
40
43
  ## Configuration
41
44
 
42
- Inscribe your `provider.yaml` with these mystical runes:
45
+ Here's an example `provider.yaml` configuration:
43
46
 
44
47
  ```yaml
45
- apiHostname: localhost # The dwelling of your local oracle
46
- apiKey: # The secret word to commune with your oracle
47
- apiPath: /v1/chat/completions # The path to wisdom
48
- apiPort: 11434 # The gate through which knowledge flows
49
- apiProtocol: http # The method of communion
50
- apiProvider: ollama # The lineage of your oracle
51
- dataCollectionEnabled: true # Whether to gather lore
52
- maxConnections: 10 # The limit of simultaneous seekers
53
- modelName: llama3:8b # The true name of your oracle
54
- name: # Your title in this realm
55
- path: /home/richard/.config/symmetry/default # The dwelling for data
56
- public: true # Whether your services are open to all
57
- serverKey: 4b4a9cc325d134dee6679e9407420023531fd7e96c563f6c5d00fd5549b77435 # The key of the central tower
48
+ apiHostname: localhost # The hostname of the API server.
49
+ apiKey: # The API key for authentication.
50
+ apiPath: /v1/chat/completions # The endpoint path for chat completions.
51
+ apiPort: 11434 # The port number on which the API server is listening.
52
+ apiProtocol: http # The protocol used to communicate with the API server.
53
+ apiProvider: ollama # The name of the API provider.
54
+ dataCollectionEnabled: false # Whether to enable data collection.
55
+ maxConnections: 10 # The maximum number of connections.
56
+ modelName: llama3.1:latest # The name and version of the AI model to use.
57
+ name: twinnydotdev # Your chosen name as a provider on the Symmetry network.
58
+ path: /home/twinnydotdev/.config/symmetry/data # The local path where Symmetry will store its configuration and data files.
59
+ public: true # Whether this provider is publicly accessible on the Symmetry network.
60
+ serverKey: 4b4a9cc325d134dee6679e9407420023531fd7e96c563f6c5d00fd5549b77435 # The unique key for connecting to the Symmetry server.
58
61
  ```
59
62
 
60
- Adjust these runes to align with your own preferences.
63
+ Adjust these settings according to your preferences and setup.
61
64
 
62
65
  ## Architecture
63
66
 
@@ -88,80 +91,46 @@ graph TB
88
91
 
89
92
  C1 <--> |"4. Inference<br/>Request/Response"| P2
90
93
  C2 <--> |"4. Inference<br/>Request/Response"| P3
91
-
92
- style S fill:#ff9900,stroke:#333,stroke-width:4px
93
- style P1 fill:#00ccff,stroke:#333,stroke-width:2px
94
- style P2 fill:#00ccff,stroke:#333,stroke-width:2px
95
- style P3 fill:#00ccff,stroke:#333,stroke-width:2px
96
- style C1 fill:#333,stroke:#fff,stroke-width:2px
97
- style C2 fill:#333,stroke:#fff,stroke-width:2px
98
94
  ```
99
95
 
100
- ### Server, Providers and Clients:
101
- - **Central Server**: Symmetry Server, a beacon of order in the chaotic digital winds.
102
- - **Providers**: Inference Providers, keepers of knowledge and computational might.
103
- - **Client**: Clients, adventurers in search of answers from the oracles of data.
104
-
105
- ### Connection:
106
-
107
- 1. The Providers approach the Central Tower, proving their worth and declaring their specialties.
108
- 2. Seekers call out to the Tower, their questions echoing in the digital void.
109
- 3. The Tower, in its wisdom, guides each Seeker to a suitable Provider.
110
- 4. Seeker and Provider join in a dance of query and response, their connection direct and true.
111
-
112
- ### Communication:
113
-
114
- - All messages between Seekers and Providers are cloaked in unbreakable encryption, safe from prying eyes.
115
- - The Providers may choose to remember the tales told to them, a choice they must declare openly.
116
- - Seekers are granted the wisdom to choose their Providers based on these declarations of memory.
96
+ ## Development
117
97
 
118
- ### Features:
98
+ To set up Symmetry for development:
119
99
 
120
- - **Adaptability**: As changeable as the seasons, ready for new knowledge and new seekers.
121
- - **Swiftness**: Direct connections ensure that wisdom flows like the rapids of a mountain stream.
122
- - **Guardianship**: Only the worthy may enter this circle of trust.
123
- - **Balance**: The Tower ensures no single Provider bears too heavy a burden.
124
- - **Growth**: New Providers may join the circle, expanding the realm of possibility.
125
-
126
- Thus does Symmetry weave its web of connections, bringing together the seekers and keepers of digital wisdom in a grand tapestry of knowledge and computation.
127
-
128
- ## Forging of Symmetry
129
-
130
- For those who wish to shape Symmetry with their own hands:
131
-
132
- 1. Summon the essence:
133
- ```
100
+ 1. Clone the repository:
101
+ ```bash
134
102
  git clone https://github.com/twinnydotdev/symmetry.git
135
103
  cd symmetry
136
104
  ```
137
105
 
138
- 2. Gather the necessary elements:
139
- ```
106
+ 2. Install dependencies:
107
+ ```bash
140
108
  npm install
141
109
  ```
142
110
 
143
- 3. Forge the tool:
144
- ```
111
+ 3. Build the project:
112
+ ```bash
145
113
  npm run build
146
114
  ```
147
115
 
148
- 4. Awaken:
149
- ```
150
- npm start
116
+ 4. Start the development server:
117
+ ```bash
118
+ npm run dev
151
119
  ```
152
120
 
153
- ## Call for Heroes
121
+ ## Contributing
122
+
123
+ Contributions are welcome! Please submit your pull requests to the [GitHub repository](https://github.com/twinnydotdev/symmetry/pulls).
154
124
 
155
- Brave souls willing to improve upon this grand design are most welcome. Present your [scrolls of change](https://github.com/twinnydotdev/symmetry/pulls) for consideration.
125
+ ## License
156
126
 
157
- ## Covenant
127
+ This project is licensed under the [MIT License](https://github.com/twinnydotdev/symmetry/blob/master/LICENCE).
158
128
 
159
- This work is protected under the [Oath of MIT](https://github.com/twinnydotdev/symmetry/blob/main/LICENSE), a sacred bond between creator and user.
129
+ ## Support
160
130
 
161
- ## Council of Elders
131
+ If you encounter any issues or have questions, please [open an issue](https://github.com/twinnydotdev/symmetry/issues) on GitHub.
162
132
 
163
- Should you face trials or seek guidance, bring your [queries](https://github.com/twinnydotdev/symmetry/issues) before the Council on GitHub.
133
+ ## Acknowledgments
164
134
 
165
- ## A Nod to the Ancients
135
+ We thank [Hyperswarm](https://github.com/holepunchto/hyperswarm) for providing the underlying peer-to-peer networking capabilities.
166
136
 
167
- We pay homage to [Hyperswarm](https://github.com/holepunchto/hyperswarm), the tool that makes our connections possible.
package/src/provider.ts CHANGED
@@ -13,10 +13,8 @@ import {
13
13
  safeParseStreamResponse,
14
14
  } from "./utils";
15
15
  import { logger } from "./logger";
16
- import { Peer, ProviderMessage, InferenceRequest } from "./types";
17
- import {
18
- serverMessageKeys,
19
- } from "./constants";
16
+ import { Peer, ProviderMessage, InferenceRequest, Message } from "./types";
17
+ import { serverMessageKeys } from "./constants";
20
18
 
21
19
  export class SymmetryProvider {
22
20
  private _challenge: Buffer | null = null;
@@ -65,7 +63,7 @@ export class SymmetryProvider {
65
63
  chalk.white(`🔑 Server key: ${this._config.get("serverKey")}`)
66
64
  );
67
65
  logger.info(chalk.white("🔗 Joining server, please wait."));
68
- await this.joinServer();
66
+ this.testProviderCall();
69
67
  }
70
68
 
71
69
  process.on("SIGINT", async () => {
@@ -80,6 +78,66 @@ export class SymmetryProvider {
80
78
  });
81
79
  }
82
80
 
81
+ private async testProviderCall(): Promise<void> {
82
+ logger.info(chalk.white(`👋 Saying hello to your provider...`));
83
+ const testMessages: Message[] = [
84
+ { role: "user", content: "Hello, this is a test message." },
85
+ ];
86
+ const req = this.buildStreamRequest(testMessages);
87
+
88
+ if (!req) {
89
+ logger.error(chalk.red("❌ Failed to build test request"));
90
+ throw new Error("Failed to build test request");
91
+ }
92
+
93
+ const { requestOptions, requestBody } = req;
94
+ const { protocol, hostname, port, path, method, headers } = requestOptions;
95
+ const url = `${protocol}://${hostname}:${port}${path}`;
96
+
97
+ logger.info(chalk.white(`🚀 Sending test request to ${url}`));
98
+
99
+ try {
100
+ const response = await fetch(url, {
101
+ method,
102
+ headers,
103
+ body: JSON.stringify(requestBody),
104
+ });
105
+
106
+ if (!response.ok) {
107
+ logger.error(
108
+ chalk.red(`❌ Server responded with status code: ${response.status}`)
109
+ );
110
+ throw new Error(
111
+ `Server responded with status code: ${response.status}`
112
+ );
113
+ }
114
+
115
+ if (!response.body) {
116
+ logger.error(
117
+ chalk.red("❌ Failed to get a ReadableStream from the response")
118
+ );
119
+ throw new Error("Failed to get a ReadableStream from the response");
120
+ }
121
+
122
+ logger.info(chalk.white(`📡 Got response, checking stream...`));
123
+
124
+ const reader = response.body.getReader();
125
+ const { done } = await reader.read();
126
+ if (done) {
127
+ logger.error(chalk.red("❌ Stream ended without data"));
128
+ throw new Error("Stream ended without data");
129
+ }
130
+
131
+ logger.info(chalk.green(`✅ Test inference call successful!`));
132
+ } catch (error) {
133
+ logger.error(chalk.red(`❌ Error during test inference call: ${error}`));
134
+ throw error;
135
+ }
136
+
137
+ logger.info(chalk.white(`🔗 Proceeding to join server...`));
138
+ await this.joinServer();
139
+ }
140
+
83
141
  async joinServer(): Promise<void> {
84
142
  const serverSwarm = new Hyperswarm();
85
143
  const serverKey = Buffer.from(this._config.get("serverKey"));
@@ -192,13 +250,24 @@ export class SymmetryProvider {
192
250
  });
193
251
  }
194
252
 
253
+ private getMessagesWithSystem(messages: Message[]): Message[] {
254
+ const systemMessage = this._config.get("systemMessage");
255
+ if (messages.length === 2 && systemMessage) {
256
+ messages.unshift({
257
+ role: "system",
258
+ content: systemMessage,
259
+ });
260
+ }
261
+ return messages;
262
+ }
263
+
195
264
  private async handleInferenceRequest(
196
265
  data: ProviderMessage<InferenceRequest>,
197
266
  peer: Peer
198
267
  ): Promise<void> {
199
268
  const emitterKey = data.data.key;
200
-
201
- const req = this.buildStreamRequest(data?.data.messages);
269
+ const messages = this.getMessagesWithSystem(data?.data.messages);
270
+ const req = this.buildStreamRequest(messages);
202
271
 
203
272
  if (!req) return;
204
273
 
@@ -277,7 +346,7 @@ export class SymmetryProvider {
277
346
  private async saveCompletion(
278
347
  completion: string,
279
348
  peer: Peer,
280
- messages: { role: string; content: string }[]
349
+ messages: Message[]
281
350
  ) {
282
351
  fs.writeFile(
283
352
  `${this._config.get("path")}/${peer.publicKey.toString("hex")}-${
@@ -296,7 +365,7 @@ export class SymmetryProvider {
296
365
  );
297
366
  }
298
367
 
299
- private buildStreamRequest(messages: { role: string; content: string }[]) {
368
+ private buildStreamRequest(messages: Message[]) {
300
369
  const requestOptions = {
301
370
  hostname: this._config.get("apiHostname"),
302
371
  port: Number(this._config.get("apiPort")),
package/src/types.ts CHANGED
@@ -18,6 +18,7 @@ export interface ProviderConfig {
18
18
  port: number;
19
19
  public: boolean;
20
20
  serverKey: string;
21
+ systemMessage: string;
21
22
  }
22
23
 
23
24
  export interface ProviderMessage<T = unknown> {
@@ -27,7 +28,7 @@ export interface ProviderMessage<T = unknown> {
27
28
 
28
29
  export interface InferenceRequest {
29
30
  key: string;
30
- messages: { role: string; content: string }[];
31
+ messages: Message[];
31
32
  }
32
33
 
33
34
  interface ReadableState {