Skip to content

Releases

PI 0.1.6(pi 1.3.0)· 富渲染

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 05 Nov 15:40

引擎:@earendil-works/pi-coding-agent 1.3.0(与上一包相同)。

从 v0.1.5 到这里共 99 笔提交。这一版是一个大功能:富渲染。代码块不再只是等宽文字——Mermaid、公式、JSON/XML/YAML 树、CSV、堆栈、HTML、SVG、动图都能画出来。


富渲染

聊天里的围栏代码块按内容分派到对应的渲染器,源码随时可切回来看。

Mermaid 图表。 在离屏 WebView 里跑 mermaid 12.2.0,输出 SVG 经清洗后由 AndroidSVG 画成矢量图,可 1×–8× 缩放。共享一个宿主、串行有界队列、同 cacheKey 合并请求、LRU 缓存、超时后重建,渲染进程被杀也不带崩 App。旧版的 ASCII 降级路径保留为运行时回退。

数学公式。 MathJax 真排版,显示式与行内式都走它。渲染结果 LRU 缓存、状态可保存、占位固定高度——不会因为公式落笔而跳版。

JSON / XML / YAML 树。 后台解析并缓存,整行点击展开,缩进参考线,子节点分页,深层缩进封顶保证深嵌套仍有内容宽度。展开状态可保存,不随流式重置。

CSV / TSV 表格。 RFC 4180 解析(引号、字段内换行、CRLF 全认),表头冻结、横滑、数值列右对齐、隔行淡底、单元格可复制。

堆栈跟踪。 识别常见语言格式,函数名可换行,库帧调淡,消息可展开,分页。

安全 HTML 块。 jsoup 解析 + 白名单重建:危险标签整棵子树丢弃、URL 协议校验、三层上限。流式、拒绝或超限时原样回退源码。<details> 状态可保存,<hr> 变淡,引用去掉合成斜体。

SVG。 独立围栏、HTML 里夹的 <svg>、以及裸 SVG 链接都交给 SVG 渲染器;动画 SVG(SMIL / CSS)可播放。

脚注与链接卡片。 脚注保留未引用的定义;链接渲染成卡片,长按复制,流式末段不画卡片。

围栏别名与内容嗅探。 mmd / latex / geojson / rss 等别名认了;没标语言的块按内容猜 svg / xml / mermaid / json。

公共卡片语言

所有富内容共用一套卡片:胶囊标题 + 复制图标 + 右上角 ⋮ 菜单,统一的卡片头、分隔线、折叠条、状态位。工具栏不再摊在正文里,低频动作收进 ⋮。树与 CSV 的「源码 ↔ 视图」切换也并入卡片头。

动图与媒体

  • URL 动图(GIF / WebP / APNG)与动画 SVG 可播放,随生命周期暂停,限制并发
  • 图片查看器支持动图播放与 SVG 打开
  • 音频、视频链接渲染成播放卡片
  • 远程图片带常规 UA 与 Accept,手动跟跳转(含 http→https),认 SVG 与 AVIF 并栅格化
  • 图片加载失败时用共用卡片占位(破图图标 + alt + 缩短来源,点按复制地址),Markdown 与 HTML 一致

流式光标

回复生成时 ▍ 光标接在 Markdown 末尾,紧跟最后一个字,不占布局宽度。

排版重做

舒适档重做为母版 16/27,紧凑 15/25、宽松 17/28 按同一组比例推出;标题行高固定按比例走,不再随行距档时变时不变。

  • 用户气泡右对齐、贴内容宽度(非经典档)——单行短句不再撑满整行
  • 标题贴近正文,代码块上下对称,表格圆角与内边距统一
  • 代码块边线 100% → 28% 并铺 6% 同色淡底;分割线 100% → 35%;行内代码加 14% 淡底;h1 去掉下划线(金色 + 下划线像链接)
  • 思考块与引用去掉伪斜体(中文斜体是假斜体)
  • 经典档全部保持原样

阅读字体瘦身

从官方 SourceHanSerifCN 可变字体(25 MB,APK 内约 15 MB)裁出 wght 450 / 600 两个静态 TTF,裁到 GB2312 + 常用符号(约 7700 字形),每个 3.0 MB,合计 6.1 MB。

  • 正文 400 → 450:深色背景下宋体细笔画在 16sp 偏虚,450 更接近原来系统字体的密度
  • 粗体落在真实 600
  • 字体内部名改为 Pi Reading Serif(OFL 要求修改版不得保留 Reserved Font Name),版权与许可声明原样保留
  • 生成脚本入库 tools/build-prose-font.py,字体加入 noCompress 以便平台 mmap,只有实际绘制到的字形页驻留内存

工作区认领

点开别的工作区的会话时,App 认领那个工作区,不重启引擎——以前这一下会打断正在跑的那一轮。

编辑安全

工作区里的文件编辑补上了一整套保护:

  • 只读门槛、读原文、保留换行
  • 冲突检测:文件被别人改过就不覆盖
  • 原子写
  • 草稿恢复
  • 删除不跟随符号链接

模型页

  • 自定义厂商可以建任意多个,按名字生成不冲突的 id
  • 已配置的厂商可以再换
  • 文件里已有的自建厂商也出现在选择列表里
  • 订阅账号挪到厂商卡后面,并显示已登录数
  • 对话页选模型按厂商分段
  • 导入表单里自建厂商的名称框与 Base URL 提到 Key 前面

构建信息

引擎 @earendil-works/pi-coding-agent 1.3.0(未变)
变体 sideload28(targetSdk 28,默认选这个)
架构 arm64
安装包 151,709,389 字节(144.7 MiB)
sha256 3fb62942643a767393151f1c1dd7380b0308fb10cdeb9ea7a356512196a269ee
来源 CI run #608,commit 506d2b70

同一密钥签名,可以覆盖安装,升级不丢数据。
这一版新增了 Mermaid / MathJax / AndroidSVG / jsoup / SnakeYAML 五个依赖,许可证清单已同步。

PI 0.1.5(pi 1.3.0)· 订阅登录与界面重做

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 31 Oct 18:45

引擎:@earendil-works/pi-coding-agent 1.3.0(与上一包相同,不含引擎升级)。

