Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Turns your Bots into one recursive tree that splits a request into parts, sends

*Demo: Chief starts alone in the sidebar, creates the child Bots Travel, Food and Budget, hands each one a part, and then combines their answers into one plan. Some waiting is sped up.* [Watch the full video (MP4)](docs/images/demo-tree.mp4)

- **One root.** The tree's root is the Main Bot (Chief); no new bot is created for it. A separate `Root` bot is created only if the team has Bots but no Main Bot. Existing local Bots join under the root as its children, up to `maxChildren`.
- **One root.** The tree's root is the Main Bot (Chief); no new bot is created for it. A separate `Root` bot is created only if the team has Bots but no Main Bot. Every other local Bot joins the tree, including one made with `create_bot` or the Bot list, under the same limits as `create_child_bot`. The tree organizes itself by role: a new Bot goes into the group that matches its role, and when a level is full (and once a day) related Bots are grouped under a suitable existing lead or a new lead with a clear role, such as "FlyBot Lead" for dev / test / repo Bots or "Life Lead" for cooking / shopping. Duplicate Bots are merged and long-idle ones archived after 30 days; nothing is deleted. Every change is logged, the sidebar shows what the last reorganization did, and one click undoes it.
- **Children on demand.** Any tree Bot (not only the Main/root) calls `create_child_bot(name, role_description)` to make a child directly under *itself*; the tool takes no parent argument. Calls are handled one at a time per parent, so parallel calls never go over the limits or create two siblings with the same name. The rules:
- names are 1–40 characters, and duplicate sibling names are rejected (case and spaces ignored);
- depth is at most 5 (the root counts as 1), with at most 8 children per Bot (set in `limits.json` or the plugin config);
Expand All @@ -49,10 +49,10 @@ Turns your Bots into one recursive tree that splits a request into parts, sends
- the root may also message any local Bot;
- local Bots outside the tree may message only the root;
- `stopped` and `report` notices are never blocked, so Chief can always stop any Bot.
- **Reparenting.** When a Bot is deleted, its children move up to its parent. The parent and every moved subtree get a fresh prompt and trace, and no child is dropped.
- **Reparenting.** When a Bot is deleted, its children move up to its parent. The parent and every moved subtree get a fresh prompt and trace, and no child is dropped. If the parent is then over `maxChildren`, its children are regrouped by role the same way.
- **Trace line.** When a tree Bot answers its *parent*, it starts the answer with its path, e.g. `Chief → Work → Dev`. Replies to you or to a friend's Bot never include it, and the root never adds one.
- **Your prompts are kept.** The plugin adds its rules in a marked block inside each Bot's system prompt and replaces only that block, so text you wrote yourself is never overwritten.
- **Sidebar.** The Bot list is drawn as one expandable tree with Chief on top. Bots outside the tree are shown directly under Chief.
- **Sidebar.** The Bot list is drawn as one expandable tree with Chief on top. Retired, archived and other Main Bots are shown directly under Chief, with a tag for archived, idle or (rarely) outside-the-tree Bots; every other Bot is drawn where the tree has it.

Install (needs the core, `path:/core`):

