Pi HTTP开发

给Pi Coding Agent提供结构化HTTP(S)请求能力。每次Tool Call只表示一次请求,不解析Shell或curl语法。

项目:https://github.com/evalexp/pi-http

相关笔记:Pi Extension

当前状态

当前准备发布0.2.0。这是0.1接口到新结构化接口的Breaking Change,但本轮后续修改都只是0.2.0发布前的Bug Fix,不再改版本号

发布前最后一次验证结果:

  • npm run typecheck通过;
  • npm test共45个测试通过;
  • npm audit为0个漏洞;
  • npm pack后的生产依赖安装通过;
  • 使用Pi官方Extension Loader实际加载和执行通过;
  • 自签名HTTPS默认返回HTTP_TLS_FAILED,设置tls.insecure=true后可正常请求;
  • 临时调试日志已经全部移除;
  • Tool描述、Schema描述、Prompt Guidelines和重试提示已经改成精简中文。

先记住的结论

  1. 这个Extension只适配Pi Coding Agent,不再考虑Bun兼容。
  2. Pi实际运行时是Node.js,最低版本跟随Pi要求:>=22.19.0
  3. 直接依赖undici@8.9.0,不要检测Bun,也不要使用Bun.*
  4. 不依赖Pi安装过的全局Fetch Dispatcher;每次Tool调用建立独立的Undici Dispatcher,确保代理和TLS参数真的生效。
  5. 模型能看到的是Tool Result的content,不能假设它能看到details
  6. 完整结果超过Pi输出预算时不截断,原子落盘,只把绝对路径和字节数告诉模型。
  7. HTTP 4xx/5xx是正常协议结果;只有参数、本地文件和传输错误才抛Tool Error。
  8. Extension本身不暗中重试。Prompt告诉Agent如何改参数以及何时安全重试。

设计目标

  • 请求参数只有一种规范表达,不兼容0.1别名;
  • 字符串都按JSON字面值使用,不展开环境变量、反斜线、Glob或命令替换;
  • Body字节和Multipart结构尽量可控;
  • 上传、下载采用流式处理;
  • Redirect、Cookie、Proxy、TLS、Timeout都有明确状态;
  • 无法忠实实现的功能明确拒绝,不能静默忽略;
  • 输出同时适合模型阅读和Pi UI保留结构化信息;
  • 错误可诊断,而且重试不会默认制造副作用;
  • index.ts保持薄,HTTP Core不依赖Pi Context。

Pi运行时适配

为什么不再判断Bun

之前误以为Pi Extension可能直接运行在Bun中,因此TLS代码出现过运行时分支,最终在Pi里触发了:

Bun is not defined

实际适配目标就是Pi Coding Agent。Pi以Node.js加载TypeScript Extension,并且当前包本身声明:

{
  "engines": {
    "node": ">=22.19.0"
  },
  "dependencies": {
    "undici": "8.9.0"
  }
}

因此维护时不要重新加入:

  • Bun全局变量;
  • typeof Bun运行时探测;
  • Bun专用TLS Option;
  • Node/Bun双分支;
  • 为兼容Bun而绕开Pi的真实执行模型。

为什么不直接依赖全局fetch

Pi会为自身网络请求配置全局Undici Dispatcher。若Extension直接依赖全局fetch的隐式Dispatcher,逐请求代理、CA、自签名证书和mTLS设置可能被宿主配置干扰或根本不生效。

现在的结构是:

flowchart LR
    A[Pi调用http Tool] --> B[解析并校验参数]
    B --> C[为本次调用建立Undici Agent或ProxyAgent]
    C --> D[fetch或undici.request]
    D --> E[读取响应/下载]
    E --> F[销毁本次Dispatcher]

关键点:

  • Dispatcher属于一次Tool Call,不共享可变状态;
  • 显式代理使用ProxyAgent
  • 直连使用Agent
  • TLS参数传给本次连接;
  • 清理失败不能覆盖原始请求错误;
  • transfer.decompress=falseundici.request,用于保留压缩响应字节;
  • 204、205、304等无Body状态在Raw路径也必须正确处理。