从 v0.1.4 到这里共 153 笔提交。这一版是新功能 + 整体界面重做:订阅登录、配色方案、悬浮输入框、模型能力编辑、思源宋体、拆底栏、排版重定标。


新功能

订阅登录:原生 OAuth,不经过终端

以前登录订阅账号要开终端敲 pi /login。现在模型与供应商屏顶部有一张「订阅账号」卡,点进去就是完整的登录流程:

  • 清单不硬编码:直接取 pi 的 builtinProviders() 过滤 auth.oauth,pi 认几家就有几家
  • 登录就是 pi 自己的登录:调同一个 pi-ai 的 auth.oauth.login(interaction),auth_url / device_code / progress 通知直通界面
  • 按 pi 的提示画界面:设备码、浏览器链接、select / text / manual_code 四种交互全支持;粘贴整条回调地址的入口一直可见
  • 写盘走 pi 自己的规矩:PiAuthStorage.setOAuth —— 锁、0600、镜像目录、等重启标记;只校验 pi 会拒绝的那几条,其余键(accountId / enterpriseUrl / scope)原样保留
  • 失败会说话:providers() 加 20 秒超时,进程 stderr 留最后 40 行带进错误;读不到时用内置九家清单撑起页面并标明「运行时没响应」,可以重试

从订阅登进来的厂商不再显示「换 Key / 改模型」——Key 与模型清单都不是人填的,只剩「删除」。

配色方案 / 系统主题

pi 的 system 主题本来就是按调色板推导出全部 56 个 token 的。现在这个推导搬到了手机上,调色板由你选:

  • 四档预设底色:pi 默认深底 #1E1E1E、浅底 #F5F5F5、#121212、纯黑 #000000;ANSI 16 色仍是 pi 的 DEFAULT_ANSI,只换底色
  • 自定义底色:#RRGGBB 输入 + 色相/饱和度/明度三条滑杆(HSV 直改,不走 RGB 反算,修掉色相 360° 回跳与饱和度归零丢色相)
  • 色彩强度三档(素 / 标准 / 鲜艳)走 pi 推导函数的 saturation 参数
  • 拖动只预览,按「应用」才写盘:页内用真实 deriveSystemPalette 做页面 / 卡片 / 文字 / 强调四个预览块,不触发全 App 重组
  • 默认主题改成 system:底色一换,整套 56 个 token 跟着重算;明暗由底色亮度决定(这是 pi 自己的规则)
  • 修掉「整页染蓝」——页面与卡片底色改用选中的背景色本身,不再从 userMessageBg 缩放

悬浮输入框

输入框从贴着屏幕底边改成真正悬浮:

  • 12 / 8 边距、26dp 圆角、中性阴影、聚焦时描边 1.5 → 2dp、运行中呼吸
  • 6 行自适应高度
  • 工具行 32 圆形按钮 / 20 字形,引导 / 后续回到键行
  • 输入框下方不再实心铺到屏底:卡片背后实心,卡片下边缘画 24dp 的页面底色 → 透明渐隐,与上边缘对称,8dp 缝和导航条自然透出列表
  • 去掉 6dp 投影——浅色下它落在下面那行卡片上,就是输入框与导航条之间那条灰带
  • 关掉导航条系统遮罩:SystemBarStyle.auto 会在 API 29+ 把 isNavigationBarContrastEnforced 重新设成 true,覆盖 XML 的设置,浅色下系统于是在导航条上盖一层约 90% 白遮罩

模型能力:每条模型都能改

以前只有导入那一刻能设能力,之后只能看。现在导入时与导入后共用同一支表单:

  • 可调:上下文 token、最大输出 token、支持图片、输入 / 输出价、缓存读 / 写价(美元 / 百万 token)、推理
  • 留空 = 不写这个键,交还 pi 的默认(128000 / 16384 / 仅文本 / 0),与「填 0」严格区分
  • 没碰过的开关不写:只改价格不会顺手把 reasoning 或图片能力写成 false
  • 预填顺序:申报过的定义 → 引擎快照 → pi 目录(反过来会把上次改的值一打开就盖回官方值)
  • 「恢复 pi 默认」= 删掉这条申报
  • 写入只动 models[] 里同 id 的那一条,其余模型与厂商块上的未知键按 id 合并保留

models.dev 接入:自动补思考档位与缺失能力

没有任何厂商的 /models 会回思考档位——这就是以前只有一家能思考的原因。models.dev 是 pi 目录的上游(pi 自己的 generate-models.ts 就吃它),232 家厂商、几千个模型:

  • 解析 api.json → 精确 厂商/模型 + 裸 模型 id 两级索引
  • reasoning_options 按 pi 自己的 getEffortThinkingLevelMap 逐条生成 thinkingLevelMap(off/minimal/low/medium/high/xhigh/max,未支持写 null,一个都没有就不写)
  • 约 6 MB 缓存到本地、7 天有效;只在扫描回来的模型缺上下文时取一次,失败或断网就跳过,绝不让导入失败
  • 候选的元数据来源补齐为五级:目录 → 引擎 → 本次扫描 → 跨厂商目录 → models.dev

顺带修掉一批元数据采集:中转站的 /models 通常只回 id,以前一律落到 pi 默认值,看起来像随便填的。现在按语义认五家拼法——

字段 认得的写法
上下文 context_length / context_window / max_context_length(LM Studio) / max_model_len(vLLM、SGLang) / max_input_tokens / inputTokenLimit(Google) / limit.context(models.dev)
最大输出 top_provider.max_completion_tokens / max_output_tokens / max_completion_tokens / outputTokenLimit / limit.output
图片 architecture.input_modalities / capabilities.vision(Ollama、LM Studio) / modalities.input / supports_vision
思考 reasoning / supports_reasoning / supports_thinking / capabilities 里的 thinking / supported_parameters 里的 reasoning 系列
缓存价 OpenRouter pricing.input_cache_read|input_cache_write / models.dev cost.cache_read|cache_write / LiteLLM cache_read_input_token_cost

价格三种单位各按各的换算(OpenRouter per-token、models.dev per-million、LiteLLM per-token),厂商 per-token 价只在 PiScanVendorMeta 里乘一次到 per-million,表单与 models.json 都是 per-million。

