@buyi1net/pi-toolkit 0.0.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/LICENSE +21 -0
- package/README.md +45 -0
- package/assembler.ts +127 -0
- package/config.ts +201 -0
- package/i18n.ts +693 -0
- package/index.ts +99 -0
- package/menu/items.ts +264 -0
- package/menu/panels.ts +91 -0
- package/menu/settings-list.ts +84 -0
- package/menu/theme.ts +31 -0
- package/menu/toolkit-menu.ts +139 -0
- package/module.ts +156 -0
- package/modules/eyes/chain.ts +173 -0
- package/modules/eyes/config.ts +319 -0
- package/modules/eyes/index.ts +161 -0
- package/modules/eyes/menu.ts +828 -0
- package/modules/eyes/pi-model-backend.ts +245 -0
- package/modules/eyes/resilience.ts +161 -0
- package/modules/eyes/vision-bridge.ts +232 -0
- package/modules/eyes/vision-cache.ts +86 -0
- package/modules/eyes/vision-json.ts +19 -0
- package/modules/eyes/vision-preprocess.ts +192 -0
- package/modules/eyes/vision-probe.ts +21 -0
- package/modules/eyes/vision-prompt.ts +90 -0
- package/modules/eyes/vision-tool.ts +59 -0
- package/modules/eyes/vision-types.ts +33 -0
- package/modules/index.ts +10 -0
- package/modules/subagents/agents/researcher.md +51 -0
- package/modules/subagents/agents/scout.md +40 -0
- package/modules/subagents/agents/worker.md +79 -0
- package/modules/subagents/config.json.example +6 -0
- package/modules/subagents/config.ts +144 -0
- package/modules/subagents/index.ts +91 -0
- package/modules/subagents/menu.ts +388 -0
- package/modules/subagents/src/activity.ts +511 -0
- package/modules/subagents/src/agents.ts +126 -0
- package/modules/subagents/src/command.ts +37 -0
- package/modules/subagents/src/dependencies.ts +246 -0
- package/modules/subagents/src/diagnostics.ts +13 -0
- package/modules/subagents/src/display.ts +94 -0
- package/modules/subagents/src/headless.ts +342 -0
- package/modules/subagents/src/herdr.ts +203 -0
- package/modules/subagents/src/index.ts +2798 -0
- package/modules/subagents/src/inspect-tool.ts +839 -0
- package/modules/subagents/src/launch-config.ts +196 -0
- package/modules/subagents/src/layout-budget.ts +26 -0
- package/modules/subagents/src/list-tool.ts +292 -0
- package/modules/subagents/src/message-tool.ts +808 -0
- package/modules/subagents/src/names.ts +17 -0
- package/modules/subagents/src/pane-layout.ts +49 -0
- package/modules/subagents/src/params.ts +145 -0
- package/modules/subagents/src/renderers.ts +181 -0
- package/modules/subagents/src/result.ts +43 -0
- package/modules/subagents/src/retention.ts +114 -0
- package/modules/subagents/src/route-error.ts +212 -0
- package/modules/subagents/src/routing.ts +235 -0
- package/modules/subagents/src/runtime-registry.ts +159 -0
- package/modules/subagents/src/session.ts +801 -0
- package/modules/subagents/src/status.ts +513 -0
- package/modules/subagents/src/stop-tool.ts +235 -0
- package/modules/subagents/src/subagent-done.ts +590 -0
- package/modules/subagents/src/subagent-tool.ts +1155 -0
- package/modules/subagents/src/surface.ts +355 -0
- package/modules/subagents/src/team-dispatch-tool.ts +219 -0
- package/modules/subagents/src/team.ts +232 -0
- package/modules/subagents/src/tmux.ts +210 -0
- package/modules/subagents/src/tools/safe-bash.ts +72 -0
- package/modules/subagents/src/types.ts +131 -0
- package/modules/tui/adapter/provider-usage.ts +143 -0
- package/modules/tui/config.ts +50 -0
- package/modules/tui/index.ts +120 -0
- package/modules/tui/kernel/pkg/shared/grok-subscription.ts +169 -0
- package/modules/tui/kernel/pkg/shared/official-subscription.ts +237 -0
- package/modules/tui/kernel/pkg/shared/provider-catalog.ts +367 -0
- package/modules/tui/kernel/pkg/shared/provider-contracts.ts +150 -0
- package/modules/tui/kernel/pkg/shared/provider-display.ts +55 -0
- package/modules/tui/kernel/pkg/shared/provider-parsers.ts +171 -0
- package/modules/tui/kernel/pkg/shared/volcengine.ts +191 -0
- package/modules/tui/kernel/pkg/shared/zhipu.ts +149 -0
- package/modules/tui/kernel/pkg/usage-core/index.ts +335 -0
- package/modules/tui/kernel/pkg/usage-core/provider-routes.ts +187 -0
- package/modules/tui/kernel/pkg/usage-node/index.ts +635 -0
- package/modules/tui/kernel/pkg/usage-node/provider-usage.ts +388 -0
- package/modules/tui/kernel/usage-core.ts +2 -0
- package/modules/tui/kernel/usage-node.ts +2 -0
- package/modules/tui/menu.ts +418 -0
- package/modules/tui/plugin/editor.ts +396 -0
- package/modules/tui/plugin/footer.ts +161 -0
- package/modules/tui/plugin/index.ts +30 -0
- package/modules/tui/plugin/lifecycle.ts +637 -0
- package/modules/tui/plugin/package-order.ts +169 -0
- package/modules/tui/plugin/screen-transition.ts +203 -0
- package/modules/tui/plugin/settings-config.ts +297 -0
- package/modules/tui/plugin/status-sources.ts +49 -0
- package/modules/tui/plugin/transition-gate.ts +261 -0
- package/modules/tui/renderer/custom-header.ts +157 -0
- package/modules/tui/renderer/editor.ts +70 -0
- package/modules/tui/renderer/header.ts +72 -0
- package/modules/tui/renderer/icons.ts +149 -0
- package/modules/tui/renderer/pi-installer-logo.ts +194 -0
- package/modules/tui/status/auto-compaction.ts +67 -0
- package/modules/tui/status/project-status.ts +655 -0
- package/modules/tui/status/provider-status.ts +120 -0
- package/modules/tui/status/runtime-status.ts +307 -0
- package/modules/tui/status/session-status.ts +325 -0
- package/modules/tui/status/status-config.ts +95 -0
- package/modules/tui/status/status-segments.ts +263 -0
- package/modules/tui/status/turn-telemetry.ts +466 -0
- package/modules/tui/themes/LICENSE.pi-themes-bundle +21 -0
- package/modules/tui/themes/UPSTREAM.md +7 -0
- package/modules/tui/themes/catppuccin-latte.json +80 -0
- package/modules/tui/themes/catppuccin-mocha.json +79 -0
- package/modules/tui/themes/crimson-noir.json +85 -0
- package/modules/tui/themes/dracula.json +79 -0
- package/modules/tui/themes/everforest-dark.json +85 -0
- package/modules/tui/themes/gruvbox-dark.json +85 -0
- package/modules/tui/themes/gruvbox-light.json +85 -0
- package/modules/tui/themes/matrix.json +85 -0
- package/modules/tui/themes/nord.json +85 -0
- package/modules/tui/themes/one-dark.json +85 -0
- package/modules/tui/themes/rose-pine-dawn.json +85 -0
- package/modules/tui/themes/rose-pine.json +85 -0
- package/modules/tui/themes/solarized-dark.json +85 -0
- package/modules/tui/themes/solarized-light.json +85 -0
- package/modules/tui/themes/tokyo-night-storm.json +79 -0
- package/modules/tui/themes/tokyo-night.json +79 -0
- package/package.json +28 -0
- package/services.ts +38 -0
- package/toolkit.ts +147 -0
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: worker
|
|
3
|
+
description: General-purpose worker — reads, writes, and edits code
|
|
4
|
+
tools: read, write, edit, bash, web_search, web_fetch
|
|
5
|
+
subagent_agents: scout, researcher
|
|
6
|
+
model: zai-coding-cn/glm-5.3-flash
|
|
7
|
+
thinking: max
|
|
8
|
+
system-prompt: append
|
|
9
|
+
auto-exit: true
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
You are a worker agent. You operate in an isolated context — you have no knowledge of any prior conversation. All necessary context will be provided in the task description.
|
|
13
|
+
|
|
14
|
+
You run as an independent autonomous worker (normally in a headless Pi process; the orchestrator may force a visible pane for demonstration) and complete the assigned task. When you are finished, simply write your final summary message and stop — your session ends automatically and your results are returned to the orchestrator. Do not announce that you are finishing; just produce the answer. If you get stuck, hit ambiguous requirements, or need a decision only the orchestrator can make, call `ask_question` with a single freeform question instead of guessing. Your session stays open while you wait, and the orchestrator's reply arrives as your next message.
|
|
15
|
+
|
|
16
|
+
Guidelines:
|
|
17
|
+
- Read files before editing to understand existing code
|
|
18
|
+
- Make targeted edits, not wholesale rewrites
|
|
19
|
+
- Use `bash` for running commands (tests, builds, installs, etc.)
|
|
20
|
+
- If something fails, diagnose and fix it
|
|
21
|
+
- Your FINAL assistant message should summarize what you did and what changed
|
|
22
|
+
|
|
23
|
+
## Delegation — protecting your context window
|
|
24
|
+
|
|
25
|
+
Your context is finite. Reading large or unfamiliar codebases directly will burn it before you can edit anything. You have a `subagent` tool that spawns disposable child agents whose context is separate from yours — you only receive their summary. Use it.
|
|
26
|
+
|
|
27
|
+
You can dispatch:
|
|
28
|
+
- **scout** — read-only recon (read, grep, find, ls). Returns a structured map of files, line ranges, and key snippets. Cheap (haiku). Use for *exploring unfamiliar territory*.
|
|
29
|
+
- **researcher** — web research (web_search, web_fetch). Returns a sourced brief. Use for *external knowledge* (library docs, error messages, API references).
|
|
30
|
+
|
|
31
|
+
You may only dispatch `scout` and `researcher` — no other agents are available to you.
|
|
32
|
+
|
|
33
|
+
**Always select the agent with the `agent` field**, e.g. `subagent({ agent: "scout", name: "recon", task: "…" })`. The `name` field is only a cosmetic pane label — it does NOT pick the agent. If you put "scout" in `name` and leave `agent` empty, the spawn is rejected (you're restricted to named agents).
|
|
34
|
+
|
|
35
|
+
### When to dispatch a scout vs. read directly
|
|
36
|
+
|
|
37
|
+
Dispatch a scout when:
|
|
38
|
+
- The task brief names a feature/area but not specific files ("fix the auth flow", "add a field to user settings")
|
|
39
|
+
- You'd need to grep + read 5+ files just to orient
|
|
40
|
+
- You only need to know *where* something lives or *what shape* it has, not its full source
|
|
41
|
+
|
|
42
|
+
Read directly when:
|
|
43
|
+
- The brief gives you explicit file paths
|
|
44
|
+
- You already know the file you need to edit
|
|
45
|
+
- You need the exact bytes for an `edit` call (scouts return summaries, not verbatim source — re-read the 1–3 files you actually edit)
|
|
46
|
+
|
|
47
|
+
A good rhythm: **scout to find, read to edit.** One scout dispatch up front often replaces a dozen grep/read calls and pays for itself many times over.
|
|
48
|
+
|
|
49
|
+
### When to dispatch a researcher vs. web_fetch directly
|
|
50
|
+
|
|
51
|
+
Dispatch a researcher when:
|
|
52
|
+
- The question is open-ended ("what's the idiomatic way to X in library Y")
|
|
53
|
+
- You'd need to search + read 3+ pages to triangulate
|
|
54
|
+
- You want sources synthesized, not raw HTML in your context
|
|
55
|
+
|
|
56
|
+
Fetch directly when:
|
|
57
|
+
- You already have the exact URL (a known docs page, a GitHub issue)
|
|
58
|
+
- You need a single specific piece of information from one page
|
|
59
|
+
|
|
60
|
+
### Parallelism
|
|
61
|
+
|
|
62
|
+
If you need two independent investigations (e.g. "map the auth code" AND "look up the library's session API"), emit multiple `subagent` tool calls in the same turn — they run in parallel automatically. Don't serialize independent work. After spawning, the results arrive as steer messages — don't poll or fabricate them.
|
|
63
|
+
|
|
64
|
+
After dispatching subagents you can just say what you're waiting for and stop the turn — your session will **not** close while children are still running. It stays open until every child has reported back, then wakes you with each result. Don't spin in a loop trying to "check" on them.
|
|
65
|
+
|
|
66
|
+
### What a subagent doesn't replace
|
|
67
|
+
|
|
68
|
+
Subagents can't edit files for you. You still do the `edit`/`write` calls yourself, with the focused context the scouts gave you. Treat them as a context-protecting prefetch, not a substitute for thinking.
|
|
69
|
+
|
|
70
|
+
## Output format when done
|
|
71
|
+
|
|
72
|
+
## Changes Made
|
|
73
|
+
- `path/to/file.ts` — what changed and why
|
|
74
|
+
|
|
75
|
+
## Verification
|
|
76
|
+
How you verified the changes work (tests run, build succeeded, etc.)
|
|
77
|
+
|
|
78
|
+
## Notes
|
|
79
|
+
Any caveats, follow-up items, or decisions made.
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
// 子代理模块的配置落点:pi-toolkit.json 的 `modules.subagents` 节。
|
|
2
|
+
//
|
|
3
|
+
// 归一裁决(工单 04):tier 模型路由(`models.fast` / `models.balanced` /
|
|
4
|
+
// `models.deep`)与状态显示开关(`status.enabled`)的菜单读写都落这一节;
|
|
5
|
+
// 原 pi-subagents 包内 config.json 的 status.enabled 只作兜底默认。
|
|
6
|
+
//
|
|
7
|
+
// tier 解析保留覆盖优先级链,共六级(外部显式配置优先,包内文件兜底):
|
|
8
|
+
// 1. env PI_SUBAGENTS_CONFIG
|
|
9
|
+
// 2. 项目 <cwd>/.pi/agent/pi-subagents.json
|
|
10
|
+
// 3. 全局 <agentDir>/pi-subagents.json
|
|
11
|
+
// 4. pi-toolkit.json 的 modules.subagents 节(本文件负责读写)
|
|
12
|
+
// 5. 模块目录 config.json
|
|
13
|
+
// 6. 模块目录 config.json.example
|
|
14
|
+
// 第 4 级只在真的声明了 models 对象时参与(否则让链继续落到包内兜底);
|
|
15
|
+
// 候选链的拼接在 src/routing.ts,本文件只负责本节的读写与校验。
|
|
16
|
+
|
|
17
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
18
|
+
import { getToolkitConfigPath, saveToolkitConfig } from "../../config.ts";
|
|
19
|
+
import {
|
|
20
|
+
MODEL_TIERS,
|
|
21
|
+
normalizeTier,
|
|
22
|
+
parseTierConfig,
|
|
23
|
+
resolveTierForParams,
|
|
24
|
+
loadTierRouteConfig,
|
|
25
|
+
type ModelTier,
|
|
26
|
+
type TierConfigLoadResult,
|
|
27
|
+
} from "./src/routing.ts";
|
|
28
|
+
import { getAgentConfigDir, resolveHostTierSources } from "./src/index.ts";
|
|
29
|
+
|
|
30
|
+
/** 模块 id:同时是配置节名与菜单项 id 前缀 */
|
|
31
|
+
export const SUBAGENTS_MODULE_ID = "subagents";
|
|
32
|
+
|
|
33
|
+
export { MODEL_TIERS, normalizeTier };
|
|
34
|
+
export type { ModelTier, TierConfigLoadResult };
|
|
35
|
+
|
|
36
|
+
export type TierMapping = Partial<Record<ModelTier, string>>;
|
|
37
|
+
|
|
38
|
+
export interface SubagentsSectionView {
|
|
39
|
+
/** 已校验的 tier 映射;非法项被丢弃并记录在 problems 里 */
|
|
40
|
+
readonly tier: TierMapping;
|
|
41
|
+
/** `status.enabled`;未声明时为 undefined(落回包内 config.json 的兜底默认) */
|
|
42
|
+
readonly statusEnabled: boolean | undefined;
|
|
43
|
+
readonly problems: readonly string[];
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const SECTION_LABEL = `modules.${SUBAGENTS_MODULE_ID}`;
|
|
47
|
+
|
|
48
|
+
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
|
49
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 读 `modules.subagents` 节。校验直接复用 src/routing.ts 的 parseTierConfig,
|
|
54
|
+
* 保证菜单里看到的判定与 spawn 时的判定完全一致(同一份严格规则)。
|
|
55
|
+
*/
|
|
56
|
+
export function readSubagentsSection(section: Record<string, unknown>): SubagentsSectionView {
|
|
57
|
+
const problems: string[] = [];
|
|
58
|
+
|
|
59
|
+
const tier: TierMapping = {};
|
|
60
|
+
const rawModels = section.models;
|
|
61
|
+
if (rawModels !== undefined) {
|
|
62
|
+
const parsed = parseTierConfig({ models: rawModels }, SECTION_LABEL);
|
|
63
|
+
if ("error" in parsed) problems.push(parsed.error);
|
|
64
|
+
else Object.assign(tier, parsed.config.models);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
let statusEnabled: boolean | undefined;
|
|
68
|
+
const status = section.status;
|
|
69
|
+
if (status !== undefined) {
|
|
70
|
+
if (!isPlainObject(status)) {
|
|
71
|
+
problems.push(`${SECTION_LABEL}.status must be an object`);
|
|
72
|
+
} else if (status.enabled !== undefined) {
|
|
73
|
+
if (typeof status.enabled === "boolean") statusEnabled = status.enabled;
|
|
74
|
+
else problems.push(`${SECTION_LABEL}.status.enabled must be a boolean`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return { tier, statusEnabled, problems };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* 本节点路径。菜单写盘与错误提示定位共用它——spawn 时的同一级来源也指向这里。
|
|
83
|
+
*/
|
|
84
|
+
export function subagentsSectionPath(agentDir?: string): string {
|
|
85
|
+
return `${getToolkitConfigPath(agentDir ?? getAgentDir())} (${SECTION_LABEL})`;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* 按 spawn 时的同一规则解析生效的 tier 配置(含第 4 级本节点注入),
|
|
90
|
+
* 供菜单展示与缺映射报错使用。
|
|
91
|
+
*/
|
|
92
|
+
export function loadEffectiveTierConfig(options?: {
|
|
93
|
+
readonly cwd?: string;
|
|
94
|
+
readonly agentDir?: string;
|
|
95
|
+
}): TierConfigLoadResult {
|
|
96
|
+
return loadTierRouteConfig({
|
|
97
|
+
cwd: options?.cwd ?? process.cwd(),
|
|
98
|
+
agentConfigDir: options?.agentDir ?? getAgentConfigDir(),
|
|
99
|
+
injected: resolveHostTierSources(),
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 某一档缺映射时的报错文案。走 src/routing.ts 的 resolveTierForParams,
|
|
105
|
+
* 与真正 spawn 时抛出的字符串逐字一致(含"Add models.x to <path>"与
|
|
106
|
+
* "No pi-subagents config was found (looked at …)"两条原文)。
|
|
107
|
+
*/
|
|
108
|
+
export function tierRouteError(tier: ModelTier, load: () => TierConfigLoadResult): string | undefined {
|
|
109
|
+
const resolution = resolveTierForParams({ tier }, load);
|
|
110
|
+
return "error" in resolution ? resolution.error : undefined;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function assertModelValue(tier: ModelTier, model: string, source: string): void {
|
|
114
|
+
const checked = parseTierConfig({ models: { [tier]: model } }, source);
|
|
115
|
+
if ("error" in checked) throw new Error(checked.error);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export interface SubagentsWriteOptions {
|
|
119
|
+
readonly agentDir?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** 写一档 tier 的模型映射到本节点 */
|
|
123
|
+
export async function saveTierModel(
|
|
124
|
+
tier: ModelTier,
|
|
125
|
+
model: string,
|
|
126
|
+
options: SubagentsWriteOptions = {},
|
|
127
|
+
): Promise<void> {
|
|
128
|
+
const path = getToolkitConfigPath(options.agentDir ?? getAgentDir());
|
|
129
|
+
assertModelValue(tier, model, path);
|
|
130
|
+
await saveToolkitConfig(path, {
|
|
131
|
+
modules: { [SUBAGENTS_MODULE_ID]: { models: { [tier]: model } } },
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** 写状态显示开关到本节点 */
|
|
136
|
+
export async function saveStatusEnabled(
|
|
137
|
+
enabled: boolean,
|
|
138
|
+
options: SubagentsWriteOptions = {},
|
|
139
|
+
): Promise<void> {
|
|
140
|
+
const path = getToolkitConfigPath(options.agentDir ?? getAgentDir());
|
|
141
|
+
await saveToolkitConfig(path, {
|
|
142
|
+
modules: { [SUBAGENTS_MODULE_ID]: { status: { enabled } } },
|
|
143
|
+
});
|
|
144
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// 子代理模块:把 pi-subagents 整体装进 pi-toolkit。
|
|
2
|
+
//
|
|
3
|
+
// 迁入原则是搬移优先于重写:`src/` 下是原 pi-subagents 的全部实现(只加了
|
|
4
|
+
// 宿主配置注入点与命令注册开关),`agents/` 是随包代理定义,
|
|
5
|
+
// `config.json.example` 是包内兜底配置。目录形状保持 `src/` 相对两层到包根,
|
|
6
|
+
// 因此 `SUBAGENTS_DIR` / `PACKAGE_ROOT`、`-e` 装载路径、trustedRoots
|
|
7
|
+
// containment、agents 发现路径全部沿用原规则,不需要改算法。
|
|
8
|
+
//
|
|
9
|
+
// 这里只做装配:
|
|
10
|
+
// - 6 个模型侧工具(subagent / subagent_message / subagents_list /
|
|
11
|
+
// subagent_inspect / subagent_stop / team_dispatch)+ 4 个消息渲染器 +
|
|
12
|
+
// 状态 widget + 2 个事件钩子(session_start / session_shutdown)按
|
|
13
|
+
// ModuleDefinition 注册;enabled=false 时装配器根本不调用 register
|
|
14
|
+
// - 旧 `/subagent` 命令不再注册(合并决策 5)
|
|
15
|
+
// - tier 模型路由与状态显示开关读写 pi-toolkit.json 的 `modules.subagents` 节
|
|
16
|
+
// - 服务句柄 `subagents.running`:供其它模块查询子代理运行状态
|
|
17
|
+
|
|
18
|
+
import { getAgentDir } from "@earendil-works/pi-coding-agent";
|
|
19
|
+
import { getToolkitConfigPath } from "../../config.ts";
|
|
20
|
+
import { enabledField, type ModuleContext, type ModuleDefinition } from "../../module.ts";
|
|
21
|
+
import { SUBAGENTS_MODULE_ID } from "./config.ts";
|
|
22
|
+
import { buildSubagentsMenuItems, type SubagentsMenuRuntime } from "./menu.ts";
|
|
23
|
+
import subagentsExtension, {
|
|
24
|
+
listRunningSubagents,
|
|
25
|
+
runtimeRegistryPathForSession,
|
|
26
|
+
type SubagentsHostSection,
|
|
27
|
+
} from "./src/index.ts";
|
|
28
|
+
import { readRuntimeRecords, type RuntimeRecord } from "./src/runtime-registry.ts";
|
|
29
|
+
|
|
30
|
+
export { SUBAGENTS_MODULE_ID } from "./config.ts";
|
|
31
|
+
|
|
32
|
+
/** 服务句柄名(注册表要求全小写) */
|
|
33
|
+
export const SUBAGENTS_SERVICE_NAME = "subagents.running";
|
|
34
|
+
|
|
35
|
+
export interface SubagentsService {
|
|
36
|
+
readonly id: "subagents";
|
|
37
|
+
/** 进程内运行中的子代理数量(与状态 widget 同源,实时) */
|
|
38
|
+
runningCount(): number;
|
|
39
|
+
/** 进程内运行中的子代理名(便于其它模块做哨兵判断) */
|
|
40
|
+
runningNames(): readonly string[];
|
|
41
|
+
/** 会话作用域的持久化运行态登记:沿用 runtime-registry 的既有数据 */
|
|
42
|
+
runtimeRecords(sessionDir: string, sessionId: string): RuntimeRecord[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function registerSubagents(context: ModuleContext, runtime: SubagentsMenuRuntime): void {
|
|
46
|
+
runtime.reload = () => context.reloadConfig();
|
|
47
|
+
|
|
48
|
+
// 宿主注入:本节点就是 pi-toolkit.json 的 `modules.subagents` 节。
|
|
49
|
+
// getConfig() 返回状态中枢解析后的本模块配置(schema 默认值 + 磁盘取值),
|
|
50
|
+
// 非 schema 键原样透传,因此 models / status 直接可用;写盘后由 reloadConfig 刷新。
|
|
51
|
+
subagentsExtension(context.pi, {
|
|
52
|
+
registerCommand: false,
|
|
53
|
+
readHostSection: (): SubagentsHostSection => ({
|
|
54
|
+
source: `${getToolkitConfigPath(getAgentDir())} (modules.${SUBAGENTS_MODULE_ID})`,
|
|
55
|
+
section: context.getConfig(),
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
context.services.register(SUBAGENTS_SERVICE_NAME, {
|
|
60
|
+
id: "subagents",
|
|
61
|
+
runningCount: () => listRunningSubagents().length,
|
|
62
|
+
runningNames: () => listRunningSubagents().map((running) => running.name),
|
|
63
|
+
runtimeRecords: (sessionDir, sessionId) =>
|
|
64
|
+
readRuntimeRecords(runtimeRegistryPathForSession(sessionDir, sessionId)),
|
|
65
|
+
} satisfies SubagentsService);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function createSubagentsModule(): ModuleDefinition {
|
|
69
|
+
// 菜单写盘后要让状态中枢重新读盘,否则 getConfig() 还是旧副本
|
|
70
|
+
const runtime: SubagentsMenuRuntime = { reload: async () => {} };
|
|
71
|
+
|
|
72
|
+
return {
|
|
73
|
+
id: SUBAGENTS_MODULE_ID,
|
|
74
|
+
labelKey: "module.subagents.label",
|
|
75
|
+
descriptionKey: "module.subagents.description",
|
|
76
|
+
group: "subagents",
|
|
77
|
+
// schema 只放总开关;tier 路由与 status 开关是结构化配置(非 schema 键),
|
|
78
|
+
// 由本模块的菜单与配置层读写。
|
|
79
|
+
configSchema: {
|
|
80
|
+
enabled: enabledField("module.subagents.enabled.label", "module.subagents.enabled.description"),
|
|
81
|
+
},
|
|
82
|
+
register(context): void {
|
|
83
|
+
registerSubagents(context, runtime);
|
|
84
|
+
},
|
|
85
|
+
menuItems(context): ReturnType<typeof buildSubagentsMenuItems> {
|
|
86
|
+
return buildSubagentsMenuItems(context, runtime);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const subagentsModule: ModuleDefinition = createSubagentsModule();
|