代码结构

文件职责
index.tsPi Adapter、TypeBox Schema、注册Tool、把结果放入模型可见content
agent-guidance.ts中文Prompt Guidelines和按错误码分类的参数重试建议
request.ts参数校验、请求编排、Redirect、Timeout、错误分类和Timing
request-types.ts输入、结果、状态、错误等共享Contract
request-body.ts各类Body与精确Multipart构造
file-stream.ts本地文件校验和流式上传
pi-transport.tsPi专用Undici Agent/ProxyAgent、Fetch/Raw传输与清理
response-body.tsResponse Header、内联捕获、Hash和原子下载
cookie-store.ts单次调用Cookie Jar、Netscape Cookie文件与原子写回
model-output.ts完整JSON内联或超限后原子落盘
test-server.ts测试用HTTP、HTTPS、代理Server
request.test.tsHTTP Core集成测试
contract-size.test.tsSchema、Prompt和模型输出预算回归测试

依赖方向尽量保持:

flowchart TD
    A[index.ts / Pi Adapter] --> B[request.ts]
    A --> C[model-output.ts]
    A --> D[agent-guidance.ts]
    B --> E[request-body.ts]
    B --> F[pi-transport.ts]
    B --> G[response-body.ts]
    B --> H[cookie-store.ts]
    E --> I[file-stream.ts]
    C --> J[Node文件系统]

不要把Pi的ctx一路传进HTTP Core。目前只在Adapter取ctx.cwd和Pi的DEFAULT_MAX_BYTES

Tool输入

唯一必填参数是:

{ "url": "https://example.com/status" }

Method默认规则:

条件默认Method
无BodyGET
有BodyPOST

GET和HEAD Body会直接拒绝,不尝试依赖运行时的模糊行为。

完整输入按职责分组:

分组用途
urlmethodheadersquery基础请求
bodytext/base64/json/form/file/multipart六选一
authBasic或Bearer
cookies显式Cookie、Cookie文件、Jar写回
delayMstimeoutMs网络前延迟和请求总超时
redirect模式、次数、协议、方法和敏感Header策略
connection显式代理、noProxy、连接超时和HTTP版本偏好
tlsCA、客户端证书和证书校验
transfer自动解压与Range
response模式、捕获上限、Header选择和详情级别
download流式文件下载

Header和Query

统一使用有序数组:

{
  "headers": [
    { "name": "X-Trace", "value": "abc" }
  ],
  "query": [
    { "name": "tag", "value": "one" },
    { "name": "tag", "value": "two" }
  ]
}

Query、Form和Multipart Part Header可以重复。顶层请求Header如果重复,Fetch语义会合并,无法保持原始重复项,因此当前直接返回HTTP_UNSUPPORTED_CAPABILITY,不能让模型误以为字节被保留。

requestTargetpathAsIs=true也属于当前Undici层不能忠实表达的功能,传入即拒绝。

Body

Body是Discriminated Union,只允许一种type

文本:

{ "body": { "type": "text", "value": "literal $HOME\\n" } }

Base64原始字节:

{ "body": { "type": "base64", "value": "AAEC/w==" } }

JSON:

{ "body": { "type": "json", "value": { "name": "Pi" } } }

重复Form字段:

{
  "body": {
    "type": "form",
    "entries": [
      { "name": "role", "value": "a" },
      { "name": "role", "value": "b" }
    ]
  }
}

流式文件Body:

{ "body": { "type": "file", "path": "./archive.bin" } }

所有相对路径都基于Pi调用时的ctx.cwd。整个字符串就是路径,@没有特殊含义。

Multipart

