zyn-ai 1.3.6 → 1.4.0

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/README.md CHANGED
@@ -8,42 +8,41 @@
8
8
  <img src="https://img.shields.io/npm/v/zyn-ai?label=npm&color=%23CB3837" alt="NPM Version"/>
9
9
  <img src="https://img.shields.io/github/v/release/SoyMaycol/Zyn?include_prereleases&sort=semver" alt="Latest Release"/>
10
10
  <img src="https://img.shields.io/npm/dt/zyn-ai" alt="Downloads"/>
11
+ <img src="https://img.shields.io/github/license/SoyMaycol/Zyn" alt="License"/>
11
12
  </p>
12
13
 
13
14
  <p align="center">
14
- <b>Local AI agent for terminal, TUI, and web.</b>
15
+ <b>A complete CLI Agent for production and enterprise level, with incredible results.</b>
15
16
  </p>
16
17
 
17
18
  <p align="center">
18
- <a href="https://github.com/SoyMaycol/Zyn">Official repository</a>
19
+ <a href="https://github.com/SoyMaycol/Zyn">GitHub</a>
19
20
  </p>
20
21
 
21
22
  ---
22
23
 
23
- ## What is Zyn
24
+ ## Features
24
25
 
25
- Zyn is a local AI agent designed for terminal and web usage. It supports persistent sessions, system tools, multiple AI providers, session exports, and configurable models.
26
-
27
- ---
28
-
29
- ## Requirements
30
-
31
- - Node.js 18+
32
- - npm
33
- - Internet connection for remote providers
26
+ - **CLI + TUI** full terminal UI with keyboard navigation, token display, **improved history & compaction**, overlay system
27
+ - **Multi-provider** — Zen (free, no config), Gemini, Qwen (DashScope), HuggingFace, **skill search**, custom providers (any OpenAI-compatible API)
28
+ - **Skills system** — folder-based skills with **improved prompt integration** and YAML frontmatter
29
+ - **Tool execution** — read/write files, run commands, search code, browse web, glob patterns
30
+ - **Session management** — **real conversation history**, persistent sessions with **better compaction**, full transcript replay, resume, export
31
+ - **Context tracking** — token estimator with per-model context limits, **auto-compaction at 85%**, updated to reflect new history behavior
32
+ - **Multi-platform** — embeddable in WhatsApp (Baileys), Discord, and Telegram bots, Although this function is not complete (It is under development)
33
+ - **Background workers** — detach long-running turns to background processes
34
+ - **i18n** English and Spanish interfaces
34
35
 
35
36
  ---
36
37
 
37
38
  ## Installation
38
39
 
39
- ### Global install
40
-
41
40
  ```bash
42
41
  npm install -g zyn-ai
43
42
  zyn
44
43
  ```
45
44
 
46
- ### Local development
45
+ ### From source
47
46
 
48
47
  ```bash
49
48
  git clone https://github.com/SoyMaycol/Zyn.git
@@ -52,125 +51,190 @@ npm install
52
51
  npm start
53
52
  ```
54
53
 
55
- ---
56
-
57
54
  ## Usage
58
55
 
59
56
  ```bash
60
- zyn
61
- zyn "Explain this project"
62
- zyn --new
63
- zyn --resume ID
57
+ zyn # Interactive TUI (default)
58
+ zyn "question" # Single prompt (CLI mode)
59
+ zyn --new # Force new session
60
+ zyn --resume ID # Resume existing session (keeps history)
64
61
  ```
65
62
 
66
- ---
67
-
68
- ## Web mode
69
-
70
- Inside Zyn:
63
+ ## Models
71
64
 
72
- ```text
73
- /web
74
- /web 0.0.0.0:3000
75
- ```
65
+ 14 built-in models across 4 providers. Each model has its real context length in the StatusBar (e.g. `10.8K/128K`).
76
66
 
77
- Or directly:
67
+ ### Zen (free, no configuration)
78
68
 
79
- ```bash
80
- npm run web
81
- ```
69
+ | Key | Model | Context |
70
+ |---|---|---|
71
+ | `nemotron` | Nemotron 3 Ultra | 128K |
72
+ | `mimo` | Mimo 2.5 | 128K |
73
+ | `north-mini` | North Mini Code | 128K |
74
+ | `deepseek` | DeepSeek V4 Flash | 128K |
82
75
 
83
- ---
76
+ ### Gemini (requires API key)
84
77
 
