mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 10:45:22 +00:00
- 根包恢复 file:./pi-subagents 依赖与 extensions/subagents.ts 加载 (排在 permission-system 之后、Tool Search 之前),并刷新根锁文件; Agent / get_subagent_result / steer_subagent 权限设为 allow, 子 Agent 内的实际操作仍逐个经权限系统并转发主会话。 - 新增 config/prompt/subagent/:执行者角色 preamble 与组合包自带的 general-purpose / Explore / Plan 定义(替换上游内置,去掉 bash find 冲突规则与写死的 Haiku 模型)。 - pi-subagents 新增 basePrompt / bundledAgentsDir / excludedExtensionPaths 选项:子 Agent 不再嵌入父会话提示词,身份标记置于开头;子会话排除 pi-ask-user。未传选项时保持上游行为。 - system-prompt.ts:customPrompt 自带开场白时不再覆盖(修复子 Agent 角色 与 <active_agent> 身份被抹掉);仅凭 customPrompt 上的 <active_agent> 识别子会话,routing 规则支持 scope,sections 支持 subagentExclude (子会话去掉 memory_policy 与 chrome_profile_bridge)。 - pi-hermes-memory:子会话只读,记忆/skill 写入工具返回错误,后台整理、 纠错检测、会话 flush 与索引写入全部跳过。 Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
59 lines
2.7 KiB
TypeScript
59 lines
2.7 KiB
TypeScript
/**
|
|
* subagent-mode.ts — subagent sessions are read-only for memory and skill
|
|
* writes. All automatic write-related work (background review, correction
|
|
* detection, session flushes, session indexing) is skipped as well.
|
|
*
|
|
* A child session is identified by the `<active_agent name="..."/>` identity
|
|
* tag that pi-subagents stamps into every child prompt
|
|
* (permission-system-bridge.ts): the tag arrives via
|
|
* `systemPromptOptions.customPrompt`. The tag is only trusted on that field —
|
|
* never in the rendered system prompt, which a main session can legitimately
|
|
* contain through project docs.
|
|
*
|
|
* Membership is tracked per session by its sessionManager identity: the same
|
|
* process hosts the parent and its children concurrently, so a global boolean
|
|
* would let a child's turn flip the parent's session into read-only mid-turn.
|
|
*/
|
|
import type { BeforeAgentStartEvent, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
|
|
/** pi-subagents `<active_agent name="X"/>` identity tag contract. */
|
|
const ACTIVE_AGENT_TAG = /<active_agent\s+name=["'][^"']+["'][^>]*>/i;
|
|
const LEADING_ACTIVE_AGENT_TAG = /^\s*<active_agent\s+name=["'][^"']+["'][^>]*>/i;
|
|
|
|
export const SUBAGENT_WRITE_DISABLED_MESSAGE =
|
|
"Memory and skill writes are disabled in subagent sessions; include this in your final report so the delegating agent can decide.";
|
|
|
|
const subagentSessionManagers = new WeakSet<object>();
|
|
|
|
/** Same regex as the pi-subagents `<active_agent>` contract, applied only to customPrompt. */
|
|
export function isSubagentCustomPrompt(customPrompt: string | undefined | null): boolean {
|
|
return typeof customPrompt === "string" && ACTIVE_AGENT_TAG.test(customPrompt);
|
|
}
|
|
|
|
/**
|
|
* before_agent_start hook: authoritative detection via the event's
|
|
* systemPromptOptions.customPrompt.
|
|
*/
|
|
export function markSubagentSession(event: BeforeAgentStartEvent, ctx: ExtensionContext): void {
|
|
if (isSubagentCustomPrompt(event.systemPromptOptions?.customPrompt)) {
|
|
subagentSessionManagers.add(ctx.sessionManager);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* session_start runs before before_agent_start; detect tag-leading prompts
|
|
* early so session_start writes (skill migration, root setup) can be skipped.
|
|
* A main prompt cannot lead with the tag — without customPrompt the rendered
|
|
* prompt always opens with the base preamble.
|
|
*/
|
|
export function markSubagentSessionFromPrompt(systemPrompt: string, ctx: ExtensionContext): void {
|
|
if (LEADING_ACTIVE_AGENT_TAG.test(systemPrompt)) {
|
|
subagentSessionManagers.add(ctx.sessionManager);
|
|
}
|
|
}
|
|
|
|
export function isSubagentSession(ctx: unknown): boolean {
|
|
const sm = (ctx as { sessionManager?: unknown } | undefined | null)?.sessionManager;
|
|
return typeof sm === "object" && sm !== null && subagentSessionManagers.has(sm);
|
|
}
|