@evalexp/pi-http

Structured HTTP request tool adapted for Pi Coding Agent

Packages

Package details

extension

Install @evalexp/pi-http from npm and Pi will load the resources declared by the package manifest.

$ pi install npm:@evalexp/pi-http
Package
@evalexp/pi-http
Version
0.2.0
Published
Sep 3, 2026
Downloads
321/mo · 21/wk
Author
evalexp
License
MIT
Types
extension
Size
92.6 KB
Dependencies
1 dependency · 2 peers
Pi manifest JSON
{
  "extensions": [
    "./index.ts"
  ]
}

Security note

Pi packages can execute code and influence agent behavior. Review the source before installing third-party packages.

README

@evalexp/pi-http

A Pi Coding Agent extension for one structured HTTP(S) request per tool call. It uses its own per-request Undici dispatcher, so explicit proxy and TLS settings work independently of Pi's installed global fetch dispatcher. Inputs are literal JSON values, results state what the client actually observed, and no shell or curl syntax is interpreted.

一个适配 Pi Coding Agent 的 HTTP(S) 扩展。扩展为每次请求创建独立的 Undici dispatcher,使显式代理和 TLS 设置不受 Pi 全局 fetch dispatcher 影响。每次工具调用只描述一次请求;输入是字面 JSON 值,结果只陈述客户端真实可见的信息,不解析 shell 或 curl 语法。

English

Runtime and installation

  • Node.js 22.19.0 or newer (the runtime required by Pi Coding Agent)
  • Pi with package installation support
pi install npm:@evalexp/pi-http

For local development:

npm install
npm test
pi -e .

Request model

Only url is required. The method defaults to GET, or POST when body is present.

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

Headers and query fields are ordered arrays. Query names may repeat. The Fetch header model combines repeated top-level request headers before transmission, so the extension rejects those inputs with HTTP_UNSUPPORTED_CAPABILITY instead of silently changing them; multipart part headers remain byte-exact and may repeat.

{
  "url": "https://api.example.com/items?before=0",
  "headers": [{ "name": "X-Trace", "value": "a" }],
  "query": [
    { "name": "tag", "value": "one" },
    { "name": "tag", "value": "two" }
  ]
}

body is one discriminated object:

{ "url": "https://example.com/text", "body": { "type": "text", "value": "literal $HOME\\n" } }
{ "url": "https://example.com/data", "body": { "type": "base64", "value": "AAEC/w==" } }
{ "url": "https://example.com/json", "body": { "type": "json", "value": { "name": "Pi" } } }
{
  "url": "https://example.com/form",
  "body": {
    "type": "form",
    "entries": [{ "name": "role", "value": "a" }, { "name": "role", "value": "b" }]
  }
}
{ "url": "https://example.com/upload", "body": { "type": "file", "path": "./archive.bin" } }

Paths are resolved from Pi's current working directory. Their full value is a path; @ has no special meaning. File bodies and multipart file parts are streamed.

Multipart

Parts retain array order and may repeat names. An explicit filename is not cleaned or converted to a basename.

{
  "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",
        "contentType": "text/plain",
        "content": { "type": "file", "path": "./report.txt" }
      }
    ]
  }
}

Structured part headers retain order. rawHeaderLines instead emits the supplied multipart header lines literally; it is mutually exclusive with headers. For complete control of preamble, separators, binary content or epilogue, construct the whole body with body.type=base64 and set the top-level Content-Type explicitly.

Body bytes and multipart bytes can be exact. The tool is not a raw TCP client: Undici still owns the request line, HTTP header encoding, framing, connection reuse and protocol negotiation.

Authentication, cookies and redirects

{
  "url": "https://api.example.com/private",
  "auth": { "type": "bearer", "token": "token-value" },
  "cookies": { "file": "./cookies.txt", "jarPath": "./cookies-after.txt" },
  "redirect": { "mode": "follow", "max": 5, "protocols": ["https"] }
}

Basic credentials are UTF-8 encoded before Base64. A Cookie Jar exists only for the current call and its redirect chain. Cookie files use Netscape format and jar writes replace atomically. Cross-origin redirects strip explicit Authorization, Proxy-Authorization, and Cookie by default; set redirect.trusted=true only when forwarding them is intended.

Redirect modes are follow, manual, and error. Following is implemented hop by hop, with loop and limit detection. preserveMethod may contain 301, 302, or 303; 307 and 308 preserve method/body normally.

Proxy, TLS and transfer controls

{
  "url": "https://example.com/large.bin",
  "connection": {
    "proxy": "http://proxy.example:8080",
    "proxyHeaders": [{ "name": "Proxy-Authorization", "value": "Bearer value" }],
    "noProxy": ["localhost", ".internal.example:8443"]
  },
  "tls": { "caFile": "./private-ca.pem" },
  "transfer": { "decompress": false, "range": "0-1023" },
  "response": { "mode": "base64", "details": "standard" }
}

Proxy use is explicit; proxy environment variables are not inherited. noProxy accepts *, exact hosts, dot-prefixed domain suffixes, and optional ports. proxyHeaders are passed only to Undici's proxy agent and are not target headers. tls.caFile replaces Node's default trust input for this request; clientCert and clientKey must be paired. tls.insecure=true disables server certificate verification only.

The Pi transport supports a separate connectTimeoutMs and HTTP/1.1 preference. It does not currently expose faithful resolve, connectTo, IP-family forcing, an independent requestTarget, or path-as-is controls. It also rejects GET/HEAD request bodies. Supplying unsupported options returns HTTP_UNSUPPORTED_CAPABILITY; they are never ignored.