85
- ## Language
78
+ | Key | Model | Context |
79
+ |---|---|---|
80
+ | `gemini-flash` | Gemini 2.5 Flash | 1M |
81
+ | `gemini-flash-001` | Gemini 2.5 Flash 001 | 1M |
82
+ | `gemini-pro` | Gemini 2.5 Pro | 1M |
83
+ | `gemini-flash-lite` | Gemini 2.5 Flash Lite | 1M |
84
+ | `gemini-flash-lite-001` | Gemini 2.5 Flash Lite 001 | 1M |
85
+ | `gemma-3` | Gemma 3 27B | 128K |
86
86
 
87
- Supported languages:
87
+ ### Qwen (requires DashScope API key)
88
88
 
89
- - `en`
90
- - `es`
89
+ | Key | Model | Context |
90
+ |---|---|---|
91
+ | `qwen-plus` | Qwen Plus | 128K |
92
+ | `qwen-max` | Qwen Max | 32K |
93
+ | `qwen-turbo` | Qwen Turbo | 1M |
91
94
 
92
- Commands:
95
+ ### HuggingFace (requires HF token)
93
96
 
94
- ```text
95
- /lang
96
- /lang en
97
- /lang es
98
- ```
97
+ | Key | Model | Context |
98
+ |---|---|---|
99
+ | `hf-ling-2.6-1t` | InclusionAI Ling 2.6 1T | 128K |
99
100
 
100
- ---
101
+ Default model: `nemotron` (Zen, no configuration required).
101
102
 
102
- ## Main Commands
103
+ ## Commands
103
104
 
104
105
  ### Sessions
105
106
 
106
107
  | Command | Description |
107
108
  |---|---|
108
- | `/help` | Show available commands |
109
- | `/status` | Show current status |
110
- | `/history` | Show recent actions |
111
- | `/memory` | Show memory summary |
112
- | `/sessions` | List saved sessions |
113
- | `/new` | Create a new session |
114
- | `/resume <ID>` | Resume a session |
109
+ | `/help` | Show help |
110
+ | `/status` | Current status |
111
+ | `/history` | Recent actions (last 20) |
112
+ | `/memory` | Memory summary |
113
+ | `/session` | Current session info |
114
+ | `/sessions` | List all sessions |
115
+ | `/new` | New session |
116
+ | `/resume <ID>` | Resume session (keeps history) |
115
117
  | `/title <text>` | Rename session |
116
118
 
117
119
  ### Configuration
118
120
 
119
121
  | Command | Description |
120
122
  |---|---|
121
- | `/model` | Show or change model |
122
- | `/models` | List models |
123
- | `/providers` | List providers |
123
+ | `/models` | Open model picker (current provider) |
124
+ | `/providers` | Open interactive provider picker → configure → pick model |
125
+ | `/provider list` | List configured providers and their fields |
126
+ | `/provider sync <name>` | Fetch models from a provider's API |
127
+ | `/provider set <name> <field> <value>` | Set provider config (apiKey, baseUrl, modelId, contextLength) |
128
+ | `/provider remove <name>` | Remove a provider configuration |
124
129
  | `/lang <en\|es>` | Change language |
130
+ | `/auto on\|off` | Toggle auto-approval |
131
+ | `/concuerdo` | Toggle group model mode (queries all configured models) |
132
+ | `/persona set <text>` | Set response persona |
125
133
  | `/config show` | Show config |
126
- | `/auto on\|off` | Toggle auto approval |
134
+ | `/git set\|list\|remove` | Manage git credentials |
127
135
  | `/cwd <path>` | Change working directory |
128
136
 
129
- ### Tools
137
+ ### Tools & Skills
130
138
 
131
139
  | Command | Description |
132
140
  |---|---|
133
- | `/tools` | List tools |
134
- | `/skills` | List skills |
135
- | `/gmail connect` | Connect Gmail with Google OAuth + PKCE |
136
- | `/gmail status` | Show Gmail connection status |
137
- | `/gmail disconnect` | Remove saved Gmail tokens |
138
- | `/cwd` | Show working directory |
141
+ | `/tools` | List agent tools |
142
+ | `/skills` | List loaded skills |
143
+ | `/gmail connect` | Connect Gmail via OAuth |
139
144
 
140
- ### Web & Export
145
+ ### Export & Control
141
146
 
142
147
  | Command | Description |
143
148
  |---|---|