跨厂商借定义:中转站转的 gpt-4o / claude-sonnet-4-5 / deepseek-chat 在 pi 随包目录里本来就有真数据,只是不在这一家的文件里。精确 id 与 vendor/model 两种拼法都试——但价格不跨厂商借,定价不是一回事。

  • 采样参数:OpenRouter 的 default_parameters(468 个模型里 271 个有)读成 pi 的 samplingParams 原样写进模型定义——那是厂商给的默认值,不是替它调参
  • 接回「切换到下一个模型」:切完立刻更新 meta.model 并提示「已切到 <名字>(provider)」,没得循环时明说

思源宋体:聊天正文换字体

  • 随包内置 Source Han Serif(OFL-1.1),最终采用官方 CN 可变字体,只保留 wght 400/600 两档,SemiBold 注册为 Bold —— **粗体** 用真实 600,不再是合成加粗
  • 从全量 SC 静态双字重(49.2 MB / APK +40.3 MB)瘦身到 CN 子集可变字体(25.1 MB / APK 约 +15.5 MB)
  • 只作用于聊天 Markdown 正文:标题、引用、列表、表格用宋体;行内代码与代码块仍是 JetBrains Mono;界面文字仍是系统 Sans
  • 列表圆点改用界面字体——思源宋体的全宽 U+2022 会把列表正文整体右移
  • 许可证全文、组件清单、生成器 pin 同步更新

UI 一致性门禁(CI)

新增三条规则,无 JDK、无 SDK,纯 grep / sed / awk:

  1. 硬失败:只有 PiSheet.kt 能调 ModalBottomSheet
  2. 棘轮:按文件的 MaterialTheme.typography 计数只许降不许升
  3. 棘轮:screens / chat / settings 的裸 .dp / .sp 总数对着基线只许降不许升

界面重做

导航:拆掉底栏

  • Scaffold 不再有 bottomBar,底栏组件与图标集整套删除
  • 工作区 / 设置改走顶栏入口;对话页 ⋯ 菜单末尾也加了这两项
  • 关闭 ✕ 换成左侧返回箭头,退回行为不变
  • 返回键按条件互斥:覆盖层开着先关覆盖层,否则按设置栈逐级回退
  • 底栏拆掉后底距自动变成系统导航条 inset;全程只有 Scaffold 一处 imePadding

弹层统一:PiSheet

新增全 App 唯一弹层外壳 PiSheet:顶部圆角 20、36×3 把手、遮罩 0x8C000000、surfaceContainerHigh 底、一次展开。聊天的六个 sheet(模型选择 / 思考等级 / 会话工具 / 上下文 / 会话统计 / 分叉选择)全部换壳,设置的三处弹层也并了进来。

顶栏

  • 共享 PiTopBar:56 高、16 SemiBold 标题、48 热区 + 24 字形、圆形按压区
  • 颜色从 surfaceDim 改为页面底色(pi 的 pageBg),修掉浅色主题下状态栏那条色块
  • 发丝线与 12dp 渐隐只在滚动时出现,停下即收回
  • 对话页删掉模型 chip,右侧只剩搜索 / 工作区 / ⋮,标题拿回完整会话名的宽度

排版:四档全部重新定标

  • 经典档不再是「最挤最细」那一档:正文从 14/23 字重 400 改为 15/24 500,块距、列表、缩进、消息间隙、行内代码全部对齐舒适档
  • 列表:紧凑/舒适/宽松项上下内边距 4/8/8 → 3/4/5,项间实际 6/8/10
  • 分割线:非经典 0.75dp、上下各加 4dp,总间距 12/16/24;经典 1dp 不加
  • 标题:h1–h6 额外上边距 16/12/8/4(首块、或前一块也是标题时不叠加);h1 去掉下划线,靠字号与字重分层
  • 标题行高:舒适 25/30…17/22,紧凑/宽松同比例,经典保持原密度
  • 行内代码:字重 600 → 500
  • 表格:列宽不再固定 160,按可用宽拟合(最小 120,低于才横滑并画右缘渐隐);表头底色裁上圆角

会话页

  • 搜索框默认收起,顶栏加放大镜(展开动画 + 自动聚焦),把常驻的 48dp 还给列表
  • 分段控件、筛选 chip、筛后条数合成一行
  • 行改两行:标题 + 相对时间 /「模型 · N条」+ 按需出现的标签
  • 当前会话标识改版:描边胶囊 → 行底 selectedBg 35% + 左缘 3dp 主色竖条 + 标题 SemiBold
  • 卡内行间线 1dp 不透明 → 0.5dp outlineVariant
  • 新建按钮改用主题容器色

工作区:拆成两页

  • 顶栏只留返回 + 标题 + 刷新 / ⋯;引擎状态行删除,两段常驻说明挪进 ⋯ →「关于工作区」
  • 新增**「文件 / 资源」分段**
  • 文件页:目录卡压成芯片、面包屑只显示最后三级(前面折成可点的省略号)、文件名改无衬线 15/Medium、图标放进 32dp 圆角底
  • 资源页:技能/提示词/扩展/主题改成带计数的 chip,按来源分组,描述最多两行,行尾动作改成「复制名字」
  • 图标列统一 32dp 圆角底,行间线对齐到文字列;等宽只留给路径与命令
  • 修 YAML:description 的 | / > / >- 块标量按缩进取正文,不再把标记符当描述

模型页

  • 一屏收口:导入按钮上移、厂商卡头直接显示「N 个模型 · x 可用 · y 缺凭证 · z 等待重启」
  • 导入页分节、能力收成 chip、默认值说明从每行重复改为列表上方出现一次、手动模型名默认收起
  • 「pi 目录里有」不再每行重复;扫描与保存改成真按钮
  • 删掉**「本地模型(llama.cpp)」按钮**——它和「导入模型」是同一个 sheet,只是预选一档;手机上本来也跑不了 llama.cpp(pi 的 /llama 只在 TUI 里工作)
  • 凭证区加「移除」:只删 Key,保留厂商块与模型
  • 默认模型 / 默认厂商 / 循环模型三行收进同一张卡
  • 候选列表改懒加载、一次最多画 500 行(覆盖 OpenRouter 的约 470 个端点)

