pi-shadow-mind 0.1.5
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/DESIGN.md +493 -0
- package/README.md +58 -0
- package/dist/config.d.ts +18 -0
- package/dist/config.js +132 -0
- package/dist/config.js.map +1 -0
- package/dist/entity-store.d.ts +22 -0
- package/dist/entity-store.js +71 -0
- package/dist/entity-store.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +8537 -0
- package/dist/index.js.map +7 -0
- package/dist/management-tools.d.ts +4 -0
- package/dist/management-tools.js +130 -0
- package/dist/management-tools.js.map +1 -0
- package/dist/protocol.d.ts +5 -0
- package/dist/protocol.js +34 -0
- package/dist/protocol.js.map +1 -0
- package/dist/random.d.ts +2 -0
- package/dist/random.js +14 -0
- package/dist/random.js.map +1 -0
- package/dist/registry.d.ts +9 -0
- package/dist/registry.js +139 -0
- package/dist/registry.js.map +1 -0
- package/dist/report-batcher.d.ts +15 -0
- package/dist/report-batcher.js +49 -0
- package/dist/report-batcher.js.map +1 -0
- package/dist/runtime.d.ts +36 -0
- package/dist/runtime.js +274 -0
- package/dist/runtime.js.map +1 -0
- package/dist/scheduler.d.ts +10 -0
- package/dist/scheduler.js +46 -0
- package/dist/scheduler.js.map +1 -0
- package/dist/shadow-runner.d.ts +93 -0
- package/dist/shadow-runner.js +251 -0
- package/dist/shadow-runner.js.map +1 -0
- package/dist/shutdown-drain.d.ts +12 -0
- package/dist/shutdown-drain.js +22 -0
- package/dist/shutdown-drain.js.map +1 -0
- package/dist/summaries.d.ts +9 -0
- package/dist/summaries.js +56 -0
- package/dist/summaries.js.map +1 -0
- package/dist/trajectory.d.ts +7 -0
- package/dist/trajectory.js +33 -0
- package/dist/trajectory.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/validation.d.ts +8 -0
- package/dist/validation.js +18 -0
- package/dist/validation.js.map +1 -0
- package/package.json +52 -0
package/DESIGN.md
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Shadow Mind:Pi 并行认知运行时设计
|
|
2
|
+
|
|
3
|
+
## 1. 目标
|
|
4
|
+
|
|
5
|
+
Shadow Mind 是一个运行在 Pi 主 Agent 旁边的通用并行认知运行时。
|
|
6
|
+
|
|
7
|
+
主 Agent 继续正常推理和执行任务;插件以 heartbeat 随机唤醒多个 Shadow Mind,让它们沿各自的职责独立观察或推进任务。Shadow 既可以检查 Main,也可以承担文档维护等并行工作,并在有结果需要同步时向主 Agent 注入消息。
|
|
8
|
+
|
|
9
|
+
第一版要验证的核心假设是:
|
|
10
|
+
|
|
11
|
+
> 不引入复杂的智能调度,仅通过随机唤醒多个具有持久职责的异步 Agent,能否让一个 Pi Session 稳定推进多条相互补充的认知与任务线。
|
|
12
|
+
|
|
13
|
+
纠错、事实核查和约束检查只是典型场景;Shadow 也可以探索替代路线、维护文档或承担其他长期职责。“多核”和“章鱼”可用于解释和后续产品表达,但不是运行时的技术定义。
|
|
14
|
+
|
|
15
|
+
## 2. 核心结构
|
|
16
|
+
|
|
17
|
+
```text
|
|
18
|
+
Main Agent
|
|
19
|
+
│
|
|
20
|
+
├── model call / message / tool events
|
|
21
|
+
│
|
|
22
|
+
▼
|
|
23
|
+
Trajectory Builder
|
|
24
|
+
│ 生成净化后的行为轨迹
|
|
25
|
+
▼
|
|
26
|
+
Heartbeat Scheduler
|
|
27
|
+
│ 按 heartbeat_probability 随机触发
|
|
28
|
+
│ 每个 Shadow 按自己的概率独立参与
|
|
29
|
+
│ 并行数量受 max_parallel_shadows 限制
|
|
30
|
+
▼
|
|
31
|
+
Shadow Runtime × N
|
|
32
|
+
│ 独立推理、独立使用工具
|
|
33
|
+
│
|
|
34
|
+
└── 有重要发现 ──→ steer / follow-up ──→ Main Agent
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Shadow 的持久化定义与运行实例相互分离:
|
|
38
|
+
|
|
39
|
+
- Shadow Mind 的定义是用户可阅读、可编辑的 Markdown 实体。
|
|
40
|
+
- 第一版只维护全局 Shadow registry,不提供项目级 Shadow。
|
|
41
|
+
- 每次激活产生全新的临时 AgentSession。
|
|
42
|
+
- 插件负责发现实体、筛选、随机调度、构造上下文和回收结果。
|
|
43
|
+
|
|
44
|
+
Shadow 的 Markdown 定义持久存在,但运行实例不保留长期记忆。每次激活只接收当时的净化轨迹和自身定义;运行结束或超时后立即销毁,不继承上一次激活的消息历史。
|
|
45
|
+
|
|
46
|
+
每个实例同时快照激活时 Main 的当前工作目录,并在整个临时 AgentSession 中保持不变。Shadow 的工具都以该目录为 `cwd`;Main 后续切换目录只影响新激活的 Shadow。
|
|
47
|
+
|
|
48
|
+
## 3. Shadow Mind 实体
|
|
49
|
+
|
|
50
|
+
每个 Shadow Mind 使用一个 Markdown 文件描述。用户可以创建和调整它,主 Agent 也可以通过插件工具创建和调整它。
|
|
51
|
+
|
|
52
|
+
第一版统一从全局目录加载定义:
|
|
53
|
+
|
|
54
|
+
```text
|
|
55
|
+
~/.pi/agent/shadow-minds/
|
|
56
|
+
├── config.json
|
|
57
|
+
├── grounded-reviewer.md
|
|
58
|
+
├── requirement-keeper.md
|
|
59
|
+
└── logs/
|
|
60
|
+
└── grounded-reviewer/
|
|
61
|
+
└── <debug session logs>
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
该目录属于用户数据,不放入插件安装目录,也不随当前项目切换。插件级配置保存在 `config.json`;registry 只扫描目录顶层的 `.md` 文件,不读取 `config.json`,也不递归读取 `logs/`。
|
|
65
|
+
|
|
66
|
+
`config.json` 保存默认 Shadow 模型、`default_thinking_level`、`heartbeat_probability`、`max_parallel_shadows`、`default_shadow_timeout_seconds` 和 `result_batch_window_ms` 等全局调度配置。`default_shadow_model` 省略时,插件使用激活时的当前 Main 模型;用户也可以配置一个固定默认模型。`default_thinking_level` 的内置默认值为 `low`。
|
|
67
|
+
|
|
68
|
+
每次 Main `turn_end` 进行 heartbeat 判断前,插件检查并重新加载发生变化的 `config.json`。新配置只影响后续调度和新建实例;已经运行的 Shadow 继续使用启动时取得的配置快照。
|
|
69
|
+
|
|
70
|
+
`config.json` 使用 last-known-good 策略。解析失败或字段无效时,插件继续使用最后一次有效配置,在界面及 `/shadow status` 中持续显示错误和当前实际生效值。只有首次加载就不存在有效配置时才使用内置默认值;插件不会自动用默认内容覆盖用户的无效文件。
|
|
71
|
+
|
|
72
|
+
首次启动时,插件创建该目录及带默认值的 `config.json`,但不自动创建任何 Shadow Markdown。registry 为空时只显示简短引导,用户可以手动创建定义或让 AI 提议创建;所有实际参与调度的 Shadow 都必须是目录中可见的实体。
|
|
73
|
+
|
|
74
|
+
示例:
|
|
75
|
+
|
|
76
|
+
```md
|
|
77
|
+
---
|
|
78
|
+
id: grounded-reviewer
|
|
79
|
+
name: 项目事实检查者
|
|
80
|
+
enabled: true
|
|
81
|
+
debug: false
|
|
82
|
+
activation_probability: 0.6
|
|
83
|
+
run_with_model: openai/gpt-5-mini
|
|
84
|
+
thinking_level: low
|
|
85
|
+
timeout_seconds: 120
|
|
86
|
+
tools:
|
|
87
|
+
- read
|
|
88
|
+
- search
|
|
89
|
+
active_for_models:
|
|
90
|
+
- anthropic/claude-sonnet-4
|
|
91
|
+
- anthropic/claude-opus-4.1
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
检查主 Agent 在分析和编写方案时,是否把未经项目证据支持的推测描述成事实。
|
|
95
|
+
|
|
96
|
+
重点关注不存在的模块、接口、现有能力和技术前提。需要时使用自己的工具独立核实;没有值得介入的问题时保持沉默。
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
第一版 frontmatter 包含以下运行字段:
|
|
100
|
+
|
|
101
|
+
| 字段 | 含义 |
|
|
102
|
+
| --- | --- |
|
|
103
|
+
| `id` | Shadow 的稳定标识;省略时使用 Markdown 文件名(不含扩展名) |
|
|
104
|
+
| `name` | 展示名称;省略时使用最终解析出的 `id` |
|
|
105
|
+
| `enabled` | 是否参与调度;默认 `true` |
|
|
106
|
+
| `debug` | 是否保存完整 Shadow Session 日志;默认 `false` |
|
|
107
|
+
| `activation_probability` | 每次 heartbeat 时独立激活的概率,范围为 `0` 到 `1`;默认 `0.3` |
|
|
108
|
+
| `active_for_models` | 适用于哪些 Main 模型;`"*"` 表示全部模型,省略时默认 `["*"]` |
|
|
109
|
+
| `run_with_model` | Shadow 自己使用的模型;省略时使用插件默认模型 |
|
|
110
|
+
| `thinking_level` | Shadow 使用的 thinking level;省略时使用插件默认值,再回退到 Main 会话当前生效等级 |
|
|
111
|
+
| `timeout_seconds` | Shadow 单次运行超时;省略时使用插件默认超时 |
|
|
112
|
+
| `tools` | 在 Pi SDK `readOnlyTools` 之上追加的工具白名单;默认 `[]` |
|
|
113
|
+
|
|
114
|
+
`name` 只用于 `shadow-report` 和状态界面展示,不参与身份判断;省略时回退到最终解析出的 `id`。Markdown 正文就是 Shadow 的认知定义、长期职责和行为要求。
|
|
115
|
+
|
|
116
|
+
`active_for_models` 绑定的是被观察的 Main 模型,`run_with_model` 则指定 Shadow 自己运行时使用的模型。匹配前由 Pi 将 Main 的别名或简写解析为完整 `provider/model-id`;第一版只支持该完整 ID 和精确值 `"*"`,不引入其他通配、正则、标签或复杂条件。模型选择优先级为:Shadow 的 `run_with_model` → 插件的 `default_shadow_model` → 激活时的当前 Main 模型。
|
|
117
|
+
|
|
118
|
+
如果显式配置的 `run_with_model` 当前不存在、未认证或不可用,本次激活失败并写入轻量运行事件,不自动换用其他模型。只有省略该字段时才使用插件默认 Shadow 模型。
|
|
119
|
+
|
|
120
|
+
`thinking_level` 的选择优先级为:Shadow 自身配置 → 插件的 `default_thinking_level` → 激活时 Main 会话当前生效的 thinking level。所选模型不支持当前候选等级时,依序尝试下一个候选;全部候选都不支持时本次激活失败并记录原因。这样当插件默认等级不被 Shadow 执行模型支持(例如只支持高推理档位的闪速模型)时,Shadow 会自动回退到 Main 正在使用的等级,而不是无谓失败。实际生效的等级记录在 run-end 事件中。
|
|
121
|
+
|
|
122
|
+
每个 Shadow 的最终工具集合由三部分组成:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
Pi SDK readOnlyTools
|
|
126
|
+
+ 当前可用的 tools 追加项
|
|
127
|
+
+ 内置 report_to_main
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
默认名称集合包含 `read`、`grep`、`find` 和 `ls`。激活时插件按名称从当前 Main Session 的最终工具 registry 解析实际实现,因此会继承其他插件对同名工具的覆盖以及当前环境适配。这里的 `readOnlyTools` 表示默认名称约定,不保证被覆盖后的实现仍然没有副作用。
|
|
131
|
+
|
|
132
|
+
`tools` 是在该集合之上追加的显式白名单,省略时视为 `[]`。例如 `tools: [write]` 会获得当前 registry 中的默认四个工具、`write` 和内置 `report_to_main`。
|
|
133
|
+
|
|
134
|
+
Pi 的通用 `ToolDefinition` 没有可供插件查询的只读属性,因此自定义工具不会被自动归类或加入;编辑文件、执行 Shell 或其他能力也不会被隐式继承自 Main。配置的追加工具在当前 Session 不存在时,插件忽略该项、写入轻量运行事件,其余工具继续正常提供。
|
|
135
|
+
|
|
136
|
+
`tools` 白名单本身就是用户对该 Shadow 的执行授权。列入白名单的写入、Shell 或其他工具可以由后台 Shadow 直接调用,插件不增加逐次确认层。
|
|
137
|
+
|
|
138
|
+
### 写入并发边界
|
|
139
|
+
|
|
140
|
+
第一版不包装或替换 Main、Pi 内置工具及第三方插件工具,也不承诺文件级写入互斥。Pi 允许插件覆盖和新增工具,而任意工具可能产生无法预先声明的文件副作用;不完整的锁机制会形成错误的安全保证。
|
|
141
|
+
|
|
142
|
+
当用户把写入、Shell 或其他有副作用的工具加入 Shadow 白名单时,即表示接受它与 Main 或其他 Shadow 并发执行产生冲突的风险。可以在 Shadow Markdown 中约定职责范围,例如文档 Shadow 只维护 `docs/`,但这属于模型行为约束,不是运行时强制隔离。
|
|
143
|
+
|
|
144
|
+
未来可以提供自愿接入的协作式锁协议,让能够声明目标文件的工具主动参与协调;未知工具仍不能被视为受保护。该协议不属于第一版。
|
|
145
|
+
|
|
146
|
+
每个 Shadow 运行实例还会固定获得内置工具 `report_to_main`。该工具用于提交一条值得 Main 注意的发现,不属于普通工具白名单,也不能被移除。它是终止型工具:一旦调用,当前 Shadow Agent loop 立即结束,运行实例随即回收,因此一次激活最多上报一条意见。Shadow 正常结束且未调用该工具时,运行结果视为“保持沉默”。
|
|
147
|
+
|
|
148
|
+
“保持沉默”不代表 Shadow 没有执行工作。即使运行中成功调用过写入或其他有副作用的工具,Shadow 仍可不调用 `report_to_main` 而正常结束;插件不强制生成工作报告。此类行为只通过轻量运行事件和可选的 debug Session 日志追踪。
|
|
149
|
+
|
|
150
|
+
第一版 `report_to_main` 只接受一个 `content` 参数。它不包含严重度、类别或固定的报告结构;不同 Shadow 的表达要求由各自 Markdown 正文定义。
|
|
151
|
+
|
|
152
|
+
`content` 不设置硬性长度上限,也不在运行时截断。公共协议只要求报告清楚、简洁,具体详略由对应 Shadow 定义控制。
|
|
153
|
+
|
|
154
|
+
```text
|
|
155
|
+
report_to_main({ content: "..." })
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
插件提供默认运行超时,第一版默认值为 `60s`。单个 Shadow 可以通过 `timeout_seconds` 覆盖。超时后插件终止该运行实例、释放并发槽位,并丢弃未完成结果,不向 Main 注入消息。
|
|
159
|
+
|
|
160
|
+
第一版不设置单次 model call 数或工具调用次数上限。运行资源只通过 heartbeat 概率、Shadow 激活概率、最大并发数和时间超时控制。
|
|
161
|
+
|
|
162
|
+
所有 Shadow 都记录轻量运行事件,包括激活、沉默、上报、超时、中止、耗时、执行模型以及工具使用摘要。工具摘要只记录工具名、调用次数和成功/失败统计,不保存参数或结果。事件作为自定义 entries 写入当前 Main Session,随会话持久化和恢复,但不参与 Main 的模型上下文。
|
|
163
|
+
|
|
164
|
+
每次 Main `turn_end` 的 heartbeat 判断都会写入一条轻量调度事件:先记录 heartbeat 随机值与是否触发;触发后再记录候选 Shadow、各自随机值、概率命中项、模型过滤、运行中排除、并发槽位裁剪和最终激活项。事件不保存 Main 或 Shadow 上下文,用于完整复盘调度决策。
|
|
165
|
+
|
|
166
|
+
`/shadow` 打开统一状态面板,展示当前 Session 的暂停状态、有效与无效 Shadow、正在运行的实例、最近事件和实际生效配置;`/shadow status` 提供对应的摘要视图。第一版面板以观察为主,不内置完整 Markdown 编辑器。
|
|
167
|
+
|
|
168
|
+
Pi 主界面常驻一个紧凑状态指示,例如 `🐙 2`,数字表示当前运行的 Shadow 实例数。产生报告、超时或错误时指示器短暂改变状态,不弹出逐次通知;详细信息统一进入 `/shadow` 面板。
|
|
169
|
+
|
|
170
|
+
只有设置 `debug: true` 的 Shadow 才保存完整的临时 AgentSession 日志,存入 `~/.pi/agent/shadow-minds/logs/<shadow-id>/`。
|
|
171
|
+
|
|
172
|
+
每次 Shadow 激活对应一个独立日志文件。文件覆盖该次临时 AgentSession 从创建到结束的完整生命周期;沉默、上报、超时和中止都会正常收口并记录最终状态。因此目录中的文件数量可以直接反映 `debug` 开启期间该 Shadow 的激活次数。
|
|
173
|
+
|
|
174
|
+
日志使用 Pi 原生 Session JSONL 格式,并在运行过程中增量写入。每个文件同时标记 Shadow ID、所属 epoch 和最终状态,以便复用 Pi 的会话查看能力并在异常退出时保留已有记录。
|
|
175
|
+
|
|
176
|
+
完整调试日志默认永久保留,不自动轮转或删除。任何日志清理都必须由用户显式执行,避免目录文件数失去累计激活次数的含义。
|
|
177
|
+
|
|
178
|
+
完整日志包含 Shadow 实际收到的净化轨迹、Shadow thinking、自己的工具调用和工具结果,可能包含其独立读取到的项目内容,因此 `debug` 默认关闭。
|
|
179
|
+
|
|
180
|
+
建议提供以下工具,使用户与 AI 操作同一套实体:
|
|
181
|
+
|
|
182
|
+
```text
|
|
183
|
+
create_shadow
|
|
184
|
+
update_shadow
|
|
185
|
+
delete_shadow
|
|
186
|
+
list_shadows
|
|
187
|
+
enable_shadow
|
|
188
|
+
disable_shadow
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
`list_shadows` 是只读操作,可以直接执行。AI 发起的 `create_shadow`、`update_shadow`、`enable_shadow`、`disable_shadow` 以及删除操作都会持久影响全局 registry,执行写入前必须向用户展示变更并取得确认。用户直接手动编辑 Markdown 不经过插件确认流程。
|
|
192
|
+
|
|
193
|
+
`create_shadow` 和 `update_shadow` 接收结构化配置字段与单独的 Markdown `body`,不接收一整段未经解析的文件文本。插件负责校验字段并统一序列化 frontmatter;确认界面展示字段级差异和正文差异。用户手动编辑时仍直接操作普通 Markdown 文件。
|
|
194
|
+
|
|
195
|
+
AI 调用 `create_shadow` 时必须显式提供 `id`,文件保存为 `<id>.md`。如果目标文件名或 registry 中的最终 ID 已存在,创建失败,不自动改名。用户手动创建的 Markdown 仍可省略 `id` 并由文件名派生。
|
|
196
|
+
|
|
197
|
+
`update_shadow` 不允许修改 `id`。需要更换身份时必须创建新 Shadow,再删除旧实体;插件不自动迁移日志、事件或正在运行实例。
|
|
198
|
+
|
|
199
|
+
`delete_shadow` 只删除 Markdown 定义,不删除 `logs/<shadow-id>/`。历史调试 Session 继续保留,日志清理必须由用户另行显式执行。
|
|
200
|
+
|
|
201
|
+
插件同时提供读取和修改全局配置的工具。读取 `config.json` 无需确认;AI 请求修改时必须向用户展示配置差异并取得确认,不能静默改变 heartbeat 概率、并发上限、默认模型或其他调度行为。
|
|
202
|
+
|
|
203
|
+
插件不应把“事实检查者”“替代路线探索者”等类型写进主流程。新的认知视角通过新增 Markdown 实体扩展。
|
|
204
|
+
|
|
205
|
+
registry 加载时逐文件校验 frontmatter。无效 Markdown 只会使对应 Shadow 被跳过,不影响其他实体和插件启动。插件在启动时显示文件路径及具体错误,并在 `/shadow status` 中持续标记;不会自动修正或改写用户定义。
|
|
206
|
+
|
|
207
|
+
`id` 省略时取 Markdown 文件名去掉扩展名;显式填写可让文件重命名后仍保持同一身份。registry 校验解析后的 ID 在全局目录中唯一,冲突的定义均不参与调度并显示错误。
|
|
208
|
+
|
|
209
|
+
`enabled` 省略时视为 `true`;只有明确设置为 `false` 的 Shadow 才退出调度。
|
|
210
|
+
|
|
211
|
+
`active_for_models` 省略时视为 `["*"]`,匹配所有 Main 模型。只有用于补偿特定模型表现的 Shadow 才需要显式声明模型列表。
|
|
212
|
+
|
|
213
|
+
每次 heartbeat 判断前,registry 检查顶层 Markdown 的文件变更,只重新解析新增或发生变化的文件,并移除已删除定义。不使用文件系统实时监听;用户手动编辑的结果在下一次 Main `turn_end` 生效。
|
|
214
|
+
|
|
215
|
+
Shadow 实例启动时取得定义的不可变快照。运行期间对 Markdown 的修改、禁用或删除只影响后续激活,不会改变或中止已有实例;需要立即停止时由用户执行 `/shadow pause`。
|
|
216
|
+
|
|
217
|
+
## 4. Shadow 上下文
|
|
218
|
+
|
|
219
|
+
Shadow 上下文以 Main 能看到的完整上下文为基础做减法,而不是重新构造一套任务背景。它完整继承 Main system prompt,包括适用于当前任务的系统级和项目级指令;随后过滤消息历史,并加入当前 Shadow Mind 的定义。
|
|
220
|
+
|
|
221
|
+
保留的消息内容包括:
|
|
222
|
+
|
|
223
|
+
- 用户消息;
|
|
224
|
+
- Main 的普通文本;
|
|
225
|
+
- 工具调用及其结果概述;
|
|
226
|
+
- 已注入 Main 会话的历史 `shadow-report`;
|
|
227
|
+
- 当前 Shadow Mind 的定义。
|
|
228
|
+
|
|
229
|
+
Main system prompt 保持原始内容和前缀顺序,既避免 Shadow 遗漏 Main 必须遵守的约束,也有利于多个 AgentSession 共享 prompt cache。其后先追加一段稳定的 Shadow 公共协议,再追加当前 Shadow Markdown 正文,形成 Shadow 专属 system suffix;不同 Shadow 只改变最后的实体定义,不改动可共享的 Main prompt 与公共协议前缀。
|
|
230
|
+
|
|
231
|
+
```text
|
|
232
|
+
Main system prompt
|
|
233
|
+
→ stable Shadow runtime protocol
|
|
234
|
+
→ current Shadow Markdown definition
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
公共协议保持最小,只说明:当前实例是一次性的并行认知核心;消息历史已经过净化;它可以依照自身职责独立观察或执行工作;需要向 Main 同步结果时调用 `report_to_main`,该调用会立即结束当前 loop;没有需要同步的内容时可以正常结束。具体关注点、任务线和表达方式全部由 Shadow Markdown 决定。
|
|
238
|
+
|
|
239
|
+
轨迹范围覆盖当前 Main Session 从开始到激活时刻的全部历史,而不只包含当前用户 epoch。这样 Shadow 能看到早期用户约束和已经形成的会话决策。epoch 只用于判断 Shadow 的迟到结果能否介入,不参与轨迹裁剪。
|
|
240
|
+
|
|
241
|
+
这里的“全部历史”以 Main 激活时实际可见的上下文为准。Main 已发生 compaction 时,Shadow 继承压缩后的上下文,不绕过 compaction 读取已被替换的原始消息。
|
|
242
|
+
|
|
243
|
+
由于净化轨迹是 Main 上下文的严格子集,第一版不增加单独的摘要或截断机制。如果某个 Shadow 配置的 `run_with_model` 上下文窗口更小而无法容纳轨迹,则该次激活失败并记录原因,不生成介入消息。
|
|
244
|
+
|
|
245
|
+
以下内容不进入 Shadow 上下文:
|
|
246
|
+
|
|
247
|
+
- Main 的 thinking / reasoning;
|
|
248
|
+
- 工具返回的完整内容;
|
|
249
|
+
- 其他 Shadow 未上报的推理过程。
|
|
250
|
+
|
|
251
|
+
第一版原样保留工具调用参数,不额外识别或脱敏其中的密钥、令牌等内容。如果 Shadow 使用与 Main 不同的模型供应商,这些参数会随净化轨迹发送给 `run_with_model` 指定的模型;用户配置执行模型时需要接受这一信息边界。
|
|
252
|
+
|
|
253
|
+
工具调用和结果概述写在同一行,以 `·` 分隔:
|
|
254
|
+
|
|
255
|
+
```text
|
|
256
|
+
User: 帮我为项目设计权限系统。
|
|
257
|
+
Main: 我先检查现有实现。
|
|
258
|
+
Tool: read({ path: "src/auth.ts" }) · 成功,返回 186 行
|
|
259
|
+
Tool: search({ query: "UserRole" }) · 成功,3 个文件中有 7 处匹配
|
|
260
|
+
Main: 建议复用项目现有的 UserRole。
|
|
261
|
+
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
上例展示的是净化后的消息轨迹;Shadow Markdown 不作为普通消息出现在其中,而是追加到继承的 Main system prompt 末尾。
|
|
265
|
+
|
|
266
|
+
运行时保留 Pi 原生的 assistant tool call 与 tool result 消息结构,以及二者的关联 ID;只将 tool result 的完整内容替换为摘要器生成的概述。`调用 · 概述` 是面向用户和文档的紧凑渲染形式,不代表将两类消息扁平化成普通文本。
|
|
267
|
+
|
|
268
|
+
结果概述只表达调用是否成功、结果规模和必要的状态信息,不携带完整正文。例如:
|
|
269
|
+
|
|
270
|
+
```text
|
|
271
|
+
read({ path: "src/auth.ts" }) · 成功,返回 186 行
|
|
272
|
+
search({ query: "UserRole" }) · 成功,3 个文件中有 7 处匹配
|
|
273
|
+
shell({ command: "npm test" }) · 失败,12 项通过、2 项失败
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
概述由插件中的工具摘要器注册表生成。每类工具拥有自己的摘要策略,例如 `read` 记录路径和行数,`search` 记录文件数与匹配数,`shell` 记录退出状态和测试统计。未知工具使用通用摘要器,只记录成功/失败、结果类型和结果规模。摘要过程不调用模型。
|
|
277
|
+
|
|
278
|
+
工具摘要器是独立扩展点;增加新工具时注册对应摘要器,不在轨迹构建主流程中持续追加类型分支。
|
|
279
|
+
|
|
280
|
+
这样,Shadow 可以观察 Main 做了什么以及行动的大致结果,但无法直接继承 Main 的证据内容和推理路径。需要核实时,Shadow 使用自己的工具重新调查,形成独立证据链。
|
|
281
|
+
|
|
282
|
+
## 5. Heartbeat 调度
|
|
283
|
+
|
|
284
|
+
第一版不识别 plan change、uncertainty、risk 等语义事件,也不使用 Gate Model。
|
|
285
|
+
|
|
286
|
+
每次 Main model call 完成后,按插件配置 `heartbeat_probability` 独立判断是否产生 heartbeat。默认值为 `1/3`:
|
|
287
|
+
|
|
288
|
+
```text
|
|
289
|
+
P(heartbeat after model call) = heartbeat_probability
|
|
290
|
+
default heartbeat_probability = 1 / 3
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
实现上以 Main Agent 的每次 `turn_end` 作为一次 model call 边界。带工具调用的中间轮次与不带工具调用的最终回复轮次都参与判断;Shadow AgentSession 自己的 `turn_end` 不参与 Main heartbeat。
|
|
294
|
+
|
|
295
|
+
由 `shadow-report` 触发的 Main 补充或修正也属于正常 Main 工作链,其 `turn_end` 继续参与 heartbeat。第一版不限制 Shadow 介入链的深度,允许后续 Shadow 再次检查 Main 的修正;概率、并发上限、超时和结果聚合共同承担节流。
|
|
296
|
+
|
|
297
|
+
默认情况下,相邻 heartbeat 的期望间隔为 3 次 model call,但实际间隔保持随机:可能连续发生,也可能较长时间不发生。
|
|
298
|
+
|
|
299
|
+
第一版直接使用运行时随机数,不提供或持久化随机 seed,也不承诺重放同一调度序列。实际抽样值通过轻量调度事件保留,供事后分析。
|
|
300
|
+
|
|
301
|
+
heartbeat 发生时:
|
|
302
|
+
|
|
303
|
+
1. 读取当前 Main 模型。
|
|
304
|
+
2. 筛选 `enabled: true` 且 `active_for_models` 匹配的 Shadow。
|
|
305
|
+
3. 排除当前正在运行的同一 Shadow。
|
|
306
|
+
4. 每个剩余 Shadow 按自己的 `activation_probability` 独立判断是否激活。
|
|
307
|
+
5. 如果命中项超过 `max_parallel_shadows`,从中随机选择允许的数量。
|
|
308
|
+
6. 并行创建运行实例并传入各自的净化轨迹。
|
|
309
|
+
|
|
310
|
+
一次 heartbeat 可能不激活任何 Shadow,也可能激活一个或多个。一次 heartbeat 不等待 Shadow 完成,Main 继续工作。
|
|
311
|
+
|
|
312
|
+
`max_parallel_shadows` 是插件级调度配置,默认值为 `2`。它限制同一时刻正在运行的 Shadow 实例总数,而不仅是单次 heartbeat 新建的数量。heartbeat 只能使用剩余并发槽位:
|
|
313
|
+
|
|
314
|
+
```text
|
|
315
|
+
available_slots = max_parallel_shadows - running_shadow_count
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
如果没有剩余槽位,本次 heartbeat 不启动新的 Shadow。
|
|
319
|
+
|
|
320
|
+
命中数量超过剩余槽位时,未被随机选中的 Shadow 直接跳过,不进入等待队列,也不保留本次轨迹快照。后续 heartbeat 会基于届时的最新上下文重新判断。
|
|
321
|
+
|
|
322
|
+
`activation_probability` 表示 heartbeat 已经发生之后,该 Shadow 被选中的基础概率。因此某个 Shadow 在单次 Main model call 后获得激活机会的基础概率为:
|
|
323
|
+
|
|
324
|
+
```text
|
|
325
|
+
P(activation) = heartbeat_probability × activation_probability
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
`activation_probability` 省略时使用默认值 `0.3`。在默认 heartbeat 概率 `1/3` 下,且不考虑并发槽位竞争时,该 Shadow 每次 Main `turn_end` 的基础激活概率约为 `10%`。
|
|
329
|
+
|
|
330
|
+
当一次 heartbeat 的命中数量超过剩余并发槽位时,并发上限会进一步降低每个命中项的最终激活概率。
|
|
331
|
+
|
|
332
|
+
Main 在会话中切换模型后,后续 heartbeat 直接依据新模型重新筛选。
|
|
333
|
+
|
|
334
|
+
## 6. Shadow 的输出与介入
|
|
335
|
+
|
|
336
|
+
Shadow 可以得出“没有值得介入的发现”,此时保持沉默。插件不要求每次激活都产生消息。
|
|
337
|
+
|
|
338
|
+
当 Shadow 发现问题或完成并行工作后,可以调用 `report_to_main` 提交一条面向 Main 的简洁结果。Shadow 不决定投递方式,插件根据 Main 当前状态选择交付方式:
|
|
339
|
+
|
|
340
|
+
```text
|
|
341
|
+
Shadow 返回
|
|
342
|
+
├── Main 仍在运行
|
|
343
|
+
│ └── 使用 steer,在下一次认知边界注入
|
|
344
|
+
│
|
|
345
|
+
├── Main 已最终回复,但用户尚未开始下一轮
|
|
346
|
+
│ └── 触发 follow-up,让 Main 补充或修正
|
|
347
|
+
│
|
|
348
|
+
└── 用户已经开始下一轮
|
|
349
|
+
└── 丢弃旧结果
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
最终回复不会立即终止正在运行的 Shadow。迟到结果仍可在下一条用户消息到来前触发补充回复。
|
|
353
|
+
|
|
354
|
+
每个用户任务拥有递增的 `epoch`:
|
|
355
|
+
|
|
356
|
+
```text
|
|
357
|
+
Shadow started at epoch 12
|
|
358
|
+
Shadow returned during epoch 12 → 可以介入
|
|
359
|
+
|
|
360
|
+
User sends a new message
|
|
361
|
+
Current epoch becomes 13
|
|
362
|
+
Running Shadow from epoch 12 → 立即中止并回收
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
新用户消息开启 epoch 时,插件立即中止所有属于旧 epoch 的 Shadow AgentSession,释放并发槽位,并丢弃聚合窗口内尚未发送的旧结果。返回与 epoch 切换恰好并发时,发送前再次校验 epoch。
|
|
366
|
+
|
|
367
|
+
用户手动中止 Main 当前任务时,插件同步中止当前 epoch 的全部 Shadow AgentSession,清空待发送的聚合报告并释放并发槽位。中止操作不触发 Main 的补充回复。
|
|
368
|
+
|
|
369
|
+
Shadow 严格绑定启动它的 Main Session。用户切换、替换或关闭 Session,以及插件卸载或运行时关闭时,插件立即中止该 Session 的全部 Shadow、清空报告聚合并释放资源;结果不会跨会话投递,也不会等待后台实例完成。
|
|
370
|
+
|
|
371
|
+
这允许 Main 保持非阻塞,同时避免旧 Shadow 干扰新的用户任务。第一版接受用户偶尔先看到初始回答、随后看到补充或自我修正。
|
|
372
|
+
|
|
373
|
+
### 多结果聚合
|
|
374
|
+
|
|
375
|
+
多个 Shadow 几乎同时返回有效意见时,插件不会立即逐条注入。结果先进入一个短暂的聚合窗口,再组合成一条消息:
|
|
376
|
+
|
|
377
|
+
```text
|
|
378
|
+
[项目事实检查者]
|
|
379
|
+
Main 声称项目已有 UserRole,但当前轨迹不足以支持该结论。
|
|
380
|
+
|
|
381
|
+
[约束检查者]
|
|
382
|
+
当前方案遗漏了用户要求的访客只读访问。
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
聚合只负责按 Shadow 名称分段拼接,不调用额外模型进行总结或去重。插件配置 `result_batch_window_ms` 控制收集窗口,默认值为 `400`。
|
|
386
|
+
|
|
387
|
+
聚合消息仍遵循 epoch:窗口内混入的过期结果在发送前被丢弃。
|
|
388
|
+
|
|
389
|
+
聚合结果以可见的 `shadow-report` 自定义消息写入 Main 会话,并保留各 Shadow 名称作为来源。它不会伪装成用户消息;Main 与用户都能识别这是插件产生的并行认知报告。运行时再根据 Main 状态,将该自定义消息按 `steer` 或 follow-up 方式交付。
|
|
390
|
+
|
|
391
|
+
`shadow-report` 在聊天中采用紧凑展开样式,直接显示章鱼标识、来源 Shadow 名称和完整报告内容,但视觉层级弱于用户消息和 Main 普通回复,不使用大型对话气泡,也不默认折叠。
|
|
392
|
+
|
|
393
|
+
历史 `shadow-report` 会进入后续 Shadow 的净化轨迹,形成显式反馈链。新的 Shadow 可以结合 Main 对既有报告的响应继续复查:问题已解决则保持沉默,尚未解决则再次上报。
|
|
394
|
+
|
|
395
|
+
Shadow 自己的静默工具调用和行动摘要不进入 Main 消息历史,也不进入后续 Shadow 的净化轨迹。它们只体现在共享的外部环境、Main Session 的轻量观测 entries 和可选 debug 日志中。Shadow 之间的显式认知传播只通过 `shadow-report` 发生。
|
|
396
|
+
|
|
397
|
+
## 7. 运行状态
|
|
398
|
+
|
|
399
|
+
插件需要维护的状态保持在最小范围:
|
|
400
|
+
|
|
401
|
+
```text
|
|
402
|
+
current epoch
|
|
403
|
+
current Main model
|
|
404
|
+
model call count
|
|
405
|
+
heartbeat_probability
|
|
406
|
+
max_parallel_shadows
|
|
407
|
+
result_batch_window_ms
|
|
408
|
+
default_shadow_timeout_seconds
|
|
409
|
+
Shadow activation probabilities
|
|
410
|
+
running Shadow IDs
|
|
411
|
+
active Shadow runs and their start epoch
|
|
412
|
+
lightweight Shadow run events in Main Session custom entries
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Shadow Markdown 是定义,不承担日志和运行状态。调度记录、运行结果和统计数据不应持续写回定义文件。
|
|
416
|
+
|
|
417
|
+
Shadow 的临时 AgentSession 不跨激活复用,也不写回记忆。
|
|
418
|
+
|
|
419
|
+
轻量事件属于运行观测数据,不参与任何 Agent 的上下文。`debug: true` 产生的完整 Session 日志也只用于调试,不会成为后续 Shadow 的记忆。
|
|
420
|
+
|
|
421
|
+
插件提供 `/shadow pause` 与 `/shadow resume`,只控制当前 Main Session 是否继续产生 heartbeat,不修改全局 Shadow Markdown。执行 pause 时立即中止当前 Session 已运行的 Shadow、清空尚未发送的聚合结果并释放并发槽位;resume 后从后续 Main `turn_end` 恢复概率判断。
|
|
422
|
+
|
|
423
|
+
同一个 Shadow 在前一次实例仍运行时不重复激活;不同 Shadow 可以并行运行。
|
|
424
|
+
|
|
425
|
+
前一次实例结束后,同一个 Shadow 可以在同一用户 epoch 内被后续 heartbeat 再次激活,不设置每 epoch 次数上限。每次仍创建全新的临时 AgentSession,并取得激活时刻的最新完整净化轨迹。
|
|
426
|
+
|
|
427
|
+
## 8. 第一版范围
|
|
428
|
+
|
|
429
|
+
第一版包含:
|
|
430
|
+
|
|
431
|
+
- 从 Markdown 发现和加载多个 Shadow Mind;
|
|
432
|
+
- 隔离无效定义并提供持续可见的校验错误;
|
|
433
|
+
- 每次 heartbeat 前增量刷新全局 registry;
|
|
434
|
+
- 维护全局 Shadow registry;
|
|
435
|
+
- 每次激活创建并在结束后销毁全新的临时 AgentSession;
|
|
436
|
+
- 用户和 AI 创建、修改、启用与停用 Shadow;
|
|
437
|
+
- AI 写入全局 Shadow registry 前取得用户确认;
|
|
438
|
+
- 按 Main 模型筛选 Shadow;
|
|
439
|
+
- 为每个 Shadow 配置执行模型,并支持插件级默认模型;
|
|
440
|
+
- 通过 `heartbeat_probability` 配置随机 heartbeat,默认概率为 `1/3`;
|
|
441
|
+
- 每个 Shadow 按自己的概率参与 heartbeat;
|
|
442
|
+
- 通过 `max_parallel_shadows` 配置最大并行数量;
|
|
443
|
+
- 构造净化轨迹;
|
|
444
|
+
- 默认使用当前 Main Session 的全部净化历史;
|
|
445
|
+
- 通过工具摘要器注册表生成结果概述,并提供通用兜底;
|
|
446
|
+
- Shadow 独立使用工具进行检查;
|
|
447
|
+
- 通过内置 `report_to_main` 工具显式提交介入内容;
|
|
448
|
+
- `report_to_main` 调用后立即终止对应 Shadow Agent loop;
|
|
449
|
+
- 为每个 Shadow 配置工具白名单,默认使用 Pi 的 `readOnlyTools`;白名单中的额外工具视为已授权;
|
|
450
|
+
- 提供插件级默认运行超时,并允许单个 Shadow 覆盖;
|
|
451
|
+
- 记录轻量运行事件并提供 `/shadow status`;
|
|
452
|
+
- 为 `debug: true` 的 Shadow 保存完整临时 Session 日志;
|
|
453
|
+
- 每次 Shadow 激活使用一个独立日志文件,并记录最终状态;
|
|
454
|
+
- 调试日志采用 Pi 原生 Session JSONL 并增量写入;
|
|
455
|
+
- 运行中使用 `steer`,Main 结束后使用 follow-up;
|
|
456
|
+
- 在短聚合窗口内合并同期 Shadow 意见后一次性注入;
|
|
457
|
+
- 使用可见的 `shadow-report` 自定义消息呈现聚合结果;
|
|
458
|
+
- 使用 epoch 丢弃跨用户任务的迟到结果。
|
|
459
|
+
- 新 epoch 开始时立即中止旧 epoch 的 Shadow 并释放资源;
|
|
460
|
+
- 用户手动中止 Main 时同步停止当前 epoch 的 Shadow;
|
|
461
|
+
- 支持按 Main Session 暂停和恢复整个 Shadow 系统;
|
|
462
|
+
|
|
463
|
+
第一版明确不包含:
|
|
464
|
+
|
|
465
|
+
- 项目级 Shadow 及全局/项目覆盖规则;
|
|
466
|
+
- 语义 Gate 或 Expected Value of Thinking 预测;
|
|
467
|
+
- 根据错误、风险、计划变化等事件进行规则调度;
|
|
468
|
+
- 学习型调度器;
|
|
469
|
+
- Shadow 之间通信;
|
|
470
|
+
- 将 Main thinking 或完整工具结果暴露给 Shadow;
|
|
471
|
+
- 根据历史表现自动训练或优化 Shadow;
|
|
472
|
+
- Shadow 的跨次运行记忆。
|
|
473
|
+
- Main、Shadow 与第三方工具之间的写入并发保护。
|
|
474
|
+
|
|
475
|
+
## 9. 验证方式
|
|
476
|
+
|
|
477
|
+
使用同一组任务比较:
|
|
478
|
+
|
|
479
|
+
```text
|
|
480
|
+
Single-core Pi
|
|
481
|
+
vs
|
|
482
|
+
Pi + multiple Shadow Minds
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
第一阶段重点观察:
|
|
486
|
+
|
|
487
|
+
- Shadow 是否发现了 Main 未发现的问题;
|
|
488
|
+
- Shadow 的介入是否改变了 Main 的后续行为;
|
|
489
|
+
- 是否减少项目事实编造、遗漏约束和错误路线;
|
|
490
|
+
- 无效或有害介入的比例;
|
|
491
|
+
- heartbeat 频率和并行数量带来的成本与延迟。
|
|
492
|
+
|
|
493
|
+
这些运行数据将决定后续是否值得引入更复杂的调度,而不是在第一版提前设计智能 Gate。
|
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Pi Shadow Mind
|
|
2
|
+
|
|
3
|
+
Shadow Mind is a Pi extension that occasionally starts independent, temporary agent sessions beside the main agent. Each Shadow Mind is a Markdown entity with its own responsibility, model filter, activation probability, tools, model, thinking level, timeout, and optional debug log.
|
|
4
|
+
|
|
5
|
+
The first version activates on each main-agent `turn_end`: the heartbeat fires with probability `1/3`, eligible Shadow Minds roll independently (default `0.3`), and at most two run concurrently. Shadow sessions inherit the main system prompt and its compacted visible trajectory, but assistant thinking is removed and tool results are reduced to deterministic summaries. Tool calls remain intact.
|
|
6
|
+
|
|
7
|
+
## Install for development
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
npm install
|
|
11
|
+
pi -e ./src/index.ts
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Pi also discovers this package when installed as a Pi package because `package.json` declares `pi.extensions`.
|
|
15
|
+
|
|
16
|
+
## Build and distribute
|
|
17
|
+
|
|
18
|
+
```powershell
|
|
19
|
+
npm run build
|
|
20
|
+
npm pack
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The generated `pi-shadow-mind-<version>.tgz` contains the compiled `dist/` extension. Publish it to npm for normal Pi installation, or unpack the standalone ZIP release and install that directory:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
pi install npm:pi-shadow-mind@0.1.5
|
|
27
|
+
# or, after unpacking the ZIP
|
|
28
|
+
pi install ./pi-shadow-mind-0.1.0
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Global files
|
|
32
|
+
|
|
33
|
+
On first session start, the extension creates:
|
|
34
|
+
|
|
35
|
+
```text
|
|
36
|
+
~/.pi/agent/shadow-minds/
|
|
37
|
+
config.json
|
|
38
|
+
*.md
|
|
39
|
+
logs/<shadow-id>/*.jsonl # only when debug: true
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
No default Shadow Mind is created. A minimal definition is:
|
|
43
|
+
|
|
44
|
+
```markdown
|
|
45
|
+
---
|
|
46
|
+
id: project-grounding
|
|
47
|
+
name: Project grounding
|
|
48
|
+
activation_probability: 0.3
|
|
49
|
+
active_for_models: ["openai/gpt-5"]
|
|
50
|
+
tools: [read, grep]
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
Check whether the main agent is inventing project facts. Inspect the repository when needed and report only concrete discrepancies.
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Use `/shadow` to toggle the compact status panel, `/shadow status` for a summary, and `/shadow pause` or `/shadow resume` for the current main session. The extension also exposes tools to list, create, update, enable, disable, and delete definitions, plus read/update the global config. Every write requires user confirmation.
|
|
57
|
+
|
|
58
|
+
See [DESIGN.md](./DESIGN.md) for the complete behavioral contract.
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ShadowConfig } from "./types.js";
|
|
2
|
+
export declare const DEFAULT_CONFIG: ShadowConfig;
|
|
3
|
+
export declare function parseConfig(input: unknown): ShadowConfig;
|
|
4
|
+
export declare function serializeConfig(config: ShadowConfig): string;
|
|
5
|
+
export declare class ConfigStore {
|
|
6
|
+
private readonly agentDir;
|
|
7
|
+
readonly configPath: string;
|
|
8
|
+
private lastGood;
|
|
9
|
+
private lastError?;
|
|
10
|
+
constructor(agentDir: string);
|
|
11
|
+
initialize(): Promise<void>;
|
|
12
|
+
reload(): Promise<{
|
|
13
|
+
config: ShadowConfig;
|
|
14
|
+
error?: string;
|
|
15
|
+
}>;
|
|
16
|
+
get current(): ShadowConfig;
|
|
17
|
+
get error(): string | undefined;
|
|
18
|
+
}
|