144
- | `/web` | Start web interface |
145
- | `/transcript` | Show transcript |
146
- | `/export` | Export session |
149
+ | `/bg` | Detach current turn to background |
150
+ | `/transcript` | View session transcript |
151
+ | `/export` | Export session to txt |
152
+ | `/stop` | Stop current agent turn |
153
+ | `/undo` | Undo last turn |
154
+ | `/redo` | Redo undone turn |
155
+ | `/reset` | Reset context |
156
+ | `/exit` | Exit |
147
157
 
148
- ### Control
158
+ Press `ESC` twice in the TUI to stop the current task.
149
159
 
150
- | Command | Description |
151
- |---|---|
152
- | `/stop` | Stop current task |
153
- | `/reset` | Reset session |
154
- | `/exit` | Exit Zyn |
160
+ ## Custom Providers
155
161
 
156
- In the TUI, press `ESC` twice to stop the current task.
162
+ Add any OpenAI-compatible API:
157
163
 
164
+ ```bash
165
+ # Interactive: run /providers → select "+ Add custom provider"
166
+ # Or manual:
167
+ /provider set groq baseUrl https://api.groq.com/openai/v1
168
+ /provider set groq apiKey gsk_xxxx
169
+ /provider set groq contextLength 128000
170
+ /provider sync groq
171
+ ```
172
+
173
+ Configurable fields: `apiKey`, `baseUrl`, `modelId`, `contextLength`, `email`, `password`, `modelEndpoint`, `chatEndpoint`.
174
+
175
+ ## Skills
176
+
177
+ Skills are folders under `data/skills/<name>/SKILL.md` with YAML frontmatter:
178
+
179
+ ```markdown
180
+ ---
181
+ name: reasoning
182
+ description: Reasoning and planning for complex tasks
158
183
  ---
159
184
 
160
- ## Models
185
+ # Skill body here
186
+ ```
187
+
188
+ The system prompt automatically advertises every loaded skill to the model, and mentions of GitHub repos/skills trigger `web_search` to find them.
189
+
190
+ ## API
161
191
 
162
- Custom models can be added using `data/models.json`.
192
+ ### Embed in your bot
163
193
 