设置

  • 整块移除设置搜索(页面、入口、注册表 search API、测试一并删掉)
  • 首页重排:高频在上、与 pi 无关的合并到底部;安全与隐私、开源许可收进「其他」
  • 主题改成全屏选择、跟随系统改为列表
  • 统一卡片与行组件,去掉分组标题与文字尾巴;长文本行只显示字数,值封顶 40%

系统主题调色页

  • 三条色相/饱和度/明度滑杆改用 M3 Slider:游标居中、可拖、两端可达、48dp 触摸高度
  • 滑杆直接改 HSV,修掉色相 360° 回跳 0、饱和度为 0 或明度为 0 时丢色相
  • 页面重排:常用底色 → 三条滑杆(带数值读数)→ 色彩强度 → HEX → 应用

修复

  • 触底跟随锚点:pinToTail 以 viewportEndOffset - contentPadding.bottom 为列表终点,不再把屏幕底边当终点;流式越过输入框安全区的情况加了反例测试
  • 顶栏颜色:surfaceDim → background,状态栏透明时顶栏与页面同面
  • 订阅状态读错文件:引擎把 agentDir 绑到持久那份,/login 与订阅登录写的是镜像里的 auth.json,此前只读「优先 primary」那份会看不见 oauth 条目
  • 订阅登录失败信息:Node 的 fetch failed 把真正原因藏在 error.cause(ENOTFOUND / ECONNREFUSED / 证书),现在最多三层 cause 与 code 拼进错误信息
  • 新会话被顶掉:不再被「第一个 scoped 模型」抢占默认模型
  • 编辑官方模型:不再抹掉思考档位与采样参数;6 MB 的 models.dev 下载不再卡住扫描;Key 去空白
  • 删除厂商/模型:立刻从清单消失,不用等引擎重启;删厂商时清掉指向它的默认与循环条目
  • 两个开关点了没反应(推理设置);思考等级不再提供 off,默认显示 pi 的 medium
  • 工作区新建:落在当前层,不再拼 rootfs 相对路径;名字输入框改 48 高并带占位与校验
  • 错误卡去描边,保留错误底色与左侧色条
  • 思考卡去掉右侧「展开」+ 箭头,整块仍是点按切换
  • 回到底部按钮:视觉 36 / 点击 48;下箭头只在离开底部时出现,视觉底边在输入框顶边上方 12;上箭头约两屏后才出现
  • 清理重构后没有调用方的东西,扫掉过期注释

构建信息

引擎 @earendil-works/pi-coding-agent 1.3.0(未变)
变体 sideload28(targetSdk 28,默认选这个)
架构 arm64
安装包 157,701,973 字节(150.4 MiB)
sha256 5e8a4540f87ae40723f66ed650c3ddc62e1e997aa514c782d850f4617108bb83
来源 CI run #559,commit f2875ea6

同一密钥签名,可以覆盖安装,升级不丢数据。
这一版 APK 比上一版大 约 15 MiB,是内置的思源宋体 CN 可变字体。

PI 0.1.4(pi 1.3.0)· 设备桥 v2

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 19 Oct 11:10

引擎:@earendil-works/pi-coding-agent 1.3.0(与上一包相同,不含引擎升级)。

从 v0.1.3(313309f)到这里共 17 笔提交。这一版的主线是设备桥重做——工具面从 26 个砍到 7 个,四组能力被删掉,动作开始自带反馈。


设备桥 v2:26 个工具 → 7 个

原来那份工具面的问题很具体:26 个工具的描述合计 1.2 万字(≈4k token/轮),而其中大半是同一个能力的别名——ui / ui_dump / tap / swipe / input / key / screenshot 七个工具讲的是同一块屏幕,io / fs / files / files_list / download 五个讲的是同一批文件。

现在是一个工具一个闭集 action:

工具 action
android_status (无,常驻)
android_screen look / tap / type / swipe / key / wait / shot / steps
android_app list / launch / stop
android_files dirs / list / read / write / download / import / export
android_shell (无)
android_comm clipboard / notify / toast / vibrate / share / open / tts
android_device battery / torch / location / sensors / sensor

省下来的正是每轮都要付的那份钱:以前每个别名都各带一份 description + promptSnippet + promptGuidelines + 完整参数 schema,现在一个端点只付一次。合并丢掉的参数精校由每个 action 自己的 [BAD_PARAM] 补回来。

结果是提示词大幅变短,而能力一点没少。

动作即反馈:点一下就告诉你变了没有

这是这一版真正的加强点。以前「点一下输入框再打字」要三次工具调用(tap → dump → input),模型在两次调用之间看不到任何反馈,点错了也不知道。

现在 tap / type / swipe / key 执行后立刻做一次界面 diff,同一份结果里给出:

{
  "changed": true,
  "screen": "com.tencent.mm",
  "added": ["发送"], "removed": [], "updated": ["输入框"],
  "text": "1 个节点出现:发送"
}
  • 界面真变了 → 列出新增/消失/变化的节点;
  • 界面没变 → changed: false,并明说「界面没变,可能没点中」,模型可以直接重试,而不是接着往下错;
  • 没有上一屏可比 → changed: null,如实说「还没有上一屏可对比」,不编一个结论。

steps:一次调用连做八步

{ "action": "steps", "steps": [
  { "action": "tap", "text": "搜索框" },
  { "action": "type", "text": "天气" },
  { "action": "key", "key": "enter" }
] }

每一步先校验 action 再动手,逐步带自己的 diff,遇错即停并说清停在第几步。上限 8 步。这样一段确定的操作序列不用再来回四次。

删掉四组能力

VPN / 输入法 / 投屏 / 自动化规则 —— 整组删除,连同它们的服务类、清单项、提示词段落、技能正文与文档条目一起清干净:

  • PiVpnService.kt、PiInputMethodService.kt、PiCaptureService.kt、PiScreenCapture.kt、PiAutomation.kt 全部移除
  • pi_input_method.xml 移除
  • 最后两处 allows / android_say 残留清掉

升级后这四项不可用,是设计决定,不是回归。

