Quick Start
1
Read a capability before rendering
2
Print the unsupported scenarios
The Capability Matrix
What each shipped engine can report.Closed Gaps
The rows kept from the old gap report so a reader arriving from an old bug can find where they went.Open Gaps
Known-open, stated rather than implied so a follow-up author can pick them up.Reported, not fixed
The capabilities PR #4794 audited but deliberately left unwired, named here so a follow-up author can pick them up.Why tools: false For praisonai-ts
praisonai-ts executes tools normally; it just never announces them. Upstream Agent.streamEvents() emits a three-variant union — text, finish, error — and none of those carry a tool call, so the engine cannot report one.
true flag would render nothing and look broken — and a tool call that silently failed would be indistinguishable from a normal answer, which is exactly what tool_result.ok was introduced to prevent.
How Each Gap Closed
Gap 4 was “mechanism landed, not wired”:createSession was called and RunPersistence.record was called, and nothing connected them — the two signatures did not even line up (record(prompt, answer) against record(request, answer)).
keyboardHeightPx was declared = 0 and only updated by an event, so a component mounting while the keyboard was already up laid out at 0 for one frame and then jumped.
Dropped type, the view-model row and the seven user-facing strings all existed with no producer. remote-http was the only production caller of decodeEvent and discarded every rejection, so a malformed frame made its tool vanish and the turn rendered as a clean answer.
carry field fixed the cross-turn contamination: apply(start) no longer carries the previous turn’s entire dropped list, so one refusal on turn 1 no longer paints every later turn as damaged. Two composition tests pin the two wiring hops — createApp and the real enginesFor — because removing the sink from createRunController or dropping the registry’s forward each left the suite green in isolation. See Dropped Events.
The
showDiagnostics setting was removed in PraisonAI #4646 because no shipping code path read it, and its false default described a hiding that never happened — dropped rows are rendered unconditionally. A visibility toggle will be re-added the day a settings screen consumes it.The Unsupported Scenario
Fromsrc/praisonai-mobile/docs/gaps.md, the one conformance scenario praisonai-ts still declares unsupported. Tool scenarios and the single-approval scenario are produced and passing since upstream gained tool_call/tool_result and the dead approval skip guard was retired in PraisonAI PR #4641.
Each is printed on every run, so a contract that quietly shrinks is visible rather than silently green.
approval runs because that case only asserts that deciding an unknown id returns false, which praisonai-ts’s decide() always does — no approval channel needed. capabilities.approvals stays false because the engine still cannot emit an approval request, which is what two_approvals needs.
Closing the remaining gap needs an upstream change:
AgentEvent gaining an approval variant so praisonai-ts can emit approval_request events. Until then, use remote-http for the two-approvals flow.Roadmap
The in-process engine now ships and boots on a device: the mobile path importspraisonai/mobile — the package’s webview-safe entry (praisonai-ts #4720) — as a lazy chunk, and defaultEngineIdFor("tauri") returns praisonai-ts. The CLI-oriented agent/simple.ts still carries Node-only imports (crypto, and events in ai/tool-approval.ts), but those are not for the webview — the /mobile entry avoids them, so they no longer block the mobile app.
The remaining device gap is the API-key setting: the registry declares no secret setting yet, so a first turn reaches the model layer and fails recoverably for want of a key. A key setting is the tracked follow-up. See Engines → The known API-key gap.
Remaining native-shell gaps (tracked in src/praisonai-mobile/docs/gaps.md):
keyboard-heightis still never emitted natively; the TypeScript readsvisualViewportand would take a native event as an override.- iOS edge-swipe back is not installed.
- Haptics and share have no plugin; their bridge invokes reject and the bridge degrades.
Verified reachable in PR #4794.
shell.onBackGesture, shell.onInsetsChanged, shell.onKeyboardHeightChanged, shell.onLifecycleChanged, time.createScheduler/every/setTimer, and the settings-registry unread-key path (already pinned by registry.test.ts) were audited as starting leads and found already reachable — no doc change needed. Recorded here so a reader does not chase them again.Best Practices
Render from the capability, not from hope
Render from the capability, not from hope
Check
capabilities.tools before drawing tool rows; the flag is the contract the conformance suite enforces in both directions.Declare gaps, never fake them
Declare gaps, never fake them
An honest
unsupported entry keeps the suite meaningful; a faked scenario hides a defect it exists to catch.Switch engines to gain capabilities
Switch engines to gain capabilities
remote-http speaks the full vocabulary because the desktop server already emits it.Close a gap only when it is wired end-to-end
Close a gap only when it is wired end-to-end
A mechanism existing is not the same as a mechanism working. Gaps 4 and 5 each landed a type or a function before the wiring, and read as closed from either end until re-audited.
Keep retired gap rows visible
Keep retired gap rows visible
The Gap-4 and Gap-5 rows stay in the matrix, linked to PR #4552, so a reader coming from an old bug report can find where they went rather than assuming they were dropped.
State scope so it is not read later as an oversight
State scope so it is not read later as an oversight
The remote-http exclusion is deliberate. Documenting it up front stops a future reader from filing the empty local session as a regression.
Related
Agent Engine Port
The port and its conformance harness.
The 11 Events
The full event vocabulary.
Mobile Engines
Which engine owns the write.
Shell & Adapters
The keyboard snapshot and its guard.
Dropped Events
The closed decode-rejection gap, end to end.