0.2不再使用FormData + Blob + readFile()。Multipart由自己构造并流式读取文件,因此可以控制:

  • Part顺序和重复字段;
  • Boundary;
  • CRLF或LF;
  • 是否写结束Boundary;
  • filename原值;
  • filename编码方式;
  • 结构化Header顺序;
  • 原始Header行;
  • text/base64/file三种Part内容。
{
  "url": "https://example.com/upload",
  "body": {
    "type": "multipart",
    "boundary": "chosen-boundary",
    "lineEnding": "crlf",
    "closeBoundary": true,
    "parts": [
      {
        "name": "note",
        "content": { "type": "text", "value": "hello" }
      },
      {
        "name": "file",
        "filename": "../../report 文本.txt",
        "filenameEncoding": "both",
        "contentType": "text/plain",
        "content": { "type": "file", "path": "./report.txt" }
      }
    ]
  }
}

filename故意不做basename或Unicode改写,因为调用者可能正在复现具体报文。

headersrawHeaderLines互斥。若需要控制整个Preamble、分隔符、任意二进制内容或Epilogue,应直接用body.type=base64构造完整Body,并显式设置顶层Content-Type

这里的“精确”只指Body字节。请求行、顶层Header编码、Framing、连接复用和协议协商仍由Undici控制;它不是Raw TCP Client。

Auth、Cookie和Redirect

Auth

支持:

  • Basic:用户名、密码按UTF-8编码后再Base64;
  • Bearer:直接形成Authorization Header。

URL中携带Credential会拒绝,避免出现两个认证来源。显式Authorizationauth冲突也会在发送前报告。

{
  "cookies": {
    "value": "theme=dark",
    "file": "./cookies.txt",
    "jarPath": "./cookies-after.txt"
  }
}

Cookie文件使用Netscape格式。Jar仅存在于当前Tool Call及其Redirect Chain,不跨调用偷偷维持Session。写回使用临时文件再Rename。

即使后续Redirect请求失败,前一跳已经收到的Cookie仍应按当前状态写回。

Redirect

Redirect由request.ts逐跳处理,不交给Fetch自动跟随,这样才能准确控制:

  • followmanualerror
  • 最大20跳;
  • 只允许HTTP/HTTPS中的指定协议;
  • Loop检测;
  • 301/302/303的方法改写或显式保留;
  • 307/308正常保留Method和Body;
  • 跨Origin敏感Header处理;
  • 每一跳重新判断noProxy
  • 每一跳记录诊断信息。

跨Origin默认移除:

  • Authorization
  • Proxy-Authorization
  • Cookie

只有明确设置redirect.trusted=true才允许转发。这个开关不能默认开启。

Proxy和TLS

Proxy

代理必须显式传入:

{
  "connection": {
    "proxy": "http://proxy.example:8080",
    "proxyHeaders": [
      { "name": "Proxy-Authorization", "value": "Bearer value" }
    ],
    "noProxy": ["localhost", ".internal.example:8443"]
  }
}

设计边界:

  • 不继承HTTP_PROXYHTTPS_PROXYNO_PROXY等环境变量;
  • proxyHeaders只传给ProxyAgent,不能泄漏给目标站点;
  • noProxy支持*、精确Host、点开头域名后缀和可选Port;
  • Redirect每一跳重新选择直连或代理;
  • 仅有proxyHeadersnoProxy但没有proxy时直接报参数错误;
  • HTTPS经HTTP代理使用CONNECT,并已经用本地代理测试真实TLS握手。

TLS

{
  "tls": {
    "caFile": "./private-ca.pem",
    "clientCert": "./client-cert.pem",
    "clientKey": "./client-key.pem",
    "clientKeyPassphrase": "secret",
    "insecure": false
  }
}

注意:

  • caFile是本次请求的Node CA输入,不是简单追加系统CA的抽象;
  • clientCertclientKey必须成对;
  • insecure=true只关闭服务端证书校验;
  • TLS设置应用到本次Agent或Proxy CONNECT后的目标连接;
  • 不再存在Bun TLS分支。

当前明确不支持

以下字段保留在Schema中是为了明确返回不支持,而不是静默忽略:

