tiger-agent 0.2.2 → 0.2.4
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 +85 -31
- package/package.json +1 -1
- package/src/agent/reflectionAgent.js +14 -2
- package/src/agent/reflectionScheduler.js +19 -3
- package/src/agent/skills.js +2 -1
- package/src/agent/toolbox.js +4 -3
package/README.md
CHANGED
|
@@ -10,13 +10,20 @@ Made by **AI Research Group, Department of Civil Engineering, KMUTT**
|
|
|
10
10
|
|
|
11
11
|
---
|
|
12
12
|
|
|
13
|
-
## 🆕 What's New — v0.2.
|
|
13
|
+
## 🆕 What's New — v0.2.4
|
|
14
|
+
|
|
15
|
+
- **ClawHub skill install fixed** — `clawhub_install` and `clawhub_search` now work correctly when installed via `npm install -g`
|
|
16
|
+
- **No required API keys** — `tiger onboard` skips providers with no key; any single provider is enough to start
|
|
17
|
+
- **`/limit` Telegram command** — set per-provider daily token limits from chat without restarting
|
|
18
|
+
- **Soul & ownskill refresh fixed** — 24-hour regeneration timer now uses DB timestamps, not file mtime, so reflection appends no longer block the update cycle
|
|
19
|
+
|
|
20
|
+
### v0.2.0
|
|
14
21
|
|
|
15
22
|
- **npm global install** — `npm install -g tiger-agent`, no git clone needed
|
|
16
23
|
- **Multi-provider LLM** — 5 providers (Kimi, Z.ai, MiniMax, Claude, Moonshot) with auto-fallback
|
|
17
24
|
- **Daily token limits** — per-provider limits with automatic switching at UTC midnight
|
|
18
25
|
- **`tiger` CLI** — unified command: `tiger onboard`, `tiger start`, `tiger telegram`, `tiger stop`
|
|
19
|
-
- **Telegram `/api
|
|
26
|
+
- **Telegram `/api`, `/tokens`, `/limit`** — manage providers and usage from chat
|
|
20
27
|
- **Encrypted secrets** — optional at-rest encryption for API keys
|
|
21
28
|
|
|
22
29
|
---
|
|
@@ -33,68 +40,94 @@ Made by **AI Research Group, Department of Civil Engineering, KMUTT**
|
|
|
33
40
|
|
|
34
41
|
---
|
|
35
42
|
|
|
43
|
+
## 📋 Requirements
|
|
44
|
+
|
|
45
|
+
- Node.js 18+ (20+ recommended)
|
|
46
|
+
- npm
|
|
47
|
+
- Python 3 (for SQLite memory helper)
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
36
51
|
## 📦 Installation
|
|
37
52
|
|
|
38
53
|
```bash
|
|
39
54
|
npm install -g tiger-agent
|
|
40
55
|
```
|
|
41
56
|
|
|
57
|
+
All config and runtime data is stored in `~/.tiger/` — nothing written to the npm global directory.
|
|
58
|
+
|
|
42
59
|
---
|
|
43
60
|
|
|
44
61
|
## 🚀 Quick Start
|
|
45
62
|
|
|
63
|
+
### 1. Run the setup wizard
|
|
64
|
+
|
|
46
65
|
```bash
|
|
47
|
-
tiger onboard
|
|
48
|
-
tiger start # Start CLI chat
|
|
66
|
+
tiger onboard
|
|
49
67
|
```
|
|
50
68
|
|
|
51
|
-
|
|
69
|
+
The wizard will ask for:
|
|
70
|
+
- **Active provider** — which LLM to use by default (e.g. `zai`, `claude`)
|
|
71
|
+
- **Fallback order** — comma-separated list tried when the active provider is rate-limited
|
|
72
|
+
- **API keys** — enter only the providers you have keys for; others are skipped automatically
|
|
73
|
+
- **Telegram bot token** — from [@BotFather](https://t.me/BotFather) on Telegram
|
|
74
|
+
- **Daily token limits** — per-provider caps (0 = unlimited); auto-switches on breach
|
|
75
|
+
- **Shell / skill-install** — optional tool permissions
|
|
52
76
|
|
|
53
|
-
|
|
77
|
+
Config is saved to `~/.tiger/.env` (mode 600).
|
|
54
78
|
|
|
79
|
+
### 2. Start
|
|
80
|
+
|
|
81
|
+
**CLI chat:**
|
|
55
82
|
```bash
|
|
56
|
-
tiger
|
|
57
|
-
tiger telegram --background # Start as background daemon
|
|
58
|
-
tiger stop # Stop daemon
|
|
59
|
-
tiger status # Check daemon status
|
|
83
|
+
tiger start
|
|
60
84
|
```
|
|
85
|
+
Exit with `/exit` or `/quit`.
|
|
61
86
|
|
|
62
|
-
|
|
87
|
+
**Telegram bot (foreground):**
|
|
88
|
+
```bash
|
|
89
|
+
tiger telegram
|
|
90
|
+
```
|
|
63
91
|
|
|
64
|
-
|
|
92
|
+
**Telegram bot (background daemon):**
|
|
93
|
+
```bash
|
|
94
|
+
tiger telegram --background # start
|
|
95
|
+
tiger status # check if running
|
|
96
|
+
tiger stop # stop
|
|
97
|
+
```
|
|
65
98
|
|
|
66
|
-
|
|
67
|
-
- npm
|
|
68
|
-
- Python 3 (for SQLite memory helper)
|
|
99
|
+
Logs: `~/.tiger/logs/telegram.out.log`
|
|
69
100
|
|
|
70
101
|
---
|
|
71
102
|
|
|
72
103
|
## 🎮 Run Modes
|
|
73
104
|
|
|
74
|
-
| Mode | Command |
|
|
75
|
-
|
|
105
|
+
| Mode | Command | Description |
|
|
106
|
+
|------|---------|-------------|
|
|
76
107
|
| **CLI** | `tiger start` | Interactive terminal chat |
|
|
77
108
|
| **Telegram** | `tiger telegram` | Telegram bot (foreground) |
|
|
78
|
-
| **Background** | `tiger telegram --background` | 24/7 daemon |
|
|
79
|
-
| **Stop** | `tiger stop` |
|
|
80
|
-
| **Status** | `tiger status` | Check
|
|
81
|
-
|
|
82
|
-
Background logs: `~/.tiger/logs/telegram-supervisor.log`
|
|
109
|
+
| **Background** | `tiger telegram --background` | 24/7 daemon with auto-restart |
|
|
110
|
+
| **Stop** | `tiger stop` | Stop background daemon |
|
|
111
|
+
| **Status** | `tiger status` | Check daemon status |
|
|
112
|
+
| **Onboard** | `tiger onboard` | Re-run setup wizard |
|
|
83
113
|
|
|
84
114
|
---
|
|
85
115
|
|
|
86
|
-
## 🔧 Setup Wizard
|
|
116
|
+
## 🔧 Setup Wizard Details
|
|
87
117
|
|
|
88
|
-
`tiger onboard`
|
|
118
|
+
`tiger onboard` writes `~/.tiger/.env` with all settings. You can re-run it at any time to update config.
|
|
89
119
|
|
|
90
|
-
|
|
91
|
-
|
|
120
|
+
| Wizard prompt | What it sets |
|
|
121
|
+
|---------------|-------------|
|
|
122
|
+
| Active provider | `ACTIVE_PROVIDER` |
|
|
123
|
+
| Fallback order | `PROVIDER_ORDER` |
|
|
124
|
+
| API keys | `ZAI_API_KEY`, `CLAUDE_API_KEY`, etc. |
|
|
125
|
+
| Telegram token | `TELEGRAM_BOT_TOKEN` |
|
|
126
|
+
| Token limits | `ZAI_TOKEN_LIMIT`, `CLAUDE_TOKEN_LIMIT`, etc. |
|
|
127
|
+
| Shell tool | `ALLOW_SHELL` |
|
|
128
|
+
| Skill install | `ALLOW_SKILL_INSTALL` |
|
|
92
129
|
|
|
93
|
-
|
|
94
|
-
- Choose LLM provider and API keys
|
|
95
|
-
- Persistent vs temporary vector DB
|
|
96
|
-
- Optional `sqlite-vec` acceleration
|
|
97
|
-
- Optional encrypted secrets file
|
|
130
|
+
> **Tip:** You can also edit `~/.tiger/.env` directly and restart the bot to apply changes.
|
|
98
131
|
|
|
99
132
|
---
|
|
100
133
|
|
|
@@ -233,6 +266,27 @@ Without it, Tiger falls back to cosine similarity in Python — slower but fully
|
|
|
233
266
|
| **Skills** | `list_skills`, `load_skill`, `clawhub_search`, `clawhub_install` |
|
|
234
267
|
| **Orchestration** | `run_sub_agents` |
|
|
235
268
|
|
|
269
|
+
### ClawHub Skills
|
|
270
|
+
|
|
271
|
+
Tiger can search and install skills from [ClawHub](https://clawhub.dev) — a community registry of reusable agent skills. The `clawhub` CLI is bundled with Tiger, no separate install needed.
|
|
272
|
+
|
|
273
|
+
Enable skill install in `~/.tiger/.env`:
|
|
274
|
+
|
|
275
|
+
```env
|
|
276
|
+
ALLOW_SKILL_INSTALL=true
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
Then just ask Tiger in chat:
|
|
280
|
+
|
|
281
|
+
```
|
|
282
|
+
Search for a web search skill on clawhub
|
|
283
|
+
Install the web-search skill
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
Skills are installed to `~/.tiger/skills/` and loaded automatically on demand.
|
|
287
|
+
|
|
288
|
+
> **Note:** `ALLOW_SKILL_INSTALL=true` must be set during `tiger onboard` or added manually to `~/.tiger/.env`.
|
|
289
|
+
|
|
236
290
|
---
|
|
237
291
|
|
|
238
292
|
## 🔒 Security
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { chatCompletion, embedText } = require('../llmClient');
|
|
4
|
-
const { dataDir, embeddingsEnabled } = require('../config');
|
|
4
|
+
const { dataDir, embeddingsEnabled, reflectionUpdateHours } = require('../config');
|
|
5
5
|
const { addMemory, getMeta, setMeta, getMessagesSince, getRecentMessagesAll } = require('./db');
|
|
6
6
|
|
|
7
7
|
const REFLECTION_META_KEY = 'memory_reflection_last_run_ts';
|
|
@@ -80,7 +80,7 @@ function appendHuman2Update(filePath, payload, stampIso) {
|
|
|
80
80
|
for (const w of payload.successfulWorkflows) lines.push(`- Workflow: ${w}`);
|
|
81
81
|
if (!lines.length) return;
|
|
82
82
|
const block = `\n## Update ${stampIso}\n${lines.join('\n')}\n`;
|
|
83
|
-
fs.writeFileSync(full, `${existing.trimEnd()}
|
|
83
|
+
fs.writeFileSync(full, `${existing.trimEnd()}${block}`, 'utf8');
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
async function generateReflection(rows, sinceIso, untilIso) {
|
|
@@ -123,9 +123,20 @@ async function generateReflection(rows, sinceIso, untilIso) {
|
|
|
123
123
|
};
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
+
function shouldRunReflectionCycle(lastRunTs) {
|
|
127
|
+
if (!lastRunTs) return true;
|
|
128
|
+
const hoursPassed = (nowTs() - lastRunTs) / (60 * 60 * 1000);
|
|
129
|
+
return hoursPassed >= reflectionUpdateHours;
|
|
130
|
+
}
|
|
131
|
+
|
|
126
132
|
async function maybeRunReflectionCycle({ force = false } = {}) {
|
|
127
133
|
const startedAt = nowTs();
|
|
128
134
|
const lastRunTs = Number(getMeta(REFLECTION_META_KEY, 0) || 0);
|
|
135
|
+
|
|
136
|
+
if (!force && !shouldRunReflectionCycle(lastRunTs)) {
|
|
137
|
+
return { ok: true, skipped: true, reason: 'not_yet_due' };
|
|
138
|
+
}
|
|
139
|
+
|
|
129
140
|
const rows = lastRunTs
|
|
130
141
|
? getMessagesSince(lastRunTs, MAX_MESSAGE_SCAN)
|
|
131
142
|
: getRecentMessagesAll(Math.min(MAX_MESSAGE_SCAN, 240));
|
|
@@ -185,6 +196,7 @@ async function maybeRunReflectionCycle({ force = false } = {}) {
|
|
|
185
196
|
}
|
|
186
197
|
|
|
187
198
|
setMeta(REFLECTION_META_KEY, startedAt);
|
|
199
|
+
console.log(`[ReflectionCycle] Completed at ${stampIso} (${rows.length} messages processed)`);
|
|
188
200
|
return { ok: true, skipped: false, at: stampIso };
|
|
189
201
|
}
|
|
190
202
|
|
|
@@ -8,14 +8,30 @@ function startReflectionScheduler() {
|
|
|
8
8
|
|
|
9
9
|
const everyMs = Math.max(1, Number(reflectionUpdateHours || 12)) * 60 * 60 * 1000;
|
|
10
10
|
|
|
11
|
+
console.log(`[ReflectionScheduler] Starting with interval: ${reflectionUpdateHours || 12} hours (${everyMs}ms)`);
|
|
12
|
+
|
|
11
13
|
// Kick one asynchronous check on startup.
|
|
12
|
-
maybeRunReflectionCycle().catch(() => {
|
|
14
|
+
maybeRunReflectionCycle().catch((err) => {
|
|
15
|
+
console.error('[ReflectionScheduler] Startup check failed:', err.message);
|
|
16
|
+
});
|
|
13
17
|
|
|
14
18
|
intervalHandle = setInterval(() => {
|
|
15
|
-
|
|
19
|
+
console.log('[ReflectionScheduler] Running scheduled reflection cycle...');
|
|
20
|
+
maybeRunReflectionCycle().catch((err) => {
|
|
21
|
+
console.error('[ReflectionScheduler] Scheduled cycle failed:', err.message);
|
|
22
|
+
});
|
|
16
23
|
}, everyMs);
|
|
17
24
|
}
|
|
18
25
|
|
|
26
|
+
function stopReflectionScheduler() {
|
|
27
|
+
if (intervalHandle) {
|
|
28
|
+
clearInterval(intervalHandle);
|
|
29
|
+
intervalHandle = null;
|
|
30
|
+
console.log('[ReflectionScheduler] Stopped');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
19
34
|
module.exports = {
|
|
20
|
-
startReflectionScheduler
|
|
35
|
+
startReflectionScheduler,
|
|
36
|
+
stopReflectionScheduler
|
|
21
37
|
};
|
package/src/agent/skills.js
CHANGED
|
@@ -4,7 +4,8 @@ const { execFile } = require('child_process');
|
|
|
4
4
|
const { promisify } = require('util');
|
|
5
5
|
|
|
6
6
|
const execFileAsync = promisify(execFile);
|
|
7
|
-
|
|
7
|
+
// Resolve clawhub from the package's own node_modules (works for both global and local installs)
|
|
8
|
+
const localClawhubBin = path.resolve(__dirname, '..', '..', 'node_modules', '.bin', 'clawhub');
|
|
8
9
|
|
|
9
10
|
function listSkills(baseDir) {
|
|
10
11
|
if (!fs.existsSync(baseDir)) return [];
|
package/src/agent/toolbox.js
CHANGED
|
@@ -7,7 +7,8 @@ const { listSkills, loadSkill, clawhubSearch, clawhubInstall } = require('./skil
|
|
|
7
7
|
const { runSubAgentBatch } = require('./subAgent');
|
|
8
8
|
|
|
9
9
|
const execAsync = promisify(exec);
|
|
10
|
-
const
|
|
10
|
+
const rootDir = process.env.TIGER_HOME || process.cwd();
|
|
11
|
+
const skillsDir = path.resolve(rootDir, 'skills');
|
|
11
12
|
|
|
12
13
|
function toAbsolutePath(inputPath) {
|
|
13
14
|
return path.resolve(String(inputPath || '.'));
|
|
@@ -113,7 +114,7 @@ async function clawhubSearchTool(args = {}) {
|
|
|
113
114
|
return clawhubSearch({
|
|
114
115
|
query: args.query,
|
|
115
116
|
limit: args.limit,
|
|
116
|
-
workdir: args.workdir ||
|
|
117
|
+
workdir: args.workdir || rootDir,
|
|
117
118
|
dir: args.dir || 'skills',
|
|
118
119
|
timeout_ms: args.timeout_ms
|
|
119
120
|
});
|
|
@@ -124,7 +125,7 @@ async function clawhubInstallTool(args = {}) {
|
|
|
124
125
|
slug: args.slug,
|
|
125
126
|
version: args.version,
|
|
126
127
|
force: args.force,
|
|
127
|
-
workdir: args.workdir ||
|
|
128
|
+
workdir: args.workdir || rootDir,
|
|
128
129
|
dir: args.dir || 'skills',
|
|
129
130
|
timeout_ms: args.timeout_ms
|
|
130
131
|
});
|