symmetry-cli 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- package/.eslintrc.js +15 -0
- package/LICENCE +20 -0
- package/__test__/cli.test.ts +61 -0
- package/dist/client.js +230 -0
- package/dist/config-manager.js +58 -0
- package/dist/config.js +44 -0
- package/dist/constants.js +30 -0
- package/dist/database.js +9 -0
- package/dist/logger.js +45 -0
- package/dist/peer-repository.js +114 -0
- package/dist/provider.js +239 -0
- package/dist/server.js +143 -0
- package/dist/session-manager.js +68 -0
- package/dist/session-repository.js +127 -0
- package/dist/symmetry.js +20 -0
- package/dist/types.js +2 -0
- package/dist/utils.js +53 -0
- package/dist/websocket-server.js +52 -0
- package/global.d.ts +51 -0
- package/install.ps1 +88 -0
- package/jest.config.js +7 -0
- package/package.json +43 -0
- package/readme.md +167 -0
- package/src/config.ts +51 -0
- package/src/constants.ts +29 -0
- package/src/logger.ts +47 -0
- package/src/provider.ts +322 -0
- package/src/symmetry.ts +23 -0
- package/src/types.ts +242 -0
- package/src/utils.ts +52 -0
- package/tsconfig.json +28 -0
@@ -0,0 +1,52 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.WsServer = void 0;
|
4
|
+
const http_1 = require("http");
|
5
|
+
const ws_1 = require("ws");
|
6
|
+
class WsServer {
|
7
|
+
constructor(port, peerRepository, swarm) {
|
8
|
+
this.wssListeners = () => {
|
9
|
+
var _a;
|
10
|
+
(_a = this._wss) === null || _a === void 0 ? void 0 : _a.on("connection", (ws) => {
|
11
|
+
this.sendStats(ws);
|
12
|
+
const interval = setInterval(() => this.sendStats(ws), 5000);
|
13
|
+
ws.on("close", () => {
|
14
|
+
clearInterval(interval);
|
15
|
+
});
|
16
|
+
});
|
17
|
+
};
|
18
|
+
this._peerRepository = peerRepository;
|
19
|
+
this._swarm = swarm;
|
20
|
+
this.start(port);
|
21
|
+
}
|
22
|
+
start(port) {
|
23
|
+
const server = (0, http_1.createServer)();
|
24
|
+
this._wss = new ws_1.WebSocketServer({ server });
|
25
|
+
server.listen(port);
|
26
|
+
this.wssListeners();
|
27
|
+
}
|
28
|
+
async sendStats(ws) {
|
29
|
+
const stats = await this.getStats(this._swarm);
|
30
|
+
ws.send(JSON.stringify(stats));
|
31
|
+
}
|
32
|
+
async broadcastStats() {
|
33
|
+
var _a;
|
34
|
+
const stats = await this.getStats(this._swarm);
|
35
|
+
(_a = this._wss) === null || _a === void 0 ? void 0 : _a.clients.forEach((client) => {
|
36
|
+
if (client.readyState === ws_1.WebSocket.OPEN) {
|
37
|
+
client.send(JSON.stringify(stats));
|
38
|
+
}
|
39
|
+
});
|
40
|
+
}
|
41
|
+
async getStats(swarm) {
|
42
|
+
const activePeers = await this._peerRepository.getActivePeerCount();
|
43
|
+
const activeModels = await this._peerRepository.getActiveModelCount();
|
44
|
+
const swarmConnections = swarm.connections.size;
|
45
|
+
return {
|
46
|
+
activePeers,
|
47
|
+
activeModels,
|
48
|
+
swarmConnections,
|
49
|
+
};
|
50
|
+
}
|
51
|
+
}
|
52
|
+
exports.WsServer = WsServer;
|
package/global.d.ts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
+
declare module "b4a"
|
3
|
+
|
4
|
+
declare module "hyperswarm" {
|
5
|
+
import { EventEmitter } from "events";
|
6
|
+
|
7
|
+
export interface Swarm {
|
8
|
+
flushed(): Promise<void>;
|
9
|
+
}
|
10
|
+
|
11
|
+
export interface JoinOptions {
|
12
|
+
client?: boolean;
|
13
|
+
server?: boolean;
|
14
|
+
}
|
15
|
+
|
16
|
+
export interface SwarmOptions {
|
17
|
+
keyPair?: any;
|
18
|
+
seed?: Buffer;
|
19
|
+
maxPeers?: number;
|
20
|
+
firewall?: (remotePublicKey: string) => boolean;
|
21
|
+
dht?: any;
|
22
|
+
maxConnections: number;
|
23
|
+
}
|
24
|
+
|
25
|
+
export default class Hyperswarm extends EventEmitter {
|
26
|
+
constructor(opts?: SwarmOptions);
|
27
|
+
join(topic: string | Buffer, opts?: JoinOptions): Swarm;
|
28
|
+
on: (key: string, cb: (data: any) => void) => void;
|
29
|
+
once: (key: string, cb: (data: any) => void) => void;
|
30
|
+
flush: () => void;
|
31
|
+
leave(topic: Buffer): void;
|
32
|
+
destroy(): Promise<void>;
|
33
|
+
peers: Map<string, any>;
|
34
|
+
connecting: boolean;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
|
38
|
+
declare module "hypercore-crypto" {
|
39
|
+
const hyperCoreCrypto: {
|
40
|
+
keyPair: (seed?: Buffer) => { publicKey: Buffer; secretKey: Buffer };
|
41
|
+
discoveryKey: (publicKey: Buffer) => Buffer;
|
42
|
+
randomBytes: (n?: number) => Buffer;
|
43
|
+
verify: (
|
44
|
+
challenge: Buffer,
|
45
|
+
signature: Buffer,
|
46
|
+
publicKey: Buffer
|
47
|
+
) => boolean;
|
48
|
+
};
|
49
|
+
|
50
|
+
export = hyperCoreCrypto;
|
51
|
+
}
|
package/install.ps1
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
$ErrorActionPreference = "Stop"
|
2
|
+
|
3
|
+
# Colors for output
|
4
|
+
$RED = "`e[31m"
|
5
|
+
$GREEN = "`e[32m"
|
6
|
+
$YELLOW = "`e[33m"
|
7
|
+
$NC = "`e[0m"
|
8
|
+
|
9
|
+
function Print-Color($color, $message) {
|
10
|
+
Write-Host "$color$message$NC"
|
11
|
+
}
|
12
|
+
|
13
|
+
# Check if npm is installed
|
14
|
+
if (!(Get-Command npm -ErrorAction SilentlyContinue)) {
|
15
|
+
Print-Color $RED "Error: npm is not installed. Please install Node.js and npm first."
|
16
|
+
exit 1
|
17
|
+
}
|
18
|
+
|
19
|
+
# Install symmetry-cli globally
|
20
|
+
Print-Color $YELLOW "Installing symmetry-cli globally..."
|
21
|
+
try {
|
22
|
+
npm install -g symmetry-cli
|
23
|
+
Print-Color $GREEN "symmetry-cli installed successfully!"
|
24
|
+
}
|
25
|
+
catch {
|
26
|
+
Print-Color $RED "Failed to install symmetry-cli. Please check your npm configuration and try again."
|
27
|
+
exit 1
|
28
|
+
}
|
29
|
+
|
30
|
+
# Prompt for API provider
|
31
|
+
Print-Color $YELLOW "Please select an API provider:"
|
32
|
+
$providers = @{
|
33
|
+
1 = @{name = "LiteLLM"; value = "litellm"}
|
34
|
+
2 = @{name = "LlamaCpp"; value = "llamacpp"}
|
35
|
+
3 = @{name = "LMStudio"; value = "lmstudio"}
|
36
|
+
4 = @{name = "Ollama"; value = "ollama"}
|
37
|
+
5 = @{name = "Oobabooga"; value = "oobabooga"}
|
38
|
+
6 = @{name = "OpenWebUI"; value = "openwebui"}
|
39
|
+
}
|
40
|
+
|
41
|
+
$providers.GetEnumerator() | ForEach-Object {
|
42
|
+
Write-Host "$($_.Key): $($_.Value.name)"
|
43
|
+
}
|
44
|
+
|
45
|
+
do {
|
46
|
+
$selection = Read-Host "Enter the number of your choice"
|
47
|
+
$api_provider = $providers[$selection].value
|
48
|
+
} while (-not $api_provider)
|
49
|
+
|
50
|
+
# Prompt for model name
|
51
|
+
Print-Color $YELLOW "Please enter the model name you want to use:"
|
52
|
+
$model_name = Read-Host
|
53
|
+
|
54
|
+
# Create config directory and provider.yaml file
|
55
|
+
$config_dir = "$env:USERPROFILE\.config\symmetry"
|
56
|
+
$provider_yaml = "$config_dir\provider.yaml"
|
57
|
+
|
58
|
+
New-Item -ItemType Directory -Force -Path $config_dir | Out-Null
|
59
|
+
|
60
|
+
if (!(Test-Path $provider_yaml)) {
|
61
|
+
Print-Color $YELLOW "Creating provider.yaml file..."
|
62
|
+
@"
|
63
|
+
# Symmetry Configuration
|
64
|
+
apiHostname: localhost
|
65
|
+
apiKey:
|
66
|
+
apiPath: /v1/chat/completions
|
67
|
+
apiPort: 11434
|
68
|
+
apiProtocol: http
|
69
|
+
apiProvider: $api_provider
|
70
|
+
dataCollectionEnabled: true
|
71
|
+
maxConnections: 10
|
72
|
+
modelName: $model_name
|
73
|
+
name: $env:USERNAME
|
74
|
+
path: $config_dir
|
75
|
+
public: true
|
76
|
+
serverKey: 4b4a9cc325d134dee6679e9407420023531fd7e96c563f6c5d00fd5549b77435
|
77
|
+
"@ | Set-Content $provider_yaml
|
78
|
+
Print-Color $GREEN "provider.yaml created successfully at $provider_yaml"
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
Print-Color $YELLOW "provider.yaml already exists at $provider_yaml"
|
82
|
+
}
|
83
|
+
|
84
|
+
Print-Color $GREEN "Installation complete! You can now run 'symmetry-cli' to start your node."
|
85
|
+
Print-Color $YELLOW "Please edit $provider_yaml to customize your provider settings, especially:"
|
86
|
+
Print-Color $YELLOW " - apiKey: Add your API key if required"
|
87
|
+
Print-Color $YELLOW " - name: Currently set to your system username, change if needed"
|
88
|
+
Print-Color $YELLOW " - public: Set to true by default, change to false if you don't want to be publicly accessible"
|
package/jest.config.js
ADDED
package/package.json
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
{
|
2
|
+
"name": "symmetry-cli",
|
3
|
+
"version": "1.0.0",
|
4
|
+
"description": "",
|
5
|
+
"main": "dist/symmetry.js",
|
6
|
+
"bin": "dist/symmetry.js",
|
7
|
+
"author": "rjmacarthy",
|
8
|
+
"license": "ISC",
|
9
|
+
"scripts": {
|
10
|
+
"test": "jest",
|
11
|
+
"build": "tsc",
|
12
|
+
"package": "pkg ./dist/symmetry.js",
|
13
|
+
"start": "node dist/symmetry.js",
|
14
|
+
"dev": "ts-node src/symmetry.ts",
|
15
|
+
"debug": "ts-node --inspect src/symmetry.ts",
|
16
|
+
"lint": "eslint . --ext .ts,.js --fix"
|
17
|
+
},
|
18
|
+
"dependencies": {
|
19
|
+
"chalk": "^4.1.2",
|
20
|
+
"commander": "^12.1.0",
|
21
|
+
"hypercore-crypto": "^3.4.2",
|
22
|
+
"hyperdht": "^6.15.4",
|
23
|
+
"hyperswarm": "^4.8.0",
|
24
|
+
"js-yaml": "^4.1.0",
|
25
|
+
"sqlite3": "^5.1.7",
|
26
|
+
"ws": "^8.18.0"
|
27
|
+
},
|
28
|
+
"devDependencies": {
|
29
|
+
"@types/jest": "^29.5.12",
|
30
|
+
"@types/js-yaml": "^4.0.9",
|
31
|
+
"@types/node": "^20.14.10",
|
32
|
+
"@types/ws": "^8.5.11",
|
33
|
+
"@typescript-eslint/eslint-plugin": "^7.16.1",
|
34
|
+
"@typescript-eslint/parser": "^7.16.1",
|
35
|
+
"eslint": "^8.57.0",
|
36
|
+
"globals": "^15.8.0",
|
37
|
+
"jest": "^29.7.0",
|
38
|
+
"ts-jest": "^29.2.2",
|
39
|
+
"ts-node": "^10.9.2",
|
40
|
+
"typescript": "^5.5.4"
|
41
|
+
},
|
42
|
+
"types": "types/twinnymind.d.ts"
|
43
|
+
}
|
package/readme.md
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# Symmetry
|
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.
|
4
|
+
|
5
|
+
## Features
|
6
|
+
|
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.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
To call forth Symmetry into your realm, speak these words of power:
|
15
|
+
|
16
|
+
Linux and MacOs
|
17
|
+
```
|
18
|
+
curl -fsSL https://raw.githubusercontent.com/twinnydotdev/symmetry/main/install.sh | sh
|
19
|
+
```
|
20
|
+
|
21
|
+
Windows
|
22
|
+
```
|
23
|
+
iwr -useb https://raw.githubusercontent.com/twinnydotdev/symmetry/main/install.ps1 | iex
|
24
|
+
```
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
To awaken Symmetry, utter this command:
|
29
|
+
|
30
|
+
```
|
31
|
+
symmetry-cli
|
32
|
+
```
|
33
|
+
|
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:
|
35
|
+
|
36
|
+
```
|
37
|
+
symmetry -c /path/to/your/sacred/provider.yaml
|
38
|
+
```
|
39
|
+
|
40
|
+
## Configuration
|
41
|
+
|
42
|
+
Inscribe your `provider.yaml` with these mystical runes:
|
43
|
+
|
44
|
+
```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
|
58
|
+
```
|
59
|
+
|
60
|
+
Adjust these runes to align with your own preferences.
|
61
|
+
|
62
|
+
## Architecture
|
63
|
+
|
64
|
+
```mermaid
|
65
|
+
graph TB
|
66
|
+
S[Symmetry Server]
|
67
|
+
|
68
|
+
subgraph "Inference Providers"
|
69
|
+
P1[Provider 1]
|
70
|
+
P2[Provider 2]
|
71
|
+
P3[Provider 3]
|
72
|
+
end
|
73
|
+
|
74
|
+
subgraph "Clients"
|
75
|
+
C1[Client 1<br/>Requests Model B]
|
76
|
+
C2[Client 2<br/>Requests Model C]
|
77
|
+
end
|
78
|
+
|
79
|
+
P1 <--> |"1. Connect & Auth & Register Model"| S
|
80
|
+
P2 <--> |"1. Connect & Auth & Register Model"| S
|
81
|
+
P3 <--> |"1. Connect & Auth & Register Model"| S
|
82
|
+
|
83
|
+
C1 -- "2. Connect" --> S
|
84
|
+
C2 -- "2. Connect" --> S
|
85
|
+
|
86
|
+
S -- "3. Assign Provider<br/>based on Model" --> C1
|
87
|
+
S -- "3. Assign Provider<br/>based on Model" --> C2
|
88
|
+
|
89
|
+
C1 <--> |"4. Inference<br/>Request/Response"| P2
|
90
|
+
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
|
+
```
|
99
|
+
|
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.
|
117
|
+
|
118
|
+
### Features:
|
119
|
+
|
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
|
+
```
|
134
|
+
git clone https://github.com/twinnydotdev/symmetry.git
|
135
|
+
cd symmetry
|
136
|
+
```
|
137
|
+
|
138
|
+
2. Gather the necessary elements:
|
139
|
+
```
|
140
|
+
npm install
|
141
|
+
```
|
142
|
+
|
143
|
+
3. Forge the tool:
|
144
|
+
```
|
145
|
+
npm run build
|
146
|
+
```
|
147
|
+
|
148
|
+
4. Awaken:
|
149
|
+
```
|
150
|
+
npm start
|
151
|
+
```
|
152
|
+
|
153
|
+
## Call for Heroes
|
154
|
+
|
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.
|
156
|
+
|
157
|
+
## Covenant
|
158
|
+
|
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.
|
160
|
+
|
161
|
+
## Council of Elders
|
162
|
+
|
163
|
+
Should you face trials or seek guidance, bring your [queries](https://github.com/twinnydotdev/symmetry/issues) before the Council on GitHub.
|
164
|
+
|
165
|
+
## A Nod to the Ancients
|
166
|
+
|
167
|
+
We pay homage to [Hyperswarm](https://github.com/holepunchto/hyperswarm), the tool that makes our connections possible.
|
package/src/config.ts
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
import { ProviderConfig } from "./types";
|
2
|
+
import fs from "fs";
|
3
|
+
import yaml from "js-yaml";
|
4
|
+
|
5
|
+
export class ConfigManager {
|
6
|
+
private config: ProviderConfig;
|
7
|
+
|
8
|
+
constructor(configPath: string) {
|
9
|
+
const configFile = fs.readFileSync(configPath, "utf8");
|
10
|
+
const config = yaml.load(configFile) as ProviderConfig;
|
11
|
+
this.config = config
|
12
|
+
this.validate();
|
13
|
+
}
|
14
|
+
|
15
|
+
public getAll () {
|
16
|
+
return this.config;
|
17
|
+
}
|
18
|
+
|
19
|
+
private validate(): void {
|
20
|
+
const requiredFields: (keyof ProviderConfig)[] = [
|
21
|
+
"apiHostname",
|
22
|
+
"apiPath",
|
23
|
+
"apiPort",
|
24
|
+
"apiProtocol",
|
25
|
+
"apiProvider",
|
26
|
+
"modelName",
|
27
|
+
"path",
|
28
|
+
"public",
|
29
|
+
"serverKey",
|
30
|
+
];
|
31
|
+
|
32
|
+
for (const field of requiredFields) {
|
33
|
+
if (!(field in this.config)) {
|
34
|
+
throw new Error(
|
35
|
+
`Missing required field in client configuration: ${field}`
|
36
|
+
);
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
40
|
+
if (typeof this.config.public !== "boolean") {
|
41
|
+
throw new Error(
|
42
|
+
'The "public" field in client configuration must be a boolean'
|
43
|
+
);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
get<K extends keyof ProviderConfig>(key: K): ProviderConfig[K];
|
48
|
+
get(key: string): unknown {
|
49
|
+
return this.config[key as keyof ProviderConfig];
|
50
|
+
}
|
51
|
+
}
|
package/src/constants.ts
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
export const NORMALIZE_REGEX = /\s*\r?\n|\r/g;
|
2
|
+
|
3
|
+
export const serverMessageKeys = {
|
4
|
+
challenge: "challenge",
|
5
|
+
conectionSize: "conectionSize",
|
6
|
+
heartbeat: "heartbeat",
|
7
|
+
inference: "inference",
|
8
|
+
inferenceEnded: "inferenceEnded",
|
9
|
+
join: "join",
|
10
|
+
joinAck: "joinAck",
|
11
|
+
leave: "leave",
|
12
|
+
newConversation: "newConversation",
|
13
|
+
ping: "ping",
|
14
|
+
pong: "pong",
|
15
|
+
providerDetails: "providerDetails",
|
16
|
+
reportCompletion: "reportCompletion",
|
17
|
+
requestProvider: "requestProvider",
|
18
|
+
sessionValid: "sessionValid",
|
19
|
+
verifySession: "verifySession",
|
20
|
+
} as const;
|
21
|
+
|
22
|
+
export const apiProviders = {
|
23
|
+
LiteLLM: 'litellm',
|
24
|
+
LlamaCpp: 'llamacpp',
|
25
|
+
LMStudio: 'lmstudio',
|
26
|
+
Ollama: 'ollama',
|
27
|
+
Oobabooga: 'oobabooga',
|
28
|
+
OpenWebUI: 'openwebui',
|
29
|
+
} as const
|
package/src/logger.ts
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
2
|
+
import chalk from "chalk";
|
3
|
+
|
4
|
+
export enum LogLevel {
|
5
|
+
DEBUG,
|
6
|
+
ERROR,
|
7
|
+
INFO,
|
8
|
+
WARNING,
|
9
|
+
}
|
10
|
+
|
11
|
+
export class Logger {
|
12
|
+
private static instance: Logger;
|
13
|
+
private logLevel: LogLevel = LogLevel.INFO;
|
14
|
+
|
15
|
+
private constructor() {}
|
16
|
+
|
17
|
+
public static getInstance(): Logger {
|
18
|
+
if (!Logger.instance) {
|
19
|
+
Logger.instance = new Logger();
|
20
|
+
}
|
21
|
+
return Logger.instance;
|
22
|
+
}
|
23
|
+
|
24
|
+
public setLogLevel(level: LogLevel): void {
|
25
|
+
this.logLevel = level;
|
26
|
+
}
|
27
|
+
|
28
|
+
public info(message: string, ...args: any[]): void {
|
29
|
+
if (this.logLevel <= LogLevel.INFO) {
|
30
|
+
console.log(chalk.blue("ℹ️ INFO:"), message, ...args);
|
31
|
+
}
|
32
|
+
}
|
33
|
+
|
34
|
+
public warning(message: string, ...args: any[]): void {
|
35
|
+
console.log(chalk.yellow("⚠️ WARNING:"), message, ...args);
|
36
|
+
}
|
37
|
+
|
38
|
+
public error(message: string, ...args: any[]): void {
|
39
|
+
console.error(chalk.red("❌ ERROR:"), message, ...args);
|
40
|
+
}
|
41
|
+
|
42
|
+
public debug(message: string, ...args: any[]): void {
|
43
|
+
console.log(chalk.gray("🐛 DEBUG:"), message, ...args);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
export const logger = Logger.getInstance();
|