Summary
TaskExecute fails with spawn failed — (empty error message) when RPC reply handlers return bare payloads instead of the expected RpcReply envelope. Additionally, checkSubagentsVersion() incorrectly marks subagents as "outdated" when it receives malformed {} ping replies from stale extension mirrors or legacy handlers.
Root Causes
1. rpcCall() only accepts envelope replies
rpcCall() casts all replies to RpcReply<T> and checks reply.success. If a handler returns a bare payload like { id: "abc" } (no envelope), reply.success is undefined (falsy), so it calls reject(new Error(reply.error)) — producing an empty error message and silent spawn failure.
2. checkSubagentsVersion() fails on first malformed reply
When multiple extensions respond to a ping (e.g., a stale mirror copy replies {} before the real handler replies with { success: true, data: { version: 2 } }), the function unsubscribes on the first reply. Since {} has no data.version, it immediately sets pendingWarning and never receives the valid reply.
3. No debounce on version checks
Each subagents:ready event triggers a new checkSubagentsVersion() call. If multiple ready events fire in rapid succession (e.g., during extension initialization), multiple concurrent pings race and can produce inconsistent state.
Impact
TaskExecute returns spawn failed — for every task
subagentsAvailable stays false even when subagents are loaded and functional
- The
Agent tool works fine (bypasses RPC), so users see inconsistent behavior
Environment
- pi-tasks v0.4.2
- pi-subagents v0.5.1 (with custom bridge extensions)
Proposed Fix
See PR — fixes all three issues:
- Make
rpcCall() accept both envelope and bare payload replies
- Make
checkSubagentsVersion() ignore malformed replies and keep listening
- Add
versionCheckInFlight debounce guard
- Also includes cascade data flow (inject prerequisite results) and model forwarding as improvements
Summary
TaskExecutefails withspawn failed —(empty error message) when RPC reply handlers return bare payloads instead of the expectedRpcReplyenvelope. Additionally,checkSubagentsVersion()incorrectly marks subagents as "outdated" when it receives malformed{}ping replies from stale extension mirrors or legacy handlers.Root Causes
1.
rpcCall()only accepts envelope repliesrpcCall()casts all replies toRpcReply<T>and checksreply.success. If a handler returns a bare payload like{ id: "abc" }(no envelope),reply.successisundefined(falsy), so it callsreject(new Error(reply.error))— producing an empty error message and silent spawn failure.2.
checkSubagentsVersion()fails on first malformed replyWhen multiple extensions respond to a ping (e.g., a stale mirror copy replies
{}before the real handler replies with{ success: true, data: { version: 2 } }), the function unsubscribes on the first reply. Since{}has nodata.version, it immediately setspendingWarningand never receives the valid reply.3. No debounce on version checks
Each
subagents:readyevent triggers a newcheckSubagentsVersion()call. If multiple ready events fire in rapid succession (e.g., during extension initialization), multiple concurrent pings race and can produce inconsistent state.Impact
TaskExecutereturnsspawn failed —for every tasksubagentsAvailablestaysfalseeven when subagents are loaded and functionalAgenttool works fine (bypasses RPC), so users see inconsistent behaviorEnvironment
Proposed Fix
See PR — fixes all three issues:
rpcCall()accept both envelope and bare payload repliescheckSubagentsVersion()ignore malformed replies and keep listeningversionCheckInFlightdebounce guard