设备能力屏:1303 行 → 148 行

用户原话是「说明文字太多了」。现在收成四个状态点 + 三行开关 + 一个高级折叠,删掉 allows 字段。整个文件的净变化是 −1147 行。

权限闸门

  • danger.ts 的级别表对齐 7 个工具
  • 「按调用才危险」的两处改由新的 approvalRuleFor 判:android_shell 的 7 条不可逆命令,以及 android_app(action="stop")
  • 记住的粒度是规则 id,不是工具名
  • ShellPolicyMirrorCheck 的两条集合判据仍成立(工具名 7 = 7,硬黑名单两侧都是空)

模型可见文字统一英文

  • description 每条 ≤60 字符,只写「是什么 + action 列表」
  • promptSnippet ≤20 字符,不与 description 重复
  • promptGuidelines 只留 3 条安全规则(stop 会丢未保存内容、shell 受策略守卫、不可逆动作会二次确认)
  • 工具返回的正文仍是中文——那是给工具卡上的人看的

技能按能力组裁剪

SKILL.md(23 行)+ references/ui.md + references/env.md,正文合计 52 行。只开 basic 时不写 ui.md、索引里也没有屏幕那一行;全关时不写并删目录。上一版写过、这一版不再有的附件在写新文件前主动 rm——pi 只按目录扫盘。

diff 卡:折叠态对齐工具卡

  • 删掉折叠态的第二行(「新增 N 行 · 删除 M 行」+ 一个不可点的"展开/收起"死标签)——前者把头行的 +N/−M 用中文复述一遍,零新信息
  • 去掉描边:工具卡早就不带描边了,diff 卡留着就成了并排时的唯一异类
  • 圆角 10 → 8(复用 TOOL_CARD_SHAPE),内边距改为工具卡同一套(横 10 / 纵 7),工具名加粗与头行一致

折叠态现在只有一行:工具名 + 路径 + +N + −M + chevron。

文档与 CI

  • 新增 docs/device-bridge-v2.md:v2 工具面与屏幕重构的设计契约(工具表、动作即反馈的返回形状、技能裁剪规则)
  • 工具表、技能表格、包列表、模型提示里的旧工具名全部同步到 v2 的 7 个
  • CI 触发收紧:纯 markdown / 截图 / 标志图改动不再触发完整构建(两个 targetSdk 变体 + ~65 MB 运行时装配)

构建信息

引擎 @earendil-works/pi-coding-agent 1.3.0(未变)
变体 sideload28(targetSdk 28,默认选这个)
架构 arm64
安装包 142,126,674 字节(135.5 MiB)
sha256 281a16dfe897487ff4ff185556599b08fad6e3e6a217373f7452a8fa289773d4
来源 CI run #427,commit 005dea49

同一密钥签名,可以覆盖安装,升级不丢数据。
注意:这一版删除了 VPN / 输入法 / 投屏 / 自动化规则四组能力,升级后不可恢复(回退需装回旧包)。

PI 0.1.3(pi 1.3.0)

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 18 Oct 10:42

引擎:@earendil-works/pi-coding-agent 1.3.0(与上一包相同,不含引擎升级)。

从 v0.1.2(93945ea)到这里共 7 笔提交,其中 1 笔是撤销。下面是这一版的全部内容。


对话页:收起卡片的位置与抖动(这一版主线)

用户报的三层现象,逐层修到位:

  • 收起来人不在原地 —— 展开/收起此前根本没有锚点。整个对话页只有贴底 pin、窗口恢复、搜索跳转三处程序化滚动,展开/收起一处都没有;而 LazyColumn 的锚点只是「第几个 item + 行内像素」,这一行自己变矮以后那个偏移就被当成别的位置用了。现在收起时记住你点开它时那一行的顶端位置(y),收回后把卡还回那个 y,而不是屏幕最顶端。
  • 收完原地抖一下 —— 卡片一矮,下面的行被拉进视口,而没量过的行首帧高度是 0(画一个空 Box,解析落地才长出来)。于是"先空一帧再长出来"。改成同步解析的闩不再放过这一帧。
  • 展开状态会丢 —— 滚出窗口再回来,卡片不再自己收起来;展开状态按行 key 记住,不随 composition 消失。

中间那一笔「把卡还回到屏幕最顶端」(23f6301) 已被下一笔撤销,最终落地的是「还回你点它时的位置」。