参数原因
connection.resolve当前传输层不能提供可靠的逐请求DNS覆盖
connection.connectTo不能忠实覆盖连接目标同时保留目标语义
connection.ipVersion=4/6当前仅支持auto
requestTargetUndici不提供独立Raw Request Target
pathAsIs=trueURL规范化无法关闭

这些情况统一用HTTP_UNSUPPORTED_CAPABILITY提醒Agent删掉字段或改用别的表达。

Timeout、取消和请求状态

delayMs发生在任何网络I/O之前,而且不计入timeoutMs

flowchart LR
    A[Tool开始] --> B[delayMs]
    B --> C[启动timeoutMs]
    C --> D[连接/上传/等待Header/读Body]
    D --> E[完成或取消]

Pi传入的AbortSignal在Delay和网络阶段都有效。调用开始前Signal已经Abort时,必须保持not_sent,不能创建一次看似发生过的网络事务。

requestState.outcome是重试判断的核心:

outcome含义
not_sent没有发出网络事务,可在修正参数后重试
sent_no_response已发送,但没有拿到响应Header
response_received已收到Header,可能在读Body或下载阶段失败

同时记录:

  • networkTransactions
  • initialRequestStarted
  • uploadedBytes
  • responseHeadersReceived

这样Agent不需要仅凭错误文案猜请求是否可能已经产生副作用。

Response

详情级别

response.details返回内容
compactStatus、最终URL、请求状态、选中的Header和Body
standard再加Timing、传输统计、Hash和Redirect次数
diagnostic再加规范化请求、每跳Redirect、Proxy/TLS摘要和连接字段

默认compact,需要排查连接或完整请求语义时才用diagnostic,避免长期浪费Context。

Body模式

response.mode行为
auto根据Content-Type决定UTF-8或Base64
text按UTF-8返回
base64保留为Base64
discard读取并丢弃,不把内容放进结果

Body只出现一次:

body.content

不再同时生成一份自然语言Summary和一份结构化Body,避免重复占Token。

response.headers可以是:

  • all
  • none
  • Header名称数组,大小写不敏感。

结果继续使用{name,value}[]。重复Set-Cookie必须逐条保留;其它重复Header受Fetch/Undici规范化影响,可能显示为逗号合并值。

可观测性边界

诊断结果中的这些字段目前可能是null

  • HTTP Version;
  • Remote/Local Address和Port;
  • IP Version;
  • TLS Protocol和Cipher;
  • Wire Bytes。

原因是当前Undici层没有可靠暴露它们。宁可返回null,不能用推测值冒充实际观测。

完整报文与模型输出

这是0.2里最重要的修复之一。

Pi Tool返回:

return {
    content: [{ type: "text", text: modelOutput.text }],
    details: result.details,
};

模型实际依赖contentdetails主要供UI和程序化消费,不能认为模型一定可以看到它。

所以正常情况下,content直接放一份完整、合法、符合所选详情级别的JSON。不能只放Summary,否则用户要求完整报文时,Agent仍只看得到摘要。

两个完全不同的大小限制

Response捕获限制

response.maxBytes限制从Response Body捕获到结果中的原始字节,默认和上限都是Pi的DEFAULT_MAX_BYTES,当前为50 KiB。

达到上限时:

  • body.captureTruncated=true
  • Hash只覆盖捕获字节,hashScope=captured
  • 这是网络读取/模型上下文层面的主动限制。

如果Body本身很大且确实要完整内容,应使用download.path,而不是增大模型内联结果。

Tool模型输出限制

完整JSON即使Body不大,也可能因为Diagnostic、Header或Base64膨胀超过Pi预算。

此时model-output.ts不会截断JSON:

flowchart TD
    A[序列化完整结果] --> B{不超过Pi输出预算?}
    B -->|是| C[直接写入content]
    B -->|否| D[写同目录临时文件]
    D --> E[Rename到.pi-http-results]
    E --> F[content只返回绝对路径和字节数]

