feat: discover and select Pi extensions in provider settings - #853
Conversation
6ed5742 to
b5541c0
Compare
Surface globally installed Pi extensions in the builtin Pi provider dialog through a read-only scan of the pinned runtime. Candidates stay disabled until explicitly selected, and selections reach both the main Pi process and native subagents through the versioned piExtensions contract. The scan runs under a frozen default or saved-profile environment so no caller-supplied launch fields reach it, and the field renders only when the managed runtime declares piExtensionsProtocolVersion. Refs LodyAI#780 Model: devin-swe-2-max
The 150s default matched the daemon's worst case (120s ensure + 30s scan), so a future caller relying on it would race the daemon's own limits. The only caller already passes 180s. Refs LodyAI#780 Model: devin-swe-2-max
Move the dialog's private collapsible section into form-primitives as CollapsibleSection and adopt it for the extensions group: the selected count stays visible while collapsed, Scan sits in the header action, and the unsupported-runtime state uses the section's disabled hint. Errors and scan warnings now use FormMessage; candidates render as the standard divide-y list with a stale marker for selections missing from the latest scan. Refs LodyAI#780 Model: devin-swe-2-max
A dispatch-turn inputConfig is caller-authored on the workspace RPC transport, which cannot authorize a caller to choose a command for the target daemon. customAcp and runtimeOverrides are launch inputs: they must come only from the daemon-resolved persisted session launch config, like env and worktreeSetup already do. Preferring the history entry's copy let a dispatch caller inject e.g. runtimeOverrides.piExtensions and bypass the explicit-selection boundary for Pi extensions. Refs LodyAI#780 Model: devin-swe-2-max
Validate manually entered paths (absolute or ~/, bounded length) so a rejected value cannot silently drop the whole provider row during daemon normalization. Route the selection handler through invalidateBuiltinVerification and clear the probe flag in the probe effect cleanup so a mid-probe selection change cannot leave a stale "Probing..." state. Also remove review-flagged dead weight: the single-mount scan generation counter (the key remount already discards stale scans), the single-use options alias, and the facade's same-process re-parse of already validated RPC results. The 32/4096 selection bounds now come from shared constants in ai.ts instead of three separate literals. Refs LodyAI#780 Model: devin-swe-2-max
b5541c0 to
9cf4124
Compare
|
Ready for another look @wibus-wee, whenever you have a moment. Rebased onto latest main, and a self-review pass turned up one real fix: a dispatched turn's inputConfig could carry caller-supplied customAcp/runtimeOverrides into launches, so launch fields now only come from the persisted provider config. Also tightened the extension path input validation and cleaned up a few dead spots the review flagged. Would love your eyes on it. Thanks! |
wibus-wee
left a comment
There was a problem hiding this comment.
Here is also an implementation gap discovered by my agent after communicating with me:
Missing paths and load failures must not silently succeed.
In the code, the "missing path" is achieved, but the "path exists, extension fails to load itself" is not.
Therefore, there are typical situations:
extension.ts exists
↓
-e extension.ts
↓
import / init throws exceptions
↓
Pi extension_error
↓
adapter stderr
↓
ACP capability probe continues
↓
The base model/configOptions are still normal
↓
Provider Test = success
The result users see might be:
I clearly checked extension, and Test was successful, but extension didn't load at all.
There was a problem hiding this comment.
There may still be some issues. Regarding the dispatch injection you mentioned, I specifically went to check it out, and it seems there are still trust-boundary issues
Here, the same untrusted fields are still accepted.
Even if a custom ACP session is already in place, the attack input doesn't even need to change the agent identity
I think we can simplify this and stop keeping consumers constantly "remembering to ignore" one by one.
SessionTurnInputConfig derived from Partial<ACPSessionConfig>, which conflated per-turn dispatch config with provider launch fields. The normalizer is an explicit field allowlist, but the type and history schema still admitted customAcp and runtimeOverrides, so a crafted dispatch-turn inputConfig could inject them into the launch path. Split ACPTurnConfig out of ACPSessionConfig at both the type and schema layers: launch fields now extend the durable session config only, per-turn input is closed by construction, and stored history strips the keys while staying readable. The dispatch-watcher and delivery-continuation reads they fed become structurally impossible; no legitimate producer ever emitted them. Model: swe-2-max
|
Thanks @wibus-wee for the close look at this. Both comments deserved the digging. The inputConfig boundary is fixed at the normalization layer in On silent extension load failures, I couldn't reproduce the silent-success path on the pinned runtime. On 0.85.1, load failures land in The gap that does exist is narrower: on 中文说明感谢细致的评审,两条意见都值得认真挖。 inputConfig 边界已在归一化层修复( 关于扩展加载失败静默成功:在锁定版本上我没能复现这条链路。0.85.1 里加载失败会进入 真正存在的缺口更窄:在 |
Related issue
Refs #780
Problem / pressure
The builtin Pi provider launches the managed adapter with
--no-extensions, so globally installed Pi extensions (provider registration, packaged tools) cannot be used under Lody at all. #780 agreed on explicit opt-in loading: a read-only scan of installed extensions, candidates default-off, and selected paths forwarded with-eto both the main Pi process and native subagents.The adapter half landed in LodyAI/acp-extension-pi#2. This PR is the host side: surface the discovered candidates in provider settings and carry selections through launch, gated on a runtime that declares the extension protocol.
Summary
machine/pi-extensionsMachine RPC runs the managed runtime's read-only--list-extensionsunder a frozen default or saved-profile environment (persistedconfigIdonly, allowlisted env, bounded response schema, 180s client timeout covering runtime install plus scan).~paths are accepted, and unsupported-runtime and scan-failure states render in place. The field appears only when the runtime manifest declarespiExtensionsProtocolVersion.runtimeOverrides.piExtensionsinto launch args; the value is digested into the capability source version so changing selections invalidates cached capabilities. In the adapter, native subagents inherit the same explicit list viaLODY_PI_EXTENSIONS.piExtensionstake the real create/probe path instead of deferred provider setup, and non-Pi provider rows drop the field.piExtensionsProtocolVersionin the packaged runtime manifest, and updates the builtin-Pi spec and feature note.Visual explanation
Scanned candidates are default-off while an existing selection stays checked (fixture data — a real scan reads the target machine's Pi profile):
Narrow layout keeps the same controls usable:
A runtime without the extension protocol disables scanning with an upgrade notice:
A failed scan reports the error in place and keeps manual entry available:
Before / after
-e, while everything else stays disabledTest plan
pnpm check(typecheck, lint, all package tests, i18n and boundary guards) — green.pnpm run docs check— green.agent-config-dialog.test.tsx(36, including create mode submittingpiExtensionswithout deferred setup),pi-extensions.test.ts,session-execution-service.test.ts,machine-rpc-server.test.ts,workspace-machine-rpc-facade.test.ts,local-machine-rpc.test.ts,machine-flock.test.ts,ai-capability-cache.test.ts,message-schemas.test.ts— all green.Context handoff
Original user prompt
Show original prompt
Shared conversation
Status: shared
Link: https://share.lody.ai/s/r17b9dptdnarnzx6zvf2qt6qrh8ey346#access=v1.815782ca235dd9f8d0528894ec516bb8d27a50c26384e26e4fc94b62eee068d1
中文说明
关联:Refs #780(适配器半边已合并:LodyAI/acp-extension-pi#2)
问题:内置 Pi 以
--no-extensions启动,用户全局安装的扩展(provider 注册、工具包)完全无法使用。改动:
machine/pi-extensionsRPC 在冻结的默认或已保存 profile 环境下调用托管运行时的只读--list-extensions(仅接受已持久化configId、env 白名单、有界 schema、180s 超时)。piExtensionsProtocolVersion时渲染。runtimeOverrides.piExtensions进入启动参数并计入能力缓存失效;适配器内子代理通过LODY_PI_EXTENSIONS继承同一列表。piExtensions的配置走真实 create/probe 而非延迟 providerSetup;非 Pi 行丢弃该字段。验证:
pnpm check与docs check全绿;相关测试套件全过;适配器侧 smoke 三平台全绿。端到端验证待扩展感知运行时产物发布及 manifest 更新后进行。