Expand Down
6 changes: 3 additions & 3 deletions README.zh.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ FlyBot 是在固定版本的 [DS Bot](https://github.com/Fei2411/DeepSeek-Bot)

*演示:侧栏里一开始只有 Chief;它建出子 Bot Travel、Food、Budget,各分一块,再把答案汇总成一份行程。等待的部分做了加速。* [观看完整视频(MP4)](docs/images/demo-tree.mp4)

- **一个根。** 树的根是主 Bot(Chief),不会再新建一个根。只有团队里有 Bot、却没有主 Bot 时,才会单独建一个 `Root`。已有的本地 Bot 会挂到根下面作子节点,数量不超过 `maxChildren`。
- **一个根。** 树的根是主 Bot(Chief),不会再新建一个根。只有团队里有 Bot、却没有主 Bot 时,才会单独建一个 `Root`。其他本地 Bot(包括用 `create_bot` 或 Bot 列表建的)都会进树,遵守和 `create_child_bot` 一样的限制。树会按角色自我整理:新 Bot 进入角色匹配的分组;某一层满了时(以及每天一次),角色相近的 Bot 归到一个合适的现有负责人下,或新建一个职责明确的负责人(例如开发 / 测试 / 仓库维护归到 "FlyBot Lead",做饭 / 购物归到 "Life Lead")。重复的 Bot 会合并,长期闲置的 Bot 30 天后归档;从不删除。每次改动都记日志,侧栏会显示上一次整理做了什么,一键即可撤销。
- **按需生子。** 树中的任意 Bot(不只是主 Bot / 根)调用 `create_child_bot(name, role_description)`,在**自己**下面直接建子 Bot;工具没有 parent 参数。同一父节点的调用串行处理,避免超限或重名。规则:
- 名称 1–40 个字符;同级重名会被拒绝(忽略大小写和空格);
- 深度最多 5(根算第 1 层),每个 Bot 最多 8 个子节点(见 `limits.json` 或插件配置);
Expand All @@ -44,10 +44,10 @@ FlyBot 是在固定版本的 [DS Bot](https://github.com/Fei2411/DeepSeek-Bot)
- 根还可以给任意本地 Bot 发消息;
- 树外的本地 Bot 只能给根发消息;
- `stopped` 与 `report` 通知永不拦截,Chief 总能叫停任意 Bot。
- **换父。** 删除某个 Bot 时,其子节点上移到它的父节点;父节点与整棵子树会刷新提示词与路径,子节点不会丢失。
- **换父。** 删除某个 Bot 时,其子节点上移到它的父节点;父节点与整棵子树会刷新提示词与路径,子节点不会丢失。如果父节点因此超过 `maxChildren`,其子节点按同样的角色规则重新分组。
- **路径行。** 树中 Bot **向父节点**汇报时,答案以路径开头,例如 `Chief → Work → Dev`。回给你或好友 Bot 时不加路径;根也不会加。
- **保留你的提示词。** 插件把规则写在系统提示词里的标记块中,只替换该块,不会覆盖你自己写的内容。
- **侧栏。** Bot 列表画成可展开的树,Chief 在顶上;树外的 Bot 直接挂在 Chief 下。
- **侧栏。** Bot 列表画成可展开的树,Chief 在顶上;已退役、已归档的 Bot 和其他主 Bot 直接挂在 Chief 下,归档、闲置或(少见的)树外 Bot 带有标签;其余 Bot 都画在树里它所在的位置。

安装(需要先装核心 `path:/core`):

Expand Down
1 change: 1 addition & 0 deletions changelog.d/446-tree-self-organize.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Bots made outside the tree (Chief's `create_bot`, the Bot list) now always join the tree under the same `maxChildren` and `maxDepth` limits as `create_child_bot`, instead of staying outside while the sidebar showed them under Chief. The tree organizes itself by role: a new Bot goes into the group that matches its role, and when a level is full, and once a day, related Bots are grouped under a suitable existing lead or a new lead with a clear role (for example "FlyBot Lead" or "Life Lead"); it never puts a Bot under an unrelated one. The daily pass also merges duplicate Bots and marks long-idle ones idle, archiving them after 30 days; nothing is deleted. Every change is logged, the sidebar shows what the last reorganization did with one-click Undo, and Chief knows about it ([#446](https://github.com/ThinkFlowLab/FlyBot/issues/446)).
19 changes: 18 additions & 1 deletion docs/subsystems/tree.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ Everything in `plugins/tree/` (entry `plugins/tree/index.js` and any helpers).
| File | Role |
| --- | --- |
| `plugins/tree/index.js` | Plugin entry. |
| `plugins/tree/src/organize.js` | Self-organization (#446): placement by role, role groups and leads, repair, daily tidy (merge, idle, archive), journal and undo. |
| `plugins/tree/src/roles.js` | Role profiles and similarity (name, role label, description, own prompt, recent tools; deterministic, `classify` hook). |

## Entry points

Expand All @@ -38,8 +40,23 @@ Everything in `plugins/tree/` (entry `plugins/tree/index.js` and any helpers).

- Every tree member (not only the Main/root) may call `create_child_bot`. The parent is always the calling Bot; the tool has no parent argument.
- `maxChildren` and depth limits stay. Parallel creates are serialized per parent.
- `maxChildren` and `maxDepth` apply to **every** create path while the tree plugin is loaded (#446). A Bot made without tree fields (core `create_bot`, the Bot list) is placed by role by `src/organize.js` on `bot.created`: inside the create call when it fits a level or an existing lead, right after when a new lead has to be created first (it is marked `organizing` until then). No parent goes over `maxChildren` at any moment. `create_child_bot` keeps its contract (directly under the caller, `limit reached` when full).
- A newly created child starts with no person-grant (`bot.hasAnyGrant` false, even when the parent is granted). Sharing with another person still needs an independent per-Bot grant (default deny). Tree never copies grants and never publishes.

### Self-organization (#446, owner decision 2026-10-19 21:27)

The tree organizes itself by role instead of leaving Bots outside it or a parent over the limit. Allocation up front (reuse before create, `create_child_bot(parent?)`) is [#447](https://github.com/ThinkFlowLab/FlyBot/issues/447), which builds on these primitives.

- **Role profile** (`src/roles.js`, deterministic): name words (weighted most), the ds-bot role label, the tree role (description), the Bot's own prompt text (not the tree block) and the tools it used recently (`activity.tools`, from the `tool.start` feed; common tools such as `message_bot` ignored). They give group keys, most specific first: `project:<word>` (a name word that is not a domain word, e.g. "flybot"), `domain:<id>` (dev, life, writing, research, finance, design, business, learning; English stems and Chinese terms), `word:<w>` (a shared role word) and `area:<work|life|other>` (labels Work / Personal / General). The plugin has no model call (the codebase has no pattern for a plugin to call a Bot's model); `config.classify(profile)` may return `{ domain, project }` to override it.
- **Placement** of a Bot outside the tree: its namesake, else the tree Bot that leads a group it belongs to (most specific key first, then the shallower lead; an area only through a lead made for it, e.g. "Work Lead"), else the root. At the first of those with room it is placed. A full level is **regrouped**: the most specific group of two or more children (the newcomer counted) moves under a suitable existing member, or under a new lead. Inside a full lead of its own group with no finer group, the member closest to its role takes it (all members share the group). There is **no "least-loaded child" fallback**: a Bot that fits no group while every level it matches is full stays outside, a warning names it and the sidebar tags it "outside the tree"; the next attempt (any `bot.created`, startup) tries again.
- **Leads.** A suitable existing lead is a member already marked as that group's lead, already coordinating that group (it has children and the key, project and domain only), or named for it ("Life", "FlyBot Lead") or as a lead ("Kitchen Manager", 负责人). It gets `lead { key, label }`. Only when none fits a new lead is created with a clear role (`<Label> Lead`, role "Lead of the <Label> group: coordinates …"); its members move under it before it joins the level. A lead's own group key, and broad areas below any lead, are ignored inside it, so there is no second "Dev Lead" under "Dev Lead".
- **Repair**: a parent over `maxChildren` (after a deletion re-attached a deleted Bot's children) is regrouped the same way, at once when the lead exists, else in the queue.
- **Daily tidy** (checked hourly, runs once a day; the first check after install only records the time; `dailyTidy: false` turns it off): (1) leaf Bots with no activity for `tidy.idleDays` (14) get `idle` (any turn or tool call clears it) and are **archived** after `tidy.archiveIdleDays` (30) more days; Bots with children, granted Bots and the root are never idle; (2) duplicates: two Bots with essentially the same role (same name once generic words are dropped and no conflicting description, or near-identical descriptions in one domain), both at least `tidy.mergeGraceDays` (1) in the tree, are **merged**: the newer one's children move to the kept Bot, which lists it in `mergedFrom` and is told in its prompt; the old one is archived; (3) project and domain groups of three or more (or two with an existing lead) on every level, never a group of a whole level without a lead.
- **Archive, never delete**: an archived Bot leaves the tree (`archived { at, reason, parent, treeRole, into? }`, tree fields and block removed) but keeps its chat, memory and grants; the sidebar tags it "archived". Deleting it stays the owner's own click. Moving conversation / memory references into the kept Bot on a merge needs a core API and is a follow-up.
- **Journal and undo**: every move, new lead, lead mark, merge, archive and idle mark of a run is an action in the root's `reorg { runs (last 5), dismissed, dailyAt }` and a `flybot-tree: reorganized (<trigger>): …` log line. The tree view's notice (sidebar section `flybot-tree-reorg`, `reorgNotice: false` hides it) shows the last run with **Undo** and **Dismiss** (`tree/reorg`, `tree/undo`, `tree/dismiss`). Undo reverses the newest run: moves go back where the old parent has room and the Bot was not moved again, archived Bots come back, a lead the run created is archived once empty; what it cannot restore is listed as kept. Restored Bots are pinned for `tidy.pinDays` (14) so the daily tidy leaves them alone.
- **The owner is told afterwards**, no plan card first: the notice in the tree view, and the Main Bot's prompt names the last run (within 7 days, not undone) so Chief can say what moved.
- **No silent pull-up**: freeing a slot moves nobody up; the next new Bot takes it. Activity is metadata only (when, which tool names), never message text.

### Optional Tree section toggle

- The Bot list itself uses the core `.bt-tree-toggle` (see [core-client](core-client.md)). When `sidebarSection: true` brings this plugin's separate Tree section back, `.flybot-tree-toggle` matches that control: 28×28 hit target, 16px inner `.flybot-tree-caret`, hover, focus ring, and rotation of the glyph only. Leaf spacers (`.flybot-tree-dot`) keep the same 28px width. `aria-expanded` and Expand/Collapse `{name}` labels stay on the button.
Expand All @@ -51,7 +68,7 @@ The plugin's discarded `.catch(() => {})` calls carry a one-line reason comment

## Tests

Covered by the plugin's own tests under `plugins/tree/` / core test suite as wired. `#16 Option B` in `test/tree.test.js` (and the matching host test) asserts a non-Main tree Bot can create a child under itself, that `maxChildren`/depth still refuse, and that the child is not auto-granted.
Covered by the plugin's own tests under `plugins/tree/` / core test suite as wired. The `#446` tests in `test/tree.test.js` cover role grouping (Life Lead, FlyBot Lead), existing leads, no unrelated fallback, the cap at every step, the daily tidy (merge, idle, archive), journal, undo and the client notice; `test/host.test.js` runs `create_bot` and the `tree/reorg` / `tree/undo` endpoints on the real host. `#16 Option B` in `test/tree.test.js` (and the matching host test) asserts a non-Main tree Bot can create a child under itself, that `maxChildren`/depth still refuse, and that the child is not auto-granted.

## Common mistakes

Expand Down
Loading
Loading