164
- Example:
194
+ ```js
195
+ const { createAgent } = require('zyn-ai');
165
196
 
166
- ```json
167
- {
168
- "models": {
169
- "my-gemini-flash": {
170
- "label": "Gemini Flash",
171
- "provider": "gemini",
172
- "geminiModel": "gemini-flash"
173
- }
174
- }
175
- }
197
+ const agent = createAgent({
198
+ model: 'nemotron',
199
+ language: 'en',
200
+ autoApprove: false,
201
+ });
202
+
203
+ const response = await agent.send('userId', 'Hello!');
176
204
  ```
205
+
206
+ ### Platforms
207
+
208
+ ```js
209
+ const { createAgent, platforms } = require('zyn-ai');
210
+
211
+ const agent = createAgent({ model: 'nemotron' });
212
+
213
+ // WhatsApp (Baileys)
214
+ await platforms.whatsapp({ agent, session: './whatsapp-auth' });
215
+
216
+ // Discord
217
+ await platforms.discord({ agent, token: 'DISCORD_TOKEN' });
218
+
219
+ // Telegram
220
+ await platforms.telegram({ agent, token: 'TELEGRAM_TOKEN' });
221
+ ```
222
+
223
+ Install the corresponding `optionalDependencies` only if you need them.
224
+
225
+ ## Environment Variables
226
+
227
+ | Variable | Description |
228
+ |---|---|
229
+ | `ZYN_DEFAULT_MODEL` | Override default model key |
230
+ | `ZYN_DEFAULT_LANG` | Default language (`en` or `es`) |
231
+ | `ZYN_GEMINI_API_KEY` | Gemini API key |
232
+ | `ZYN_QWEN_API_KEY` | DashScope API key |
233
+ | `ZYN_HUGGINGFACE_TOKEN` | HuggingFace token |
234
+ | `ZYN_REQUEST_TIMEOUT_MS` | Request timeout (default: 180000) |
235
+ | `ZYN_PROVIDER_TIMEOUT_MAX_ATTEMPTS` | Retry attempts on provider failure (default: 3) |
236
+ | `ZYN_GMAIL_CLIENT_SECRET` | Gmail OAuth client secret |
237
+
238
+ ## License
239
+
240
+ MIT - Maycol B.T
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "zyn-ai",
3
- "version": "1.3.6",
4
- "description": "Production-ready AI agent for CLI and web with real tool execution and automation",
3
+ "version": "1.4.0",
4
+ "description": "Production-ready AI agent for CLI, TUI, and external platforms (WhatsApp/Baileys, Discord, Telegram) with real tool execution and automation",
5
5
  "author": "Maycol",
6
6
  "keywords": [
7
7
  "ai-agent",
@@ -14,7 +14,12 @@
14
14
  "productivity-tool",
15
15
  "local-ai-agent",
16
16
  "command-line-ai",
17
- "web-ai-agent",
17
+ "tui-agent",
18
+ "whatsapp-bot",
19
+ "discord-bot",
20
+ "telegram-bot",
21
+ "multi-platform",
22
+ "embeddable-agent",
18
23
  "zyn"
19
24
  ],
20
25
  "bin": {
@@ -22,23 +27,23 @@
22
27
  "Zyn": "./zyn.js"
23
28
  },
24
29
  "type": "commonjs",
30
+ "main": "./src/agent.js",
25
31
  "scripts": {
26
32
  "start": "node zyn.js",
27
33
  "dev": "node zyn.js",
28
- "web": "node src/web/server.js",
29
- "check": "node --check zyn.js && node --check src/cli/runtime.js"
34
+ "check": "node --check zyn.js && node --check src/cli/runtime.js && node --check src/agent.js"
30
35
  },
31
36
  "dependencies": {
32
37
  "axios": "^1.7.9",
33
- "bcryptjs": "^3.0.3",
34
38
  "cheerio": "^1.2.0",
35
- "express": "^5.2.1",
36
- "express-session": "^1.19.0",
37
39
  "ink": "^6.8.0",
38
- "keypress": "^0.2.1",
39
40
  "react": "^19.0.0",
40
- "session-file-store": "^1.5.0",
41
- "jimp": "^1.6.1"
41
+ "jimp": "^0.16.1"
42
+ },
43
+ "optionalDependencies": {
44
+ "@whiskeysockets/baileys": "^6.7.0",
45
+ "discord.js": "^14.16.0",
46
+ "node-telegram-bot-api": "^0.66.0"
42
47
  },
43
48
  "repository": {
44
49
  "type": "git",
@@ -59,7 +64,12 @@
59
64
  "LICENSE"
60
65
  ],
61
66
  "exports": {
62
- ".": "./zyn.js"
67
+ ".": "./src/agent.js",
68
+ "./agent": "./src/agent.js",
69
+ "./platforms": "./src/platforms/index.js",
70
+ "./platforms/baileys": "./src/platforms/baileys.js",
71
+ "./platforms/discord": "./src/platforms/discord.js",
72
+ "./platforms/telegram": "./src/platforms/telegram.js"
63
73
  },
64
74
  "preferGlobal": true
65
75
  }
package/src/agent.js ADDED
@@ -0,0 +1,168 @@
1
+ const { EventEmitter } = require('events');
2
+ const { runAgentTurn } = require('./core/agent');
3
+ const { createNewSessionState, loadSessionState, loadOrCreateSessionState, listSessions, saveState } = require('./utils/sessionStorage');
4
+ const { MODELS, DEFAULT_MODEL_KEY, DEFAULT_LANGUAGE } = require('./config');
5
+ const { listSkills, listModels } = require('./public/helpers');
6
+ const { runBackgroundWorker, detachBackgroundTurn } = require('./utils/backgroundWorker');
7
+ const { enqueueBackgroundTask, listBackgroundResults, consumeBackgroundResult } = require('./utils/sessionStorage');
8
+
9
+ function noopUi() {
10
+ return {
11
+ beginThinkingStream() {},
12
+ writeThinkingDelta() {},
13
+ endThinkingStream() {},
14
+ beginAssistantStream() {},
15
+ writeAssistantDelta() {},
16
+ endAssistantStream() {},
17
+ startThinkingIndicator() { return () => {}; },
18
+ pushAction() {},
19
+ logEvent() {},
20
+ paint: (text) => text,
21
+ };
22
+ }
23
+
24
+ function createAgent(options = {}) {
25
+ const emitter = new EventEmitter();
26
+ emitter.setMaxListeners(50);
27
+
28
+ const config = {
29
+ sessionId: options.sessionId || null,
30
+ cwd: options.cwd || process.cwd(),
31
+ model: options.model || DEFAULT_MODEL_KEY,
32
+ language: options.language || DEFAULT_LANGUAGE,
33
+ autoApprove: options.autoApprove !== undefined ? Boolean(options.autoApprove) : true,
34
+ personaPrompt: options.personaPrompt || '',
35
+ userId: options.userId || 'default',
36
+ resume: options.resume || false,
37
+ };
38
+
39
+ let state = null;
40
+ let initPromise = null;
41
+
42
+ async function ensureState() {
43
+ if (state) return state;
44
+ if (!initPromise) {
45
+ initPromise = (async () => {
46
+ if (config.sessionId) {
47
+ const loaded = await loadSessionState(config.sessionId, null);
48
+ if (loaded) {
49
+ if (config.cwd) loaded.cwd = config.cwd;
50
+ loaded.activeModel = config.model;
51
+ loaded.language = config.language;
52
+ loaded.autoApprove = config.autoApprove;
53
+ if (config.personaPrompt) loaded.personaPrompt = config.personaPrompt;
54
+ state = loaded;
55
+ return state;
56
+ }
57
+ }
58
+ if (config.resume) {
59
+ const loaded = await loadOrCreateSessionState(null, { forceNew: false, resume: true });
60
+ state = loaded.state;
61
+ return state;
62
+ }
63
+ state = await createNewSessionState(null);
64
+ state.cwd = config.cwd;
65
+ state.activeModel = config.model;
66
+ state.language = config.language;
67
+ state.autoApprove = config.autoApprove;
68
+ state.personaPrompt = config.personaPrompt;
69
+ await saveState(state);
70
+ return state;
71
+ })();
72
+ }
73
+ return initPromise;
74
+ }
75
+
76
+ emitter.send = async function send(userId, text) {
77
+ const s = await ensureState();
78
+ const userKey = userId || config.userId;
79
+ s.history.push({ role: 'user', content: String(text), userId: userKey });
80
+ const ui = noopUi();
81
+ const controller = new AbortController();
82
+ emitter.emit('turnStart', { userId: userKey, text });
83
+ try {
84
+ const result = await runAgentTurn(String(text), s, ui, { signal: controller.signal });
85
+ emitter.emit('turnEnd', { userId: userKey, text, content: result.content });
86
+ emitter.emit('message', { userId: userKey, role: 'assistant', content: result.content });
87
+ return result.content;
88
+ } catch (err) {
89
+ emitter.emit('error', err);
90
+ throw err;
91
+ } finally {
92
+ await saveState(s);
93
+ }
94
+ };
95
+
96
+ emitter.detach = function detach(userId, text) {
97
+ return (async () => {
98
+ const s = await ensureState();
99
+ const userKey = userId || config.userId;
100
+ const taskId = enqueueBackgroundTask({ sessionId: s.sessionId, input: String(text), detachedAt: new Date().toISOString() });
101
+ detachBackgroundTurn({
102
+ taskId,
103
+ sessionId: s.sessionId,
104
+ input: String(text),
105
+ cwd: s.cwd,
106
+ modelKey: s.activeModel,
107
+ language: s.language,
108
+ personaPrompt: s.personaPrompt,
109
+ autoApprove: s.autoApprove,
110
+ });
111
+ return taskId;
112
+ })();
113
+ };
114
+
115
+ emitter.consumeBackground = async function consumeBackground() {
116
+ const s = await ensureState();
117
+ const results = await listBackgroundResults(s.sessionId);
118
+ for (const r of results) {
119
+ emitter.emit('background', r);
120
+ await consumeBackgroundResult(r.taskId);
121
+ }
122
+ return results;
123
+ };
124
+
125
+ emitter.getState = async function getState() {
126
+ const s = await ensureState();
127
+ return {
128
+ sessionId: s.sessionId,
129
+ title: s.title,
130
+ cwd: s.cwd,
131
+ activeModel: s.activeModel,
132
+ language: s.language,
133
+ turnCount: s.turnCount,
134
+ historyLength: s.history.length,
135
+ };
136
+ };
137
+
138
+ emitter.reset = async function reset() {
139
+ const s = await ensureState();
140
+ s.history = [];
141
+ s.actionLog = [];
142
+ s.turnCount = 0;
143
+ s.memorySummary = '';
144
+ await saveState(s);
145
+ return true;
146
+ };
147
+
148
+ emitter.close = async function close() {
149
+ if (state) {
150
+ await saveState(state);
151
+ }
152
+ };
153
+
154
+ return emitter;
155
+ }
156
+
157
+ module.exports = {
158
+ createAgent,
159
+ listSkills,
160
+ listModels,
161
+ listSessions,
162
+ loadSessionState,
163
+ runBackgroundWorker,
164
+ runAgentTurn,
165
+ DEFAULT_LANGUAGE,
166
+ DEFAULT_MODEL_KEY,
167
+ MODELS,
168
+ };