设置 · 模型:只有三个厂商(bug)

  • 根因:officialCatalog() 读的是硬编码的嵌套路径 …/pi-coding-agent/node_modules/@earendil-works/pi-ai/dist/providers/data,而 pi 1.3.0 的依赖树里 @earendil-works/* 全部提升到顶层,那层嵌套 node_modules 根本不存在 → 目录读空 → 导入 sheet 里只剩三个厂商,搜也搜不出来。
  • 顺带重做了这一屏:选择器与导入流程按「更少文字、更少步骤」重排,默认模型可以直接点选,不再只能自己填。

设置 · 系统提示词:框上沿写了不存在的键

  • 那两个输入框都在用、不是重复:上面那个整份替换 pi 的 SYSTEM.md,下面那个追加 APPEND_SYSTEM.md。
  • 过时的是框上沿那行小字——显示的是旧键名 app.runtime.systemPrompt / app.runtime.appendSystemPrompt,那是它们还作为"App 设置项"时的身份,现在已经改成 pi 的官方文件。改掉。

设置:砍掉没用的一整组

  • 删掉「终端与 Shell」整组(shellPath / shellCommandPrefix / npmCommand / 终端页字号 / 终端键栏 五行)——手机上没有第二个 shell 可选,填错只会让每次 bash 命令失败;另两项只服务已叫停的终端页。
  • 说明文字砍到一句:设置项下面那一堆意义不大的注解收掉。
  • 重启卡只在真的需要时出现——此前啥也没干也让你重启;现在只在你改过需要重启的配置之后才出现。

构建信息

引擎 @earendil-works/pi-coding-agent 1.3.0(未变)
变体 sideload28(targetSdk 28,默认选这个)
架构 arm64
安装包 142,237,718 字节(135.6 MiB)
sha256 ed079273e338e0a8b687184f3bb775b9ac32110a16718827ae1d471883dba82e
来源 CI run #417,commit 313309f5

与上一版同一个密钥签名,可以覆盖安装,升级不丢数据。

PI 0.1.2(pi 1.3.0)

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 16 Oct 19:17

引擎:pi-coding-agent 1.0.1 → 1.3.0(Node 24.19 不变)。

从上一个包 v0.1.1 到这里共 130 笔提交。下面是这一版新增、修复与加强的全部内容,按面分组。


引擎与运行时

  • 引擎跨三个小版本:1.0.1 → 1.0.3 → 1.1.0 → 1.2.0 → 1.3.0,App 侧零代码改动接入
  • 引擎依赖树自己锁起来,钉住 1.3.0,构建不再受上游漂移影响
  • 官方厂商的连接字段改成「没意见就不写」——不再往配置里塞多余字段
  • provider id 列表跟上 pi 的改名(azure-openai-responses → azure)
  • 覆盖解压不再把软链写到自己目标上(修真机上的 ELOOP 死循环)
  • 升级不再必须重建运行时:覆盖解压前先清掉「占了目录位置」的旧节点
  • 覆盖解压去掉了那条空操作的 agent 目录迁移

设备能力(这一版改动最大的一块)

  • 设备 Shell 全放开:白名单取消,守卫只剩一个空黑名单
  • 闸门改为按不可逆命令审批,工具收敛为 6 个常驻
  • 审批补 3 项:pm/cmd uninstall 与 android_admin(wipe)
  • 接线第二轮能力:输入法 / 管理员 / 通知 / 自动化 / 网络 / 投屏 + 无障碍可靠性
  • 五组能力改为默认全关——要用自己去「设置 → 设备能力」开
  • 取消 deferred 与 tool_search 依赖,全部工具由能力开关控制
  • 提示词里 16 个「已被合并入口转交」的细粒度工具改为 hidden,提示词降 49%
  • 工具耗时改用 pi 1.1.0 记录的执行时间
  • ADB 那句给出明确触发条件,不再是含糊的 "when needed"

修掉的设备侧 bug

  • 输入法:切到 PI 后打不了字而且回不去 —— 加了一颗「切换输入法」,警告缩成一句
  • VPN 停不掉;投屏入口被误报为不存在
  • 广播的端点清单少了 11 个 —— 补上,并加一道检查让它不能再漂
  • 全链路审查:补上 2 个死端点,消掉 1 处能力/门禁错配
  • 把波 1 的可靠性函数接出来(此前根本够不到)
  • 诊断端点被自己要诊断的前置挡住;「激活设备管理器」的按钮指向一个已不存在的页面
  • 全关时技能仍在显示、环境段仍被注入 —— 两处「关了没关干净」
  • 删除「管理员」能力组时留下的两处语法残骸 —— 闸门因此早已加载不了
  • 审批弹窗两个真 bug:「记住」的作用域,以及超时被说成拒绝
  • 拦住「超时后盲目重试」这个坏指令,拦截消息说清是哪个操作
  • scroll 降级、apps 枚举取并集、无障碍被系统关掉时提醒
  • 扩展里一个反引号让扩展加载不了;「已失效机制」的残留说法清干净
  • 去掉每次启动都弹的「屏幕」能力失效提醒

外观与交互

  • 排版/行距/字号三行取代原来的字号微调与消息密度 —— 四档预设 + 一次性读时迁移
  • 紧凑/舒适/宽松重新定标,舒适与宽松不再松垮;按第三版修订校正预设数值
  • 转录的消息级间距 —— 换人时更大,同一条消息内部更小(舒适档 24 → 20)
  • 表格:字号跟排版档、表头一层极淡底、横滑时右缘渐隐;单元格不再无限折行
  • 段间距不再加在文档开头 —— 这是用户气泡文字偏下的根因
  • 启动图标换成用户定的 pi 字标(矢量化);启动页不要徽章、单色层 = 图标本身、通知栏用图标本身
  • 用户气泡时间戳移出气泡;错误卡只改外形;扩展三张卡对齐 24dp 模块
  • 工具卡:折叠态两行并一行、删掉执行轨道与节点、卡片变矮变宽(缩进 11dp、内边距纵 7、页脚条件化、读数并进头行),有图保留专属排版
  • 工具卡折叠态和官方不一致的地方对齐官方(折叠态冻结)
  • 思考行改版:颜色条随展开延伸到正文末行、改定宽格(消掉流式时整行每秒重测导致的整屏乱跳)

修掉的外观/交互 bug

  • 工具卡展开/收起乱跳这一串(根因排查后一次修到位):
    • 跟随的 pin 只由「内容真的变了」的帧付账
    • 收起卡片时钉住读者点的那一行,缺口用正好差额的底部空白兜底
    • 连着收起两张卡时不再丢上一次的底部空白(band 记的是总缺口,不是本次位移)
    • 收起后被推开的内容不再原地空一帧
    • 展开/收起不再把视口抢到列表底部;收回后整条内容跳到另外半屏
    • 展开过的卡片滚出窗口再回来不再自己收起来
    • 展开/折叠的点击与拖动同等对待
  • 被拒/失败的 grep、find、ls 整卡消失(回归修复)
  • EditBlock 页脚的 remember key 收窄得过头
  • codemode 的实时调用清单根本到不了卡片;脚本与调用行接上高亮与分段上色
  • 插话/排队按 pi 一比一:去掉乐观回显、判据用引擎事实、用词统一到「引导 / 后续」
  • 日期分隔行自己给下沿留白(新模型下唯一漏的一行)
  • 思考耗时改定宽格;run 中间行不再每次绘制都构造一个 Path(性能)

会话与工作区

  • 导出的 JSONL 改成「会话文件本身,逐字节复制」 —— 一次导出同时给 HTML 与会话文件
  • 带参数的 /export <名字> 回到 pi 的分派(一比一):后缀决定写哪一种、只写那一份
  • 排队消息不再冒充已发出的消息,并补上官方式的待发区
  • 工作区文件菜单补上「用其他应用打开」与「导出到 Download」
  • 修掉导出改成流式时写错的一个扩展函数(那一版 APK 编不过)

设置与提示词

  • 提示词改走 pi 的官方文件;紧急停止收拢到一处
  • 只读读数覆盖全部四份提示词文件,形状与用词沿用资源读数
  • pi 的路径列表落到只读行的证据块里,值不再被截断
  • 运行时占用按已分配块算(不再虚高)
  • 修掉一个让上一版 CI 判红的类型可见性问题

本机可跑的检查(不插设备)

  • 纯逻辑 harness 清单被多删的 224 行放回来
  • 钉住「收起这一拍跟随不该掉」以及下一个 token 会收回末端
  • tool-state 的断言改成对契约断言,不再钉调用写法(CI 曾 FAIL X3)
  • date-separator 的 harness 补上覆盖面断言

顺带

  • 文档全面对齐当前实现:过期说法按代码改对,统一「引导 / 后续」用词,能力面账本核到当前基线
  • 删掉三个没有生产调用者的旧函数(连带钉着它们的 6 条断言)
  • 修 5 个编译错误(一直没人验过,CI 挂了两次)

构建信息

引擎 @earendil-works/pi-coding-agent 1.3.0
变体 sideload28(targetSdk 28,默认选这个)
架构 arm64
安装包 142,202,286 字节(135.6 MiB)
sha256 ec39288a9415caf6f45a14f2cf88c9619600ea780c6b308f7b55b7ad06f1c4b4
来源 CI run #410,commit 93945ea

与上一版同一个密钥签名,可以覆盖安装,升级不丢数据(升级也不再必须重建运行时)。

PI 0.1.1(pi 1.0.1)

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 04 Oct 09:00

引擎:pi-coding-agent 0.99.2 → 1.0.1(Node 24.19 不变)。下面是从上一个包 v0.1.0 到这一版的全部 80 笔提交,按类型分组,原始标题一字未改。

新功能(6)

  • render — 裸 HTML 照 pi 原样排字(块级走 custom 新分支,行内走 annotator 认领钩子)
  • render — 保行通道落地(候选 B,只在含显示式网格的消息里打开)
  • render — 移植 pi 的竖直排版(renderLayout + 环境),118 条块级目标逐字节断言
  • pi — 设备工具按能力注册 —— 关掉的能力一个字都不进提示词
  • workspace — 图片自己渲染,渲染不了的交系统;修掉图片查看器里被背景层吃掉的手势
  • render — markdown 图片按视口采样、表格解禁一行限制、http(s) 真的加载

修复的 bug(36)

  • session — 分叉的用词与那条缺了的提示(落另一个代理交回的两处 diff)
  • chat — 分叉与分支按上游分开 —— 会话列表改说「来自谁」,树行仍说「分叉」
  • session — 重启时同一个 id 有两份就不猜 —— 改用 --session <path>
  • session — 列表不再把「劈成两半的对话」折成一行 —— 只有一份的字节是另一份的前缀才合并
  • session — 一次引擎重启劈开一段对话 —— --session-id 用同一个 id 再建一个文件
  • workspace — 提示条被底栏盖住 —— 它挂在没吃 contentPadding 的那个 Box 上
  • composer — 发出去的字又回到输入框 —— 失焦那次回调把清空前的文本写回了草稿
  • image — URL 画图全链路 —— 裸链接也出图、表格缩略图按格宽解码、清掉两个会伤到它的数字
  • session — 点叉就必须退出 —— 「覆盖层开着」不再住在可以重放的状态里
  • session — 点叉退出又被拉回会话树 —— 关掉覆盖层必须作废排队中的导航请求
  • runtime — 客机时区指到了 Android 那份 zoneinfo,短名静默退化成 UTC
  • session — 退出来又被拉回会话树 —— 「请求级」的状态不许比请求活得久
  • viewer — 放大不清晰是三层叠加 —— 块预算比屏幕小、倍率本来就越过源 1:1、进 App 前已被压小
  • runtime — 目录也纳入载荷所有权 —— prune 在同一趟里删掉旧载荷的空目录
  • runtime — 收尾失败不许静默,也不许照样记账
  • render — 网格写回源文本时前导缩进被 markdown 当成代码块,公式被切成两半
  • render — 正文图片根本没有点按 —— URL 图渲染出来了,却没有任何手势通向查看器
  • viewer — 放大后拖动只走了手指的 1/scale —— 手势位移按倍率换算回屏幕像素
  • render — 网格的等宽段落不再对库的类型 copy —— CI 红在 Unresolved reference 'copy'
  • build — 两个提交把 main 弄红了 —— 缺一个实参、以及注释里的 /*
  • bridge — 生产者超预算时也把结论写进 lastFailure,别让它挂着别处的旧原因
  • session — 会话树的「读取会话树 ↔ 就绪」来回刷、以及退出来又被拉回树
  • viewer — 放大之后按源图坐标重解可见的一块 —— 8× 看到的是细节,不再是小图拉大
  • render — $ 的两条前缀判定按真实 prose 语料对齐,收尾那条保留并说明理由
  • attachment — images.autoResize 关掉之后 App 照压 —— 接上这个开关的消费者
  • render — 数学补两种定界符与 5 类解析缺口,表/行为改由 pi 夹具钉住
  • attachment — 截图类源被压成有损 JPEG —— 候选序改成与 pi 一致的 PNG 优先
  • viewer — 双击直接放到最大(1× ⇄ 8×),不再有第三个档位
  • attachment — 竖拍照片被当成横图送出去 —— 先按 EXIF 摆正,再算尺寸
  • composer — 命令面板塞进来的 / 后面光标停在 0,再打字落在斜杠前面
  • bridge — KDoc 里的「星号斜杠星号」提前关掉注释,两个 APK job 全挂
  • workspace — 能看的地方就能改 —— 去掉刚加的那层"只读层"特例
  • workspace — 认得 guest 的两种拼法;工作区屏改成能往上走的文件管理器
  • ui — 「显示时间戳」真的管到气泡上的时间了,并且默认关
  • boot — 「已是最新」不再占屏 —— 没有解包可做的启动不再闪一次启动页
  • runtime — 覆盖解压前先清掉"占了目录位置"的旧节点 —— 升级不再必须重建

性能(7)

  • render — 数学预处理每轮重扫串尾 ⇒ 平方;改成两个单调迭代器
  • session — 打开会话的两处重复劳动 —— 为量一个长度序列化整棵 JSON、逐字符切行
  • render — 行内 HTML 的认领钩子只在源文本含 < 时才装 —— 其余消息代价归零
  • session — 会话列表索引落盘 + 有界并行扫描,冷启动那一次不再逐行解析几百 MB
  • bridge — 正文远端图片的请求策略 —— 进程级去重、45 s 负缓存、取字节并发上限
  • render — 表格单元格不再无限折行,mermaid 滚回来不再重问 guest
  • export — 保存会话导出不再绕一遍 base64 —— 少两份峰值内存

撤销 / 回退(2)

  • image — 裸 URL 不再改写成图 —— ![]() 才是图,链接就是链接
  • blocks — 通用工具卡标题回到原样,去掉 MCP 的 server/tool 改写

检查与不变量(本机可跑)(6)

  • pre-spawn — 三条源码不变量跟上 restartEngine 的「两种钉法」
  • session — replay-cost 的两条源码不变量跟上「argv 的两种钉法」
  • runtime — 钉住"目录也在载荷所有权里"
  • runtime — 钉住「收尾失败不许静默」的四处形状
  • session-replay-cost — §3b 那一列量的是整份 readAll,列名别写成 entries
  • session — 补一条断言 —— -c(mostRecentForResume)走索引时也必须给出同一行

文档(15)

  • --session-id/--session 的现状与列表合并规则(三处过期说法 + 一处登记)
  • session — TerminalScreen 的注释不再提已经删掉的 PiOverlay.Terminal
  • test — P19 与 fetch-runtime.mjs 必须成对改
  • runtime — 耐久目录的保护来自 DurablePreserve,不是"在易失树之外"
  • render — §A2 记下 NBSP 缩进保护(上一提交的实现)
  • render — 行内 HTML 钩子的注释别再引用会漂的行号
  • render — §A2 记下保行通道的实测结论 —— 候选 A 走不通,B 的作用域可收紧
  • render — 收录渲染能力盘点(只读审计,424 行)
  • check — EXIF 夹具条数在注释里写错(28 → 26)
  • render — §A2 里的夹具条数 31 → 34
  • attachment — AttachmentBudget 的四处过期引用(含 0.86.1 → 1.0.1)
  • render — manifest 已开明文,改掉两处"没有 usesCleartextTraffic"的过期话
  • 1.0.0 之后清一遍文档里"对当前版本已经不成立"的说法
  • readme — 装上改为指向正式 release
  • readme — 重排——能扩展成什么样提到最前,装上/架构/升级挪到底部

其他维护(8)

  • session — 剩下三处注释不再提已删除的 setOverlayView/PiOverlay/overlayIndex
  • session — 删掉没用的尾巴 setOverlayView,以及两处还提着旧名字的注释
  • checks — 注册 guest-timezone —— 钉住客机的时钟来源
  • checks — 注册 markdown-image-tap —— 正文图片点开查看器那条接线
  • html — 生成器按惯例搬进 tools/,并把 html harness 注册进 CI
  • checks — sessions 与 session-identity 两个闭包加进新文件 PiSessionIndex.kt
  • pi — 钉住 1.0.1,并把引擎那棵依赖树自己锁起来
  • pi — 钉住 pi 1.0.0,并修掉 node.tgz 的一个静默构建缺陷

PI 0.1.0(pi 1.0.0)

Choose a tag to compare

@heikeyangle-code heikeyangle-code released this 01 Oct 15:24

引擎 pi 1.0.0(上游 2026-10-01),App 版本 0.1.0。

下载哪个

文件 targetSdk 说明
pi-android-0.1.0-sideload28-arm64.apk 28 默认选这个。 用 Android 10 以前那套沙箱规则,系统权限最少,行为最可预期
pi-android-0.1.0-modern36-arm64.apk 36 面向新系统行为变更的版本,需要真机验证;只在 28 那个装不上或行为异常时才试

两个包用同一套密钥签名,可以互相覆盖安装,升级不丢数据。要求 Android 8.0 (API 26) 以上,arm64。

首次启动

会解包约 117 MiB 的运行时(APK 本身约 136 MB,大部分就是这部分),比之后每次启动慢。
之后只在载荷真的变化时才重新解包。/root/.pi/agent(会话、凭证、settings)与工作区不在载荷里,升级保留。

校验

0847f020c2688f7cedb0c0a7871d8e886555e7d352628e9eaaaa0e3f64dfff63  pi-android-0.1.0-sideload28-arm64.apk
a15133ade5bead70a1ace0638e48b704702eb724b8b9602cc2420f9044549509  pi-android-0.1.0-modern36-arm64.apk

这一版有什么

引擎从 pi 0.87.1 一路到 1.0.0(中途 0.99.0 是一次性大版本:codemode、MCP、虚拟模型、主题系统重做)。
1.0.0 这一步对 App 几乎没提要求:RPC 线、内置主题色值、会话格式、模型目录格式、工具结果文本、
设置键集合、依赖集全部零变化。逐条判据在仓库 tools/fetch-runtime.mjs 的 PI_VERSION 上方那段
审计结论;tools/pi-contract.mjs 是 CI 的 pi contract job,每次对着钉住的引擎重新核一遍。

App 侧这一轮还修了三个:

  1. 升级不再必须「重建运行时」。 覆盖解压时如果某个路径在新载荷里必须是目录、旧树里却是文件或
    断掉的软链,mkdirs() 会静默失败、写文件报 ENOENT,重试永远停在同一处,只有重建能过(代价是
    删掉你装在客体里的东西)。现在解压器会先把这类节点清掉,再写。装上这个包之后,那一次升级应该
    直接过,不用再点重建。
  2. 没有解包可做的启动不再闪一块启动页。 以前「运行时已是最新」也会占满一屏,现在只有真要解包
    或出错时才出现。
  3. 「显示时间戳」真的管事了,且默认关。 以前它只管日期分隔,气泡右下角的时间是无条件画的,
    所以关了看着像没生效。现在它同时管气泡时间、通知行时间和日期分隔,默认关。