首选目录:

<ctx.cwd>/.pi-http-results/http-result-<timestamp>-<uuid>.json

如果当前工作目录不可写,回退到:

<os.tmpdir>/pi-http-results/

权限:目录0700,文件0600。写入先使用.tmp,完成后Rename,失败清理临时文件。

这里的结果是“落盘而不是截断”,所以body.outputTruncated保持false。模型得到路径后应读取文件继续分析。

注意.pi-http-results可能包含Header、Cookie、Token和Body等敏感数据,使用后按需清理。

下载

大文件或二进制文件使用:

{
  "url": "https://example.com/archive.zip",
  "download": {
    "path": "./downloads/archive.zip",
    "overwrite": false,
    "maxBytes": 104857600
  }
}

下载行为:

  • Response Stream直接写文件;
  • 自动创建父目录;
  • 默认不覆盖;
  • 写同目录临时文件,完整结束后Rename;
  • 允许覆盖时也不会先破坏原文件;
  • Timeout、Abort、Body错误或超过download.maxBytes都会清理Partial File;
  • 返回绝对路径、实际字节数和SHA-256;
  • HTTP 404/500正文也可能被成功下载,必须另外检查Status。

两个并发请求写同一路径且都设置overwrite=true时仍是Last Writer Wins。当前没有按路径加Mutation Queue。

错误模型

所有本地/传输错误都是HttpToolError,包含:

interface HttpToolErrorDetails {
    code: string;
    phase: "delay" | "prepare" | "resolve" | "connect" | "proxy" |
           "tls" | "upload" | "headers" | "body" | "download";
    message: string;
    elapsedMs: number;
    requestState: RequestState;
    issues?: HttpIssue[];
    causeCode?: string;
}

参数预检会集中返回issues[],尽量让Agent一次修完,不要修一个再暴露下一个。底层Undici错误通过causeCode保留稳定原因,例如证书或DNS错误。

HTTP 4xx/5xx不进入这里:

flowchart TD
    A[请求结果] --> B{是否收到有效HTTP Response?}
    B -->|是| C[无论2xx/4xx/5xx都返回HttpResult]
    B -->|否| D[按阶段和原因生成HttpToolError]

重试为什么写在Prompt里

每个错误结果里重复塞完整重试说明会浪费Token,而且重试策略本来就是Tool使用规范。现在统一写在promptGuidelines,错误只返回状态、Cause和必要Issue。

通用规则:

  1. outcome=not_sent:修正所有问题后可以重试;
  2. HTTP_ABORTED:不得自动重试;
  3. 已发送请求:只有安全/幂等Method最多自动重试一次;
  4. 禁止自动重放可能有副作用的POST/PATCH等请求;
  5. Extension自身不隐藏Retry,是否重试由Agent显式决定。

参数可修正错误都有对应建议:

错误建议方向
HTTP_INVALID_BODY按issues修正Body,只留一个body.type
HTTP_INVALID_HEADERS修正Header、长度或冲突
HTTP_INVALID_URL修正URL、Query、Target或Redirect
HTTP_INVALID_AUTH修正Auth或Authorization冲突
HTTP_INVALID_COOKIES修正Cookie值、文件或Jar路径
HTTP_INVALID_CONNECTION修正连接、代理或证书密钥配对
HTTP_INVALID_DOWNLOAD修正Download与Response字段冲突
HTTP_FILE_ERROR修正不可读的上传路径
HTTP_UPLOAD_FAILED修正上传源,再判断能否安全重放
HTTP_TIMEOUT调整timeoutMsconnectTimeoutMs
HTTP_DNS_FAILED修正Host或Proxy
HTTP_CONNECT_FAILED修正Host、Port、Proxy或noProxy
HTTP_PROXY_FAILED修正代理URL、凭据、Header或noProxy
HTTP_TLS_FAILED修正CA/客户端证书,或按条件关闭校验
HTTP_REQUEST_FAILED检查Cause和请求/连接参数
HTTP_RESPONSE_FAILED解码问题可尝试decompress=false
HTTP_REDIRECT_LIMIT确认必要后增加最大跳转数
HTTP_REDIRECT_DISALLOWED允许时改followmanual
HTTP_REDIRECT_PROTOCOLmanual或修正目标协议
HTTP_REDIRECT_LOOPmanual或修正循环
HTTP_RESPONSE_TOO_LARGE调整或移除下载大小限制
HTTP_DOWNLOAD_FAILED修正下载路径和覆盖策略
HTTP_UNSUPPORTED_CAPABILITY删除字段或换成可支持的表达

