Files
my-pi/extensions/context-mode-filter.ts
T
云服务部-叶林立andDevin <158243242+devin-ai-integration[bot]@users.noreply.github.com> ba164896d2 feat: 系统提示词改为单一入口统一管理
多个扩展各自整段改写系统提示词并按加载顺序接力,任一扩展定死提示词后
其余只能做字符串手术,且各上游的工具说明与组合包实际工具格局冲突。

- 新增 extensions/system-prompt.ts 作为唯一出口(加载列表最后),按
  config/prompt/(preamble.md、tools.jsonc、routing.jsonc、sections.jsonc)
  组合开场白、工具简介/规则与 <tool_routing> 分区;替代原封面与
  tool-routing 扩展,/dump-system-prompt 输出最终提示词。
- pi-chrome、pi-ssh、pi-hermes-memory 改为写命名分区,pi-rtk-optimizer
  改写 promptGuidelines,pi-permission-system 直接过滤结构化 skills,
  均不再返回 systemPrompt;pi-chrome 未授权时不再每轮冻结提示词。
- 新增 prompt-guard 代理加载第三方扩展(Hashline、FFF、LSP、
  context-mode):拦截直接改写提示词并按目录覆盖工具说明;context-mode
  去掉与组合包路由冲突的锚点段,保留记忆与恢复快照。
- 消除冲突:bash 简介不再建议 grep/find;Hashline edit 不再称可用 grep
  锚点、不再介绍已关闭的 replace_text;context-mode 读写/网页路由提示。
- 守门测试:工具目录覆盖率、禁用用法检查、context-mode 上游原文锁定;
  AGENTS.md 新增「系统提示词单一所有权」。

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-20 17:53:04 -07:00

37 lines
1.4 KiB
TypeScript

/**
* Pure filter applied after context-mode's `context` handler: its upstream
* build appends one `{ role: "user", content }` message whose parts are
* `"\n\n"`-joined and whose first part is a routing anchor that duplicates —
* and contradicts — the bundle-owned `config/prompt/routing.jsonc`. The anchor
* part is stripped; remaining parts (active memory, resume snapshot) stay.
* No other message is touched; when nothing changes the input array is
* returned unchanged (same reference).
*/
export const CONTEXT_MODE_ANCHOR_PREFIX = "context-mode active. Hierarchy:";
type MessageLike = { role?: unknown; content?: unknown } & Record<string, unknown>;
export function filterContextModeMessages<T extends MessageLike>(
before: readonly T[],
after: readonly T[],
): T[] {
if (after.length <= before.length) return after as T[];
let result: T[] | null = null;
for (let i = after.length - 1; i >= before.length; i--) {
const message = after[i];
if (message === null || typeof message !== "object") continue;
if (message.role !== "user" || typeof message.content !== "string") continue;
const parts = message.content.split("\n\n");
const kept = parts.filter((part) => !part.startsWith(CONTEXT_MODE_ANCHOR_PREFIX));
if (kept.length === parts.length) continue;
result ??= after.slice();
if (kept.length === 0) {
result.splice(i, 1);
} else {
result[i] = { ...message, content: kept.join("\n\n") };
}
}
return result ?? (after as T[]);
}