# pi-session-header

[English](README.md)

将 Pi 当前会话的 Session ID 自动注入 LLM Provider 的 HTTP 请求头。
上游网关可以据此实现路由、会话亲和和缓存复用；扩展只负责提供标识。

```http
x-pi-session-id: <current-pi-session-id>
```

## 兼容范围

- 目标支持 **Pi 0.85.0 及之后版本**，使用官方 `before_provider_headers` 事件。
- 对 Pi 0.85.0、1.4.0 做类型检查；0.85.0、1.0.0、1.4.0 的 SDK 和真实 CLI 测试均已通过，CI 覆盖这三个版本。
  后续 Pi 版本的兼容性取决于该事件是否继续支持原地修改请求头。
- Node.js 22.19+，与 Pi 要求一致。无运行时 npm 依赖，无需编译。
- 默认对所有调用官方 HTTP 请求头钩子的 Provider 生效，不按名称筛选。
  绕过钩子的自定义传输不在覆盖范围内；WebSocket 消息及非 HTTP 传输不处理。
- 本地 HTTP 测试覆盖 OpenAI Chat Completions、OpenAI Responses、Anthropic Messages、
  Google Generative AI，以及工具调用后的连续请求；其他 Provider 未逐一连接真实服务验证。

## 安装和管理

从 npm 安装：

```bash
pi install npm:pi-session-header
pi install npm:pi-session-header@0.1.0
```

源码推送后可从 Git 安装；固定标签需先创建对应 tag：

```bash
pi install git:github.com/or-less/pi-session-header
pi install git:github.com/or-less/pi-session-header@v0.1.0
```

内网仓库也可采用 `git:git.example.com/team/pi-session-header`，或 SSH 地址
`ssh://git@git.example.com/team/pi-session-header.git`。认证由 Git 管理。

默认写入用户全局配置，添加 `-l` 则写入当前项目。安装或修改后重启 Pi 或运行 `/reload`。

```bash
pi list
pi update npm:pi-session-header
pi remove npm:pi-session-header
```

Git 安装时，将更新、卸载命令中的来源换成对应 Git 来源。固定版本或标签不会自动升级；
需移除旧来源，再安装新的固定版本。不同 Pi 版本中裸 `pi update` 的含义有变化，
建议始终指定要更新的来源。

## 环境变量

启动 Pi 前配置。扩展加载时读取变量；修改启动终端的环境后需重新启动 Pi。

| 变量 | 默认值 | 说明 |
|---|---|---|
| `PI_SESSION_HEADER_NAME` | `x-pi-session-id` | 自定义请求头名称 |
| `PI_SESSION_HEADER_ENABLED` | `true` | 是否启用注入 |
| `PI_SESSION_HEADER_DEBUG` | `false` | 是否向 stderr 输出脱敏调试日志 |

布尔值支持 `true/false`、`1/0`、`yes/no`、`on/off`，忽略大小写及前后空白。
其他值视为配置错误。Header 名称必须符合 HTTP token 规范，不接受空白，统一转为小写。

```bash
PI_SESSION_HEADER_NAME=x-custom-session-id pi
PI_SESSION_HEADER_ENABLED=false pi
PI_SESSION_HEADER_DEBUG=true pi
```

Header 名称应根据上游网关的要求设置，不能假设网关识别 `x-pi-session-id`。
本版始终覆盖全部 Provider，暂不提供可选的 Provider 白名单。

禁止将认证头和传输控制头用作 Session Header，包括 `Authorization`、
`Proxy-Authorization`、常见 API Key 头、Cookie、`Host`、`Content-Type`、
`Content-Length` 等。配置无效时输出明确提示并停用注入，Pi 仍可继续运行。
调试日志不输出 Session ID、凭据、Prompt、请求正文或响应。

## 会话行为

每次钩子触发时读取 `ctx.sessionManager.getSessionId()`，不生成、不缓存 Session ID。

| 操作 | ID 行为 |
|---|---|
| 连续对话、工具调用 | 保持一致 |
| 恢复历史会话 | 沿用原 ID |
| 上下文压缩、切换模型或 Provider、`/tree` 导航 | 保持一致 |
| 新建会话、`/clone`、`/fork`、CLI `--fork` | 使用 Pi 生成的新 ID |
| 缺少 ID 或无法作为 HTTP Header 值 | 跳过注入 |

只添加或替换配置指定的 Header，同时处理其不同大小写形式。
保留其他 Header，不改请求正文或响应。Provider 内部重试可能直接复用请求头，
不再次触发钩子。Pi 的打印模式内部仍使用 HTTP 流式请求，扩展不改变该机制。

## 本地开发和验证

```bash
npm ci --ignore-scripts
npm run check
npm pack --dry-run
pi -e ./extensions/session-header.ts
```

也可用 `pi install /absolute/path/to/pi-session-header` 持久安装本地包。
Pi 直接加载 manifest 中声明的 TypeScript 入口，无需构建。

- `npm run typecheck`：对当前 SDK 和最低兼容 SDK 检查类型。
- `npm test`：配置校验、Header 保留、日志脱敏，以及真实 SDK 的会话生命周期。
- `npm run test:e2e`：启动本地 HTTP 接收服务，分别运行真实 Pi 0.85.0 和当前版本 CLI；
  使用隔离的配置和会话目录，验证注入、恢复、分叉、跨 Provider、工具调用和本地安装流程。

端到端测试需要本地监听端口和启动子进程的权限，不需要真实 Provider 凭据，
也不会产生付费模型请求。
具体版本、验证结果和测试依赖的审计说明见源码仓库的
[VALIDATION.md](https://github.com/or-less/pi-session-header/blob/main/VALIDATION.md)。

## 发布

仓库：[or-less/pi-session-header](https://github.com/or-less/pi-session-header)。
使用 [MIT License](LICENSE)，变更见 [CHANGELOG](CHANGELOG.md)。

发布前运行 `npm view pi-session-header` 检查名称和所有权，更新版本与变更记录，
执行 `npm run check`、`npm pack --dry-run`，检查包内是否包含私有文件。
npm 返回 404 仅说明当前未发布，不能预留名称，也不保证当前账号有发布权限。

发布工作流仅允许手动触发。先为该仓库的 `publish.yml` 配置 npm Trusted Publishing，
并在 GitHub 建立带必需审核人的 `npm` environment。推送与包版本一致的
`v<版本号>` 标签后，在该标签上手动运行工作流。流程校验版本和标签、运行检查，
再携带 provenance 发布。获得发布授权后，也可在本地执行：

```bash
npm publish --access public
```

禁止在源码中保存发布凭据。

官方参考：[Pi 0.85.0 扩展 API](https://github.com/earendil-works/pi/blob/v0.85.0/packages/coding-agent/docs/extensions.md#before_provider_headers)、
[Pi 包规范](https://github.com/earendil-works/pi/blob/main/packages/coding-agent/docs/packages.md)。