TLS失败的特殊建议

只在下面条件同时成立时,Agent才应自动尝试一次:

  • 错误是HTTP_TLS_FAILED
  • 使用的是默认服务端证书校验;
  • 用户并未要求严格证书验证;
  • 请求满足重放安全规则。

重试参数:

{ "tls": { "insecure": true } }

如果用户明确要求验证CA、Hostname或mTLS,不能用insecure=true掩盖问题。

Prompt和Schema预算

Tool Prompt已经改为中文,并压缩成五条共享规则。原因不是面向用户显示,而是每轮Agent都可能携带这些内容,冗长英文会持续消耗Context。

当前要守住的预算回归:

  • 生成后的Tool Schema约7413 Bytes;
  • Prompt Guidelines约2251 Bytes;
  • Typical Compact Result有单独测试;
  • Oversized Result落盘和不可写CWD回退都有测试。

以后加参数时不要只看实现复杂度,也要检查Schema和Prompt的常驻Token成本。参数重试建议集中在agent-guidance.ts,不要复制进每个错误JSON。

测试

测试不Mock Fetch,使用本地真实Server、Socket、TLS和Proxy,更接近HTTP Core Contract Test。

当前45个测试主要覆盖:

  • 六类Body、重复Form字段和大文件流式上传;
  • 精确Multipart、Filename和Header;
  • 多问题预检、旧0.1参数拒绝、重复顶层Header拒绝;
  • HTTP 4xx/5xx正常返回;
  • 301/302/303/307/308、Loop、Limit和跨Origin凭据;
  • Cookie规则、Cookie文件、Jar持久化;
  • Delay、连接/Body阶段Timeout和不同阶段Abort;
  • 二进制、Hash、捕获限制、Header筛选和Discard;
  • Raw Undici解压控制与无Body状态;
  • 原子下载、拒绝覆盖和超限Partial清理;
  • 自签名TLS、CA参数和CONNECT Proxy TLS;
  • 独立Dispatcher,不受Pi全局Fetch Dispatcher影响;
  • 显式代理、Proxy Header、逐跳noProxy和环境变量隔离;
  • DNS、连接、代理错误分类;
  • 不支持能力明确拒绝;
  • 模型实际看到完整JSON,超限结果落盘;
  • CWD不可写时回退系统临时目录;
  • Schema、Prompt和典型结果大小预算。

测试命令:

npm run typecheck
npm test
npm audit
npm pack --dry-run

本地加载:

pi -e .

发布前不能只运行源码测试,还要解包tarball、只装Production Dependency,再用Pi官方Loader实际加载一次。这样才能发现files白名单漏文件、Peer Dependency或运行时导入问题。

Package

配置当前值
Name@evalexp/pi-http
Version0.2.0
ModuleESM
Node>=22.19.0
Runtime Dependencyundici@8.9.0
Peer DependencyPi Coding Agent、TypeBox
TestsVitest
Type CheckTypeScript tsc --noEmit
Publish AccessPublic

Package直接发布TypeScript,由Pi负责加载。files白名单必须包含全部运行时代码:

index.ts
request.ts
request-body.ts
request-types.ts
agent-guidance.ts
model-output.ts
cookie-store.ts
file-stream.ts
pi-transport.ts
response-body.ts
README.md
CHANGELOG.md
LICENSE

