tiger-agent 0.2.4 → 0.3.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/.env.example +10 -0
- package/README.md +264 -4
- package/package.json +1 -1
- package/src/agent/contextFileMirrors.js +39 -0
- package/src/agent/contextFiles.js +4 -1
- package/src/agent/mainAgent.js +4 -3
- package/src/agent/reflectionAgent.js +3 -2
- package/src/agent/skills.js +1 -1
- package/src/apiProviders.js +8 -9
- package/src/apiProviders.js.bak +222 -0
- package/src/cli.js +4 -0
- package/src/config.js +11 -0
- package/src/llmClient.js +11 -1
- package/src/swarm/agentRuntime.js +699 -0
- package/src/swarm/agentRuntime.js.bak +456 -0
- package/src/swarm/configStore.js +360 -0
- package/src/swarm/index.js +25 -0
- package/src/swarm/taskBus.js +246 -0
- package/src/telegram/bot.js +329 -1
package/.env.example
CHANGED
|
@@ -10,6 +10,16 @@ GEMINI_API_KEY=your_gemini_api_key_here
|
|
|
10
10
|
# Telegram Bot
|
|
11
11
|
TELEGRAM_BOT_TOKEN=your_telegram_bot_token_here
|
|
12
12
|
TELEGRAM_CHAT_ID=8172556270
|
|
13
|
+
# Swarm agent step timeout in ms (0 = no extra swarm timeout)
|
|
14
|
+
SWARM_AGENT_TIMEOUT_MS=0
|
|
15
|
+
# Swarm-only provider failover on timeout/network/API error (true/false)
|
|
16
|
+
SWARM_ROUTE_ON_PROVIDER_ERROR=false
|
|
17
|
+
# Swarm default flow for new Telegram tasks (auto|design|research_build)
|
|
18
|
+
SWARM_DEFAULT_FLOW=auto
|
|
19
|
+
# First agent policy (auto|flow|fixed|designer|scout|coder|critic|senior_eng|spec_writer)
|
|
20
|
+
SWARM_FIRST_AGENT_POLICY=auto
|
|
21
|
+
# Used when SWARM_FIRST_AGENT_POLICY=fixed
|
|
22
|
+
SWARM_FIRST_AGENT=designer
|
|
13
23
|
|
|
14
24
|
# X/Twitter (optional - paid API)
|
|
15
25
|
X_BEARER_TOKEN=your_x_bearer_token_here
|
package/README.md
CHANGED
|
@@ -1,16 +1,32 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="./IMG_5745.jpg" alt="Tiger bot" width="900" />
|
|
3
|
+
</p>
|
|
4
|
+
|
|
1
5
|
# 🐯 Tiger Agent
|
|
2
6
|
|
|
3
7
|
[](https://www.npmjs.com/package/tiger-agent)
|
|
4
8
|
[](LICENSE)
|
|
5
9
|
[](https://nodejs.org)
|
|
6
10
|
|
|
7
|
-
**
|
|
11
|
+
**Agentic Swarm AI Agent** with persistent long-term memory, multi-provider LLM support, token management, self-learning, and Telegram bot integration — designed for 24/7 autonomous operation on Linux.
|
|
8
12
|
|
|
9
13
|
Made by **AI Research Group, Department of Civil Engineering, KMUTT**
|
|
10
14
|
|
|
11
15
|
---
|
|
12
16
|
|
|
13
|
-
## 🆕 What's New — v0.
|
|
17
|
+
## 🆕 What's New — v0.3.1
|
|
18
|
+
|
|
19
|
+
- **YAML swarm architecture** — swarm flow is now configurable in `swarm/architecture/*.yaml` with orchestrator, agents, stages, and judgment matrix
|
|
20
|
+
- **YAML task style** — task routing style is configurable in `tasks/styles/*.yaml` and can select which architecture file to use
|
|
21
|
+
- **Telegram architecture editing** — added `/architecture` and `/taskstyle` commands so Telegram users can list/show/write YAML and switch default architecture
|
|
22
|
+
- **Parallel design orchestration default** — default architecture runs 3 designers in parallel, reviewer selects best, revision loop applies, then spec writer finalizes
|
|
23
|
+
|
|
24
|
+
### v0.2.5
|
|
25
|
+
|
|
26
|
+
- **Context-file mirror compatibility** — if legacy root files like `./soul.md` or `./ownskill.md` already exist, Tiger now mirrors updates to them automatically while continuing to use `DATA_DIR` as the canonical source
|
|
27
|
+
- **README path clarification** — docs now explicitly distinguish canonical `DATA_DIR` files from optional legacy root mirrors
|
|
28
|
+
|
|
29
|
+
### v0.2.4
|
|
14
30
|
|
|
15
31
|
- **ClawHub skill install fixed** — `clawhub_install` and `clawhub_search` now work correctly when installed via `npm install -g`
|
|
16
32
|
- **No required API keys** — `tiger onboard` skips providers with no key; any single provider is enough to start
|
|
@@ -96,6 +112,13 @@ tiger status # check if running
|
|
|
96
112
|
tiger stop # stop
|
|
97
113
|
```
|
|
98
114
|
|
|
115
|
+
**Restart background bot (after editing `.env` in this repo):**
|
|
116
|
+
```bash
|
|
117
|
+
cd /root/tiger
|
|
118
|
+
npm run telegram:stop
|
|
119
|
+
npm run telegram:bg
|
|
120
|
+
```
|
|
121
|
+
|
|
99
122
|
Logs: `~/.tiger/logs/telegram.out.log`
|
|
100
123
|
|
|
101
124
|
---
|
|
@@ -141,7 +164,7 @@ Logs: `~/.tiger/logs/telegram.out.log`
|
|
|
141
164
|
| `ALLOW_SHELL` | `false` | Enable shell tool |
|
|
142
165
|
| `ALLOW_SKILL_INSTALL` | `false` | Enable ClawHub skill install |
|
|
143
166
|
| `VECTOR_DB_PATH` | `~/.tiger/db/memory.sqlite` | SQLite vector DB path |
|
|
144
|
-
| `DATA_DIR` | `~/.tiger/data` |
|
|
167
|
+
| `DATA_DIR` | `~/.tiger/data` | Canonical context files directory |
|
|
145
168
|
| `OWN_SKILL_UPDATE_HOURS` | `24` | Hours between `ownskill.md` regenerations (min 1) |
|
|
146
169
|
| `SOUL_UPDATE_HOURS` | `24` | Hours between `soul.md` regenerations (min 1) |
|
|
147
170
|
| `REFLECTION_UPDATE_HOURS` | `12` | Hours between reflection cycles (min 1) |
|
|
@@ -184,6 +207,22 @@ ZAI_TOKEN_LIMIT=100000
|
|
|
184
207
|
MINIMAX_TOKEN_LIMIT=100000
|
|
185
208
|
CLAUDE_TOKEN_LIMIT=500000
|
|
186
209
|
MOONSHOT_TOKEN_LIMIT=100000
|
|
210
|
+
|
|
211
|
+
# Provider request timeouts (ms)
|
|
212
|
+
KIMI_TIMEOUT_MS=120000
|
|
213
|
+
ZAI_TIMEOUT_MS=120000
|
|
214
|
+
|
|
215
|
+
# Swarm worker-step timeout (0 = no extra swarm timeout)
|
|
216
|
+
SWARM_AGENT_TIMEOUT_MS=120000
|
|
217
|
+
|
|
218
|
+
# Swarm only: on timeout/network/API error, retry via next provider
|
|
219
|
+
SWARM_ROUTE_ON_PROVIDER_ERROR=true
|
|
220
|
+
|
|
221
|
+
# Swarm task entry policy
|
|
222
|
+
SWARM_DEFAULT_FLOW=auto
|
|
223
|
+
SWARM_FIRST_AGENT_POLICY=auto
|
|
224
|
+
# Used only when SWARM_FIRST_AGENT_POLICY=fixed
|
|
225
|
+
SWARM_FIRST_AGENT=designer
|
|
187
226
|
```
|
|
188
227
|
|
|
189
228
|
### Auto-Switch Behaviour
|
|
@@ -205,15 +244,232 @@ MOONSHOT_TOKEN_LIMIT=100000
|
|
|
205
244
|
| `/tokens` | Show today's token usage per provider |
|
|
206
245
|
| `/limit` | Show daily token limits per provider |
|
|
207
246
|
| `/limit <provider> <n>` | Set daily token limit (0 = unlimited, e.g. `/limit zai 100000`) |
|
|
247
|
+
| `/swarm` | Show agent swarm status (ON/OFF) |
|
|
248
|
+
| `/swarm <on|off>` | Enable or disable internal swarm routing for normal messages |
|
|
249
|
+
| `/status` | Show swarm task queues (`pending`, `in_progress`, `done`, `failed`) |
|
|
250
|
+
| `/task` | List swarm tasks across queues |
|
|
251
|
+
| `/task continue <task_id>` | Resume a failed/stuck swarm task from the last failed agent |
|
|
252
|
+
| `/task retry <task_id>` | Alias of `/task continue <task_id>` |
|
|
253
|
+
| `/task delete <task_id>` | Delete a swarm task file from queue storage |
|
|
254
|
+
| `/agents` | Show internal swarm agents and availability |
|
|
255
|
+
| `/cancel <task_id>` | Cancel a swarm task |
|
|
256
|
+
| `/ask <agent> <question>` | Ask a specific internal agent role directly |
|
|
257
|
+
| `/architecture` | List swarm architecture YAML files |
|
|
258
|
+
| `/architecture show <file>` | Show one architecture YAML file |
|
|
259
|
+
| `/architecture use <file>` | Set default task-style architecture file |
|
|
260
|
+
| `/architecture write <file>` + newline + yaml | Save architecture YAML from Telegram |
|
|
261
|
+
| `/taskstyle` | List task-style YAML files |
|
|
262
|
+
| `/taskstyle show <file>` | Show one task-style YAML file |
|
|
263
|
+
| `/taskstyle write <file>` + newline + yaml | Save task-style YAML from Telegram |
|
|
208
264
|
| `/help` | Show all commands |
|
|
209
265
|
|
|
266
|
+
### Swarm Settings (`/swarm`)
|
|
267
|
+
|
|
268
|
+
Tiger v0.3.1 includes an internal agent swarm for Telegram message routing.
|
|
269
|
+
|
|
270
|
+
- **Default:** swarm is **ON** when the Telegram bot starts
|
|
271
|
+
- **`/swarm on`**: regular user messages are routed through the YAML architecture in `swarm/architecture/*.yaml` (selected by `tasks/styles/default.yaml`)
|
|
272
|
+
- **`/swarm off`**: regular user messages skip the swarm and go directly to the standard Tiger agent reply path
|
|
273
|
+
- **Scope:** this toggle affects only **normal chat messages** (not admin commands like `/api`, `/tokens`, `/limit`)
|
|
274
|
+
- **Current persistence:** the `/swarm` toggle is currently **in-memory only** and resets to **ON** after bot restart
|
|
275
|
+
- **Task resume:** use `/task continue <task_id>` (or `/task retry <task_id>`) to continue a failed timeout/API-error task without starting over
|
|
276
|
+
|
|
277
|
+
### Swarm Timeout / Failover (`.env`)
|
|
278
|
+
|
|
279
|
+
- `SWARM_AGENT_TIMEOUT_MS`: timeout per swarm worker step (e.g. one `designer` turn). `0` disables the extra swarm timeout.
|
|
280
|
+
- `SWARM_ROUTE_ON_PROVIDER_ERROR=true|false`: swarm-only provider failover on timeout/network/API errors.
|
|
281
|
+
- Provider timeouts are separate and provider-specific, for example `KIMI_TIMEOUT_MS`, `ZAI_TIMEOUT_MS`, `CLAUDE_TIMEOUT_MS`.
|
|
282
|
+
|
|
283
|
+
### Swarm Entry Policy (`.env`)
|
|
284
|
+
|
|
285
|
+
- `SWARM_DEFAULT_FLOW=auto|design|research_build`: default flow for new Telegram swarm tasks.
|
|
286
|
+
- `SWARM_FIRST_AGENT_POLICY` controls who starts first:
|
|
287
|
+
- `auto` (default): Tiger/orchestrator picks based on the goal text
|
|
288
|
+
- `flow`: use flow mapping (`research_build -> scout`, otherwise `designer`)
|
|
289
|
+
- `fixed`: use `SWARM_FIRST_AGENT`
|
|
290
|
+
- or set a direct agent name (for example `designer`, `scout`, `coder`)
|
|
291
|
+
- `SWARM_FIRST_AGENT` is used when `SWARM_FIRST_AGENT_POLICY=fixed`
|
|
292
|
+
|
|
293
|
+
Examples:
|
|
294
|
+
|
|
295
|
+
```text
|
|
296
|
+
/swarm
|
|
297
|
+
/swarm off
|
|
298
|
+
/swarm on
|
|
299
|
+
/task
|
|
300
|
+
/task retry task_xxx
|
|
301
|
+
/task delete task_xxx
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### Swarm Agent Files (Manual Customization)
|
|
305
|
+
|
|
306
|
+
Tiger creates a local swarm workspace so you can manually customize each agent's behavior.
|
|
307
|
+
|
|
308
|
+
Default folders (project/runtime root):
|
|
309
|
+
|
|
310
|
+
```text
|
|
311
|
+
agents/
|
|
312
|
+
tiger/
|
|
313
|
+
designer/
|
|
314
|
+
senior_eng/
|
|
315
|
+
spec_writer/
|
|
316
|
+
scout/
|
|
317
|
+
coder/
|
|
318
|
+
critic/
|
|
319
|
+
tasks/
|
|
320
|
+
pending/
|
|
321
|
+
in_progress/
|
|
322
|
+
done/
|
|
323
|
+
failed/
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Each agent folder includes files such as:
|
|
327
|
+
|
|
328
|
+
- `soul.md` — the agent's personality, rules, and mindset
|
|
329
|
+
- `ownskill.md` — what the agent is good at / preferred workflow
|
|
330
|
+
- `experience.json` — learned lessons and task stats
|
|
331
|
+
- `memory.md` — long-form notes/patterns
|
|
332
|
+
- `human.md` — only for `agents/tiger/` (user preferences)
|
|
333
|
+
|
|
334
|
+
Manual setup / editing:
|
|
335
|
+
|
|
336
|
+
- Start the bot once (`tiger telegram` or `tiger start`) and Tiger will auto-create missing `agents/` and `tasks/` folders
|
|
337
|
+
- You can then open and edit files like `agents/designer/soul.md` or `agents/senior_eng/soul.md` manually
|
|
338
|
+
- Your edits are used on future swarm runs (for example `/ask designer ...` or normal swarm-routed messages)
|
|
339
|
+
- Keep edits in plain Markdown/JSON and avoid deleting required files while the bot is running
|
|
340
|
+
|
|
341
|
+
Example customization ideas:
|
|
342
|
+
|
|
343
|
+
- Make `designer` more creative / visual
|
|
344
|
+
- Make `senior_eng` stricter about security, error handling, and scalability
|
|
345
|
+
- Make `spec_writer` produce a specific document format your team uses
|
|
346
|
+
|
|
347
|
+
### Swarm Architecture YAML (v0.3.1)
|
|
348
|
+
|
|
349
|
+
Default files:
|
|
350
|
+
|
|
351
|
+
```text
|
|
352
|
+
swarm/architecture/tiger_parallel_design.yaml
|
|
353
|
+
tasks/styles/default.yaml
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
Default architecture behavior:
|
|
357
|
+
|
|
358
|
+
- Orchestrator: `tiger`
|
|
359
|
+
- Stage 1: send task simultaneously to `designer_a`, `designer_b`, `designer_c` (different souls/personalities)
|
|
360
|
+
- `designer_a`: senior conservative
|
|
361
|
+
- `designer_b`: balanced, around 40 style
|
|
362
|
+
- `designer_c`: young aggressive, higher risk appetite
|
|
363
|
+
- Stage 2: `reviewer` evaluates with the judgment matrix and picks best candidate
|
|
364
|
+
- Stage 3: selected designer revises based on reviewer feedback (loop until approved)
|
|
365
|
+
- Stage 4: `spec_writer` writes final output in two sections: **Calculation Report** and **Executive Summary**
|
|
366
|
+
|
|
367
|
+
Example `swarm/architecture/tiger_parallel_design.yaml`:
|
|
368
|
+
|
|
369
|
+
```yaml
|
|
370
|
+
version: 1
|
|
371
|
+
name: tiger_parallel_design
|
|
372
|
+
main_orchestrator: tiger
|
|
373
|
+
start_stage: design_parallel
|
|
374
|
+
agents:
|
|
375
|
+
- id: designer_a
|
|
376
|
+
runtime_agent: designer_a
|
|
377
|
+
role: designer
|
|
378
|
+
- id: designer_b
|
|
379
|
+
runtime_agent: designer_b
|
|
380
|
+
role: designer
|
|
381
|
+
- id: designer_c
|
|
382
|
+
runtime_agent: designer_c
|
|
383
|
+
role: designer
|
|
384
|
+
- id: reviewer
|
|
385
|
+
runtime_agent: senior_eng
|
|
386
|
+
role: reviewer
|
|
387
|
+
- id: spec_writer
|
|
388
|
+
runtime_agent: spec_writer
|
|
389
|
+
role: spec_writer
|
|
390
|
+
stages:
|
|
391
|
+
- id: design_parallel
|
|
392
|
+
type: parallel
|
|
393
|
+
roles:
|
|
394
|
+
- designer_a
|
|
395
|
+
- designer_b
|
|
396
|
+
- designer_c
|
|
397
|
+
store_as: design_candidates
|
|
398
|
+
next: review_best
|
|
399
|
+
- id: review_best
|
|
400
|
+
type: judge
|
|
401
|
+
role: reviewer
|
|
402
|
+
candidates_from: design_candidates
|
|
403
|
+
selected_role_key: selected_role
|
|
404
|
+
feedback_key: reviewer_feedback
|
|
405
|
+
calculation_report_key: best_calculation_report
|
|
406
|
+
pass_next: final_spec
|
|
407
|
+
fail_next: revise_selected
|
|
408
|
+
- id: revise_selected
|
|
409
|
+
type: revise
|
|
410
|
+
role_from_context: selected_role
|
|
411
|
+
feedback_from_context: reviewer_feedback
|
|
412
|
+
candidates_from: design_candidates
|
|
413
|
+
update_context_keys_from_revised:
|
|
414
|
+
- best_calculation_report
|
|
415
|
+
next: review_best
|
|
416
|
+
- id: final_spec
|
|
417
|
+
type: final
|
|
418
|
+
role: spec_writer
|
|
419
|
+
source_from_context: best_calculation_report
|
|
420
|
+
output_sections:
|
|
421
|
+
- Calculation Report
|
|
422
|
+
- Executive Summary
|
|
423
|
+
output_notes: Include formulas, assumptions, step-by-step calculations, final values, and concise recommendations.
|
|
424
|
+
next: tiger_done
|
|
425
|
+
judgment_matrix:
|
|
426
|
+
criteria:
|
|
427
|
+
- name: objective_fit
|
|
428
|
+
weight: 0.35
|
|
429
|
+
description: How well the design satisfies the objective.
|
|
430
|
+
- name: feasibility
|
|
431
|
+
weight: 0.25
|
|
432
|
+
description: Delivery realism and technical viability.
|
|
433
|
+
- name: clarity
|
|
434
|
+
weight: 0.2
|
|
435
|
+
description: Readability and implementation clarity.
|
|
436
|
+
- name: risk
|
|
437
|
+
weight: 0.2
|
|
438
|
+
description: Risk exposure and mitigation quality.
|
|
439
|
+
pass_rule: reviewer_approval
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
### Task Style YAML
|
|
443
|
+
|
|
444
|
+
Task style is the selector/policy layer for swarm execution.
|
|
445
|
+
|
|
446
|
+
- `architecture`: which file in `swarm/architecture/` to run
|
|
447
|
+
- `flow`: flow label for task routing mode
|
|
448
|
+
- `objective_prefix`: text prepended to the user objective before processing
|
|
449
|
+
|
|
450
|
+
Default file:
|
|
451
|
+
|
|
452
|
+
```text
|
|
453
|
+
tasks/styles/default.yaml
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Example:
|
|
457
|
+
|
|
458
|
+
```yaml
|
|
459
|
+
version: 1
|
|
460
|
+
name: default
|
|
461
|
+
architecture: tiger_parallel_design.yaml
|
|
462
|
+
flow: architecture
|
|
463
|
+
objective_prefix: "Objective:"
|
|
464
|
+
```
|
|
465
|
+
|
|
210
466
|
---
|
|
211
467
|
|
|
212
468
|
## 🧠 Memory & Context
|
|
213
469
|
|
|
214
470
|
### Context Files
|
|
215
471
|
|
|
216
|
-
Loaded on every turn from `~/.tiger/data
|
|
472
|
+
Loaded on every turn from `DATA_DIR` (default: `~/.tiger/data/`):
|
|
217
473
|
|
|
218
474
|
| File | Purpose |
|
|
219
475
|
|------|---------|
|
|
@@ -222,6 +478,8 @@ Loaded on every turn from `~/.tiger/data/`:
|
|
|
222
478
|
| `human2.md` | Running update log written after every conversation turn |
|
|
223
479
|
| `ownskill.md` | Known skills, workflows, and lessons learned |
|
|
224
480
|
|
|
481
|
+
> **v0.2.5 compatibility note:** If root-level legacy files already exist (for example `./soul.md`, `./ownskill.md`), Tiger mirrors updates to those files automatically. The canonical source remains `DATA_DIR`.
|
|
482
|
+
|
|
225
483
|
### Auto-Refresh Cycles
|
|
226
484
|
|
|
227
485
|
Tiger periodically regenerates these files using the LLM. All durations are configurable in `.env` (minimum 1 hour).
|
|
@@ -335,6 +593,8 @@ rm .env.secrets
|
|
|
335
593
|
| `403` quota error | Daily quota exhausted — auto-switches; raise `*_TOKEN_LIMIT` |
|
|
336
594
|
| `429` rate limit | Auto-switches to next provider in `PROVIDER_ORDER` |
|
|
337
595
|
| Z.ai auth fails | Key must be `id.secret` format (from Zhipu/BigModel console) |
|
|
596
|
+
| Telegram bot runs but does not respond | Ensure only one polling instance is running for the same bot token (stop old/global service copies) |
|
|
597
|
+
| `soul.md` / `ownskill.md` look stale | Check `DATA_DIR` first (default `~/.tiger/data`). In v0.2.5+, existing root legacy copies are mirrored automatically |
|
|
338
598
|
| Shell tool disabled | Set `ALLOW_SHELL=true` in `~/.tiger/.env` |
|
|
339
599
|
| Stuck processes | `pkill -f tiger-agent` then restart |
|
|
340
600
|
| Reset token counters | Delete `~/.tiger/db/token_usage.json` and restart |
|
package/package.json
CHANGED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
function getLegacyRootMirrorPath(filePath) {
|
|
5
|
+
const canonical = path.resolve(filePath);
|
|
6
|
+
const candidate = path.resolve(process.cwd(), path.basename(canonical));
|
|
7
|
+
|
|
8
|
+
if (candidate === canonical) return null;
|
|
9
|
+
if (!fs.existsSync(candidate)) return null;
|
|
10
|
+
|
|
11
|
+
return candidate;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function syncLegacyRootMirror(filePath) {
|
|
15
|
+
const canonical = path.resolve(filePath);
|
|
16
|
+
const legacy = getLegacyRootMirrorPath(canonical);
|
|
17
|
+
if (!legacy) return;
|
|
18
|
+
|
|
19
|
+
const content = fs.readFileSync(canonical, 'utf8');
|
|
20
|
+
fs.writeFileSync(legacy, content, 'utf8');
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function writeContextFile(filePath, content) {
|
|
24
|
+
const canonical = path.resolve(filePath);
|
|
25
|
+
fs.writeFileSync(canonical, content, 'utf8');
|
|
26
|
+
syncLegacyRootMirror(canonical);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function appendContextFile(filePath, content) {
|
|
30
|
+
const canonical = path.resolve(filePath);
|
|
31
|
+
fs.appendFileSync(canonical, content, 'utf8');
|
|
32
|
+
syncLegacyRootMirror(canonical);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
module.exports = {
|
|
36
|
+
writeContextFile,
|
|
37
|
+
appendContextFile,
|
|
38
|
+
syncLegacyRootMirror
|
|
39
|
+
};
|
|
@@ -2,6 +2,7 @@ const fs = require('fs');
|
|
|
2
2
|
const path = require('path');
|
|
3
3
|
const { dataDir } = require('../config');
|
|
4
4
|
const { ensureDir } = require('../utils');
|
|
5
|
+
const { writeContextFile, syncLegacyRootMirror } = require('./contextFileMirrors');
|
|
5
6
|
|
|
6
7
|
const files = ['soul.md', 'human.md', 'human2.md', 'ownskill.md'];
|
|
7
8
|
|
|
@@ -10,8 +11,10 @@ function ensureContextFiles() {
|
|
|
10
11
|
for (const name of files) {
|
|
11
12
|
const full = path.join(dataDir, name);
|
|
12
13
|
if (!fs.existsSync(full)) {
|
|
13
|
-
|
|
14
|
+
writeContextFile(full, `# ${name.replace('.md', '')}\n\n`);
|
|
15
|
+
continue;
|
|
14
16
|
}
|
|
17
|
+
syncLegacyRootMirror(full);
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
20
|
|
package/src/agent/mainAgent.js
CHANGED
|
@@ -12,6 +12,7 @@ const {
|
|
|
12
12
|
memoryIngestMinChars
|
|
13
13
|
} = require('../config');
|
|
14
14
|
const { loadContextFiles } = require('./contextFiles');
|
|
15
|
+
const { writeContextFile, appendContextFile } = require('./contextFileMirrors');
|
|
15
16
|
const { tools, callTool } = require('./toolbox');
|
|
16
17
|
const {
|
|
17
18
|
ensureConversation,
|
|
@@ -98,7 +99,7 @@ async function maybeUpdateHumanFile(userText, assistantText) {
|
|
|
98
99
|
if (!append) return;
|
|
99
100
|
|
|
100
101
|
const block = `\n## Update ${new Date().toISOString()}\n${append}\n`;
|
|
101
|
-
|
|
102
|
+
appendContextFile(path.resolve(human2.full), block);
|
|
102
103
|
}
|
|
103
104
|
|
|
104
105
|
function buildSystemPrompt(contextText, memoriesText) {
|
|
@@ -173,7 +174,7 @@ async function maybeUpdateOwnSkillSummary(conversationIdValue) {
|
|
|
173
174
|
|
|
174
175
|
const next = String(message.content || '').trim();
|
|
175
176
|
if (!next) return;
|
|
176
|
-
|
|
177
|
+
writeContextFile(path.resolve(ownSkillPath), `${next}\n`);
|
|
177
178
|
setMeta(OWNSKILL_META_KEY, Date.now());
|
|
178
179
|
}
|
|
179
180
|
|
|
@@ -209,7 +210,7 @@ async function maybeUpdateSoulSummary(conversationIdValue) {
|
|
|
209
210
|
|
|
210
211
|
const next = String(message.content || '').trim();
|
|
211
212
|
if (!next) return;
|
|
212
|
-
|
|
213
|
+
writeContextFile(path.resolve(soulPath), `${next}\n`);
|
|
213
214
|
setMeta(SOUL_META_KEY, Date.now());
|
|
214
215
|
}
|
|
215
216
|
|
|
@@ -3,6 +3,7 @@ const path = require('path');
|
|
|
3
3
|
const { chatCompletion, embedText } = require('../llmClient');
|
|
4
4
|
const { dataDir, embeddingsEnabled, reflectionUpdateHours } = require('../config');
|
|
5
5
|
const { addMemory, getMeta, setMeta, getMessagesSince, getRecentMessagesAll } = require('./db');
|
|
6
|
+
const { writeContextFile } = require('./contextFileMirrors');
|
|
6
7
|
|
|
7
8
|
const REFLECTION_META_KEY = 'memory_reflection_last_run_ts';
|
|
8
9
|
const MAX_MESSAGE_SCAN = 600;
|
|
@@ -67,7 +68,7 @@ function appendTimestampedBullets(filePath, heading, bullets, stamp) {
|
|
|
67
68
|
const withHeading = ensureHeading(existing, heading);
|
|
68
69
|
const lines = bullets.map((line) => `- [${stamp}] ${line}`).join('\n');
|
|
69
70
|
const next = `${withHeading.trimEnd()}\n${lines}\n`;
|
|
70
|
-
|
|
71
|
+
writeContextFile(full, next);
|
|
71
72
|
}
|
|
72
73
|
|
|
73
74
|
function appendHuman2Update(filePath, payload, stampIso) {
|
|
@@ -80,7 +81,7 @@ function appendHuman2Update(filePath, payload, stampIso) {
|
|
|
80
81
|
for (const w of payload.successfulWorkflows) lines.push(`- Workflow: ${w}`);
|
|
81
82
|
if (!lines.length) return;
|
|
82
83
|
const block = `\n## Update ${stampIso}\n${lines.join('\n')}\n`;
|
|
83
|
-
|
|
84
|
+
writeContextFile(full, `${existing.trimEnd()}${block}`);
|
|
84
85
|
}
|
|
85
86
|
|
|
86
87
|
async function generateReflection(rows, sinceIso, untilIso) {
|
package/src/agent/skills.js
CHANGED
|
@@ -135,7 +135,7 @@ async function clawhubInstall(args = {}) {
|
|
|
135
135
|
if (force) argv.push('--force');
|
|
136
136
|
|
|
137
137
|
const res = await runClawhub(argv, {
|
|
138
|
-
timeout: Number(args.timeout_ms ||
|
|
138
|
+
timeout: Number(args.timeout_ms || process.env.SWARM_AGENT_TIMEOUT_MS || 720000),
|
|
139
139
|
maxBuffer: 1024 * 1024
|
|
140
140
|
});
|
|
141
141
|
if (res.ok) {
|
package/src/apiProviders.js
CHANGED
|
@@ -134,7 +134,7 @@ function buildProviders(env) {
|
|
|
134
134
|
embedPath: '/embeddings',
|
|
135
135
|
formatRequest: standardFormat,
|
|
136
136
|
parseResponse: standardParse,
|
|
137
|
-
timeout: Number(env.KIMI_TIMEOUT_MS ||
|
|
137
|
+
timeout: Number(env.KIMI_TIMEOUT_MS || 180000)
|
|
138
138
|
},
|
|
139
139
|
|
|
140
140
|
moonshot: {
|
|
@@ -150,7 +150,7 @@ function buildProviders(env) {
|
|
|
150
150
|
embedPath: '/embeddings',
|
|
151
151
|
formatRequest: standardFormat,
|
|
152
152
|
parseResponse: standardParse,
|
|
153
|
-
timeout: Number(env.KIMI_TIMEOUT_MS ||
|
|
153
|
+
timeout: Number(env.KIMI_TIMEOUT_MS || 180000)
|
|
154
154
|
},
|
|
155
155
|
|
|
156
156
|
zai: {
|
|
@@ -171,7 +171,7 @@ function buildProviders(env) {
|
|
|
171
171
|
embedPath: '/embeddings',
|
|
172
172
|
formatRequest: standardFormat,
|
|
173
173
|
parseResponse: standardParse,
|
|
174
|
-
timeout: Number(env.ZAI_TIMEOUT_MS ||
|
|
174
|
+
timeout: Number(env.ZAI_TIMEOUT_MS || 180000)
|
|
175
175
|
},
|
|
176
176
|
|
|
177
177
|
minimax: {
|
|
@@ -187,7 +187,7 @@ function buildProviders(env) {
|
|
|
187
187
|
embedPath: '/embeddings',
|
|
188
188
|
formatRequest: standardFormat,
|
|
189
189
|
parseResponse: standardParse,
|
|
190
|
-
timeout: Number(env.MINIMAX_TIMEOUT_MS ||
|
|
190
|
+
timeout: Number(env.MINIMAX_TIMEOUT_MS || 180000)
|
|
191
191
|
},
|
|
192
192
|
|
|
193
193
|
claude: {
|
|
@@ -203,16 +203,15 @@ function buildProviders(env) {
|
|
|
203
203
|
embedPath: null, // Claude does not expose an embeddings endpoint
|
|
204
204
|
formatRequest: claudeFormat,
|
|
205
205
|
parseResponse: claudeParse,
|
|
206
|
-
timeout: Number(env.CLAUDE_TIMEOUT_MS ||
|
|
206
|
+
timeout: Number(env.CLAUDE_TIMEOUT_MS || 180000)
|
|
207
207
|
}
|
|
208
208
|
};
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
//
|
|
212
|
-
|
|
211
|
+
// Always rebuild from current process.env so runtime .env changes take effect
|
|
212
|
+
// (fixes stale timeout after PM2 restart or .env update)
|
|
213
213
|
function getProviders() {
|
|
214
|
-
|
|
215
|
-
return _providers;
|
|
214
|
+
return buildProviders(process.env);
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
function getProvider(id) {
|