Response and downloads

response.mode is auto (default), text, base64, or discard. response.headers is all, none, or a case-insensitive list. Detail levels are:

  • compact: status, final URL, request state, selected headers, and one body value;
  • standard: also timing, transfer statistics, hash, and redirect count;
  • diagnostic: also normalized request, redirect hops, proxy/TLS summary, and observable connection fields.

The model receives one valid JSON result at the selected detail level. The body appears once, in body.content; structured details mirror the result for UI use but are not relied on as model context. If the complete JSON exceeds Pi's model-output budget, it is saved without truncation under .pi-http-results/ in the current working directory, with the OS temporary directory as a fallback when the working directory is not writable. The model receives its absolute path and byte count. A capture limit marks captureTruncated=true and hashes the captured bytes. Socket, HTTP version, and wire-byte fields remain null when Undici does not expose them through this layer. Repeated Set-Cookie values remain individual; other repeated response fields may be presented in normalized comma-combined form.

Use a download object for streamed, atomic output:

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

Downloads do not overwrite by default. Failure, timeout, cancellation, or a size-limit violation removes the temporary file. HTTP 4xx/5xx responses remain normal results.

Timing and errors

delayMs occurs before network I/O and is excluded from timeoutMs. Both delay and request phases respond to cancellation. Standard timing uses a monotonic clock and separates delay, redirects, response headers, body reading, request, and total duration.

Errors are HttpToolError values with stable code, phase, elapsedMs, and requestState. The model-visible message is compact: it includes state, the stable cause code when available, and concise preflight issue lines rather than repeating the full details JSON. Shared tool instructions map every parameter-correctable error to the relevant fields, including bodies, headers, URLs, auth, cookies, connection/proxy/TLS, timeouts, redirects, upload/download paths, limits, and unsupported transport controls. Retry safety remains centralized: retry not_sent failures after correction; never retry cancellation; retry default-verification TLS failure once with tls.insecure=true unless strict verification was required; and only replay sent requests when the method is safe/idempotent. The extension itself never hides a retry.

中文

运行与接口

要求 Pi Coding Agent 所需的 Node.js 22.19.0 或更高版本。安装后,最简单的 GET 只需要:

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

存在 body 时默认方法为 POST。headersquery 和表单字段统一使用有序的 {name,value} 数组;query、表单和 multipart Header 可以表达重复名称,顶层请求 Header 重复时会明确拒绝。请求体只能选择一种带 type 的结构:textbase64jsonformfilemultipart。所有字符串均按 JSON 解析后的字面值使用,不展开变量、反斜线、glob、命令替换,也不识别 @path

文件请求体和 multipart 文件 part 均流式读取。multipart 保持 part、Header 和重复名称的顺序;显式 filename 不做 basename、路径清理或 Unicode 改写。需要完全控制 multipart Body 时,使用 body.type=base64 并显式提供顶层 Content-Type。

这里的“精确”指 Body 字节精确;请求行、顶层 Header 编码、HTTP framing、协议协商和连接复用仍由 Undici 管理,本工具不是 raw HTTP/TCP 客户端。

通用控制

  • auth 支持 Basic 与 Bearer;
  • cookies 支持显式值、Netscape 文件和原子 jar 输出,状态只存在于本次调用;
  • redirect 支持 follow/manual/error、次数、协议白名单、方法保留和跨 origin 敏感 Header 策略;
  • connection 支持 Undici HTTP/HTTPS 代理、代理专用 Header、noProxy 和独立连接超时;
  • tls 支持自定义 CA、mTLS 与显式 insecure
  • transfer 支持自动解压开关和 Range;
  • download 流式写入同目录临时文件,再原子落盘,失败时清理;
  • response 支持 auto/text/base64/discard、Header 过滤及 compact/standard/diagnostic 三档详情。

Pi 传输层当前无法忠实暴露的逐请求 DNS 覆盖、连接目标覆盖、IP 族强制、独立 request target 与 path-as-is 会明确返回 HTTP_UNSUPPORTED_CAPABILITY,不会静默忽略。connectTimeoutMs 和 HTTP/1.1 偏好可用。

delayMs 位于网络阶段之前,不计入 timeoutMs。参数错误会在发送前集中返回 issues[];模型可见错误只包含紧凑的状态、稳定 cause code 和逐项参数问题,不重复完整 details JSON。共享工具提示为每个可通过参数修正的错误码指出相关字段,覆盖 Body、Header、URL、认证、Cookie、连接/代理/TLS、超时、跳转、上传/下载路径、大小限制和传输层不支持的控制项。统一安全规则仍然适用:not_sent 修正后重试;取消不自动重试;默认 TLS 校验失败可用 tls.insecure=true 重试一次;其他已发送请求只在方法安全、幂等时重试。扩展内部不隐藏重试。

模型会收到与所选详情级别对应的单个有效 JSON 结果,响应 Body 只在 body.content 中出现一次。若完整结果超过 Pi 的模型输出预算,则不截断内容,而是将完整 JSON 原子写入当前工作目录下的 .pi-http-results/;工作目录不可写时回退到系统临时目录。模型会收到绝对路径和字节数。UI 使用的结构化 details 不作为模型能够读取响应内容的前提。

安全

该扩展拥有 Pi 进程的网络和文件权限。请核对上传路径、下载目标、代理凭据和 TLS 配置。.pi-http-results/ 可能保存响应 Header、Cookie 和 Body 等敏感内容,应按需清理。tls.insecure=true 会关闭服务端证书校验,只应在明确接受风险时使用。

发布前可运行:

npm test
npm pack --dry-run

Released under the MIT License.