测试Server、测试代码和TLS Fixture不进入npm包。

安全边界

这个Tool同时拥有Pi进程的网络和文件权限:

  • 能访问localhost、内网和宿主可访问的服务,天然具有SSRF式能力;
  • 上传文件可以读取Pi进程有权限读取的本地内容;
  • 下载可以创建文件,overwrite=true可以替换目标;
  • Cookie、Authorization、代理凭据和完整响应可能进入Tool Result或.pi-http-results
  • tls.insecure=true会放弃服务端身份校验;
  • 远端响应本身可能包含Prompt Injection。

安全默认值继续保持:

  • 不自动读取代理环境变量;
  • 不默认跨Origin转发敏感Header;
  • 不默认覆盖下载文件;
  • 不自动关闭TLS校验;
  • 不自动重试已发送的副作用请求;
  • 不在失败后保留Partial Download。

当前边界

  • 不是Raw TCP/HTTP客户端;
  • 顶层重复Request Header不能字节精确保留;
  • 文本统一按UTF-8,没有完整Charset转换;
  • auto模式依赖Content-Type判断文本或二进制;
  • 某些连接和TLS细节无法由Undici可靠观测;
  • 单次调用有Cookie Jar,但没有跨调用Session;
  • 不在Extension内部做自动Retry;
  • 同路径并发覆盖仍是Last Writer Wins;
  • 完整模型结果可落盘,但内联Body捕获本身仍有50 KiB限制;真正的大响应必须下载。

维护检查表

以后修改至少确认:

  • 没有引入Bun或运行时探测;
  • 代码在Pi实际Node运行时和官方Loader中可用;
  • 每次调用仍使用独立Undici Dispatcher;
  • Proxy、TLS和noProxy在每个Redirect Hop正确生效;
  • Dispatcher清理错误不覆盖Primary Error;
  • index.ts只做Pi Adapter;
  • 0.1旧参数仍明确拒绝;
  • 无法实现的功能不静默忽略;
  • 非2xx仍作为正常HTTP结果;
  • Abort、Timeout、DNS、Connect、Proxy、TLS错误仍可区分;
  • requestState.outcome和实际发送状态一致;
  • Agent能从content看到结果,不能只依赖details
  • 输出超限时完整落盘,不截断JSON;
  • 上传和下载保持流式;
  • 下载仍然临时写入、原子Rename、失败清理;
  • Cookie Jar写回保持原子性;
  • Prompt与参数说明保持精简中文;
  • 所有可改参数修复的错误都有重试建议;
  • 已发送副作用请求不会被自动重放;
  • Schema、Prompt和典型输出没有明显膨胀;
  • package.json files覆盖所有运行时文件;
  • 没有遗留调试日志或固定/tmp调试路径;
  • Bug Fix不要再改0.2.0版本号;
  • Type Check、45项测试、Audit、Pack和Pi实际加载全部通过。

问题快速定位

问题先看
Pi加载失败、Bun is not defined一类问题package.jsonpi-transport.ts及所有运行时Import
Agent没有选择http Toolindex.ts的Description、agent-guidance.ts
Schema不对或Token增长index.tscontract-size.test.ts
参数未一次报全request.ts的预检逻辑
Body或Multipart字节不对request-body.ts
文件上传失败或内存增长file-stream.tsrequest-body.ts
TLS、Proxy、CONNECT不生效pi-transport.ts
Redirect方法或凭据异常request.ts的逐跳逻辑
Cookie丢失或Jar异常cookie-store.ts
Timeout/Abort状态不对request.tsRequestState
Response编码、Hash、Header异常response-body.ts
用户要求完整报文但模型只见Summaryindex.tsmodel-output.ts
输出被截断或落盘失败model-output.tscontract-size.test.ts
下载覆盖或残留Partial Fileresponse-body.ts
Agent没有按错误调整参数agent-guidance.ts
npm包运行时缺文件package.json files和解包后的Pi Loader测试

参考