[plugin sdk] consolidate host workflow seams#80267
Conversation
|
Codex review: needs real behavior proof before merge. Summary Reproducibility: not applicable. This is a feature/API consolidation PR, not a bug report with a current-main failure path; current main lacks the proposed central API names. Real behavior proof Next step before merge Security Review detailsBest possible solution: Have maintainers finish normal review, resolve the failing lint/check gate, and land this replacement branch only if the broad Plugin SDK/API surface is the intended product direction. Do we have a high-confidence way to reproduce the issue? Not applicable. This is a feature/API consolidation PR, not a bug report with a current-main failure path; current main lacks the proposed central API names. Is this the best way to solve the issue? Unclear. The branch is a coherent replacement for the related split PRs and preserves flat compatibility aliases, but the broad SDK surface and failing lint gate need maintainer judgment before merge. Acceptance criteria:
What I checked:
Likely related people:
Remaining risk / open question:
Codex review notes: model gpt-5.5, reasoning high; reviewed against e8a870c550ab. |
1d5664d to
6f6ec6e
Compare
2d57b79 to
ab31947
Compare
ab31947 to
be565ae
Compare
c4eebf7 to
4f64532
Compare
86590d0 to
7b048b2
Compare
edd2a05 to
5aad844
Compare
5aad844 to
61c90ca
Compare
61c90ca to
140f6b4
Compare
Summary
Replacement for #80229, carrying forward @100yenadmin's work from #75578, #75581, #75588, and the relevant pieces of #79334 on an OpenClaw-owned branch so maintainers can keep fixing it up. History is rewritten into three review commits while preserving contributor authorship/credit on the feature commits.
Commit layout:
feat(plugin-sdk): consolidate session workflow APIsfeat(media-understanding): add structured extraction runtimedocs(plugin-sdk): document consolidated workflow seamsThis consolidates several host workflow seams behind grouped Plugin SDK namespaces:
api.session.controls.*for Control UI descriptors and typed session actions.api.session.workflow.*for next-turn injections, host-mediated attachments, Cron-backed scheduled turns, and tag cleanup.api.session.state.*for plugin-owned session metadata projected into session rows.api.agent.events.*for sanitized plugin-attributed agent events.api.runContext.*for JSON-compatible run-scoped scratch state.api.lifecycle.*for plugin-owned cleanup hooks.The old flat methods remain available, but are now marked deprecated inline and point to the grouped API. The injected grouped namespaces are required on
OpenClawPluginApi, not optional.What this enables
1. Register a typed session action
A bundled plugin can expose a typed action that Gateway clients or Control UI can invoke later. The action owns its payload schema and required operator scope.
A Gateway caller dispatches it through the new RPC:
{ "type": "req", "id": "approve-1", "method": "plugins.sessionAction", "params": { "pluginId": "deploy-plugin", "actionId": "approve-deploy", "sessionKey": "agent:main:main", "payload": { "environment": "prod" } } }The Gateway now authorizes dynamic
plugins.sessionActioncalls against the registered action scope before dispatch. In the example above,operator.approvalsis required;operator.writealone is rejected.2. Publish Control UI descriptors next to the action
Plugins can describe small UI contributions without coupling Control UI to plugin internals.
Clients can discover descriptors through
plugins.uiDescriptorsand then callplugins.sessionActionwith the descriptor action payload.3. Send files back through the active session route
A bundled plugin can attach validated local files to the active session's direct outbound channel. This is useful for generated reports, screenshots, exports, or diagnostics.
The host validates file paths and MIME/content, resolves the session delivery context, and sends via the channel-owned outbound path. Telegram-specific hints stay in the Telegram delivery layer; the core API stays generic.
4. Schedule and later clean up a follow-up agent turn
Plugins can schedule a future turn in a session without inventing a separate task system. Cron remains the scheduler and task ledger owner.
If the workflow is cancelled, the plugin can remove all matching follow-ups by tag:
Generated Cron names include plugin ownership, tag, session key, and stable job name metadata, so cleanup can target only that plugin's scheduled session turns.
5. Keep per-run plugin state and emit workflow events
Plugins can store JSON-compatible state for the active run and emit sanitized events for UI/workflow subscribers.
Workspace plugins are kept scoped to their own event stream names. Reserved streams stay bundled-only.
6. Run bounded image-first structured extraction
Trusted plugins can use provider-owned media-understanding runtimes for image-first extraction with optional supplemental text context.
The Codex provider checks model modality support, denies native tool/file approvals, requires at least one image input, parses JSON-mode results, and validates parsed JSON against the provided schema.
Maintainer fixups in this replacement
origin/mainand refreshed the Plugin SDK API baseline hash.dataresult alias; session actions now use the sameresultname as the Gateway wire response.plugins.sessionActionoperator auth to the exact registered action scopes before dispatch.Real behavior proof
Behavior or issue addressed: [plugin sdk] consolidate host workflow seams #80267 keeps the rewritten three-commit review stack, dogfoods the namespaced SDK APIs in internal fixtures/snippets, validates plugin session-action result envelopes with the existing TypeBox/Ajv protocol schema instead of hand-rolled key checks, factors the duplicated Codex app-server media-understanding turn lifecycle into one bounded runner, splits host workflow helpers into attachment-delivery and scheduled-turn modules, shrinks repeated session action/attachment/scheduled-turn contract fixture scaffolding, preserves explicit Telegram HTML before chunking, preserves Telegram HTML mode for pre-rendered outbound text chunks, fixes the Telegram explicit-formatting regression, fixes Swift protocol generator idempotency, prevents plugin session action handlers from mutating the live gateway client scope array, and keeps runtime agent event emission callable after plugin registration closes. Raw Telegram direct sends still default to Markdown; explicit
formatting.parseMode: "HTML"uses Telegram HTML splitting instead of Markdown escaping before delivery; chunker-rendered Telegram text carriesformatting.parseMode: "HTML"intosendText;protocol:gen:swiftno longer emits trailing spaces;ctx.client.scopesis now a defensive copy; capturedapi.emitAgentEventandapi.agent.events.emitAgentEventremain late-callable.Real environment tested: local OpenClaw checkout at
4f6453224d0990be8c9bbd3ace4c1d7fde75ad0d, pushed toopenclaw/openclawPR [plugin sdk] consolidate host workflow seams #80267.Exact steps or command run after this patch:
pnpm test src/plugins/contracts/session-actions.contract.test.ts extensions/codex/media-understanding-provider.test.ts;pnpm test src/plugins/contracts/session-actions.contract.test.ts src/plugins/contracts/session-attachments.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.ts src/plugins/captured-registration.test.ts src/plugins/loader.test.ts;pnpm test src/plugins/contracts/session-attachments.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.ts;env -u OPENCLAW_TESTBOX -u OPENCLAW_TESTBOX_REMOTE_RUN -u OPENCLAW_TESTBOX_ID pnpm check:changed;git diff --check;pnpm test src/plugins/contracts/host-hooks.contract.test.ts src/plugins/contracts/run-context-lifecycle.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.ts src/plugins/captured-registration.test.ts src/plugins/loader.test.ts;pnpm test extensions/telegram/src/telegram-outbound.test.ts extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/outbound-adapter.test.ts src/infra/outbound/message-plan.test.ts src/infra/outbound/deliver.test.ts;pnpm protocol:check;git log --oneline origin/main..HEAD;gh api repos/openclaw/openclaw/pulls/80267 --jq '{commits, head: .head.sha, additions, deletions, changed_files}'.Evidence after fix:
Observed result after fix: plugin session-action result envelopes now reuse the protocol schema validator and keep JSON-compatible payload checks, Codex image description and structured extraction share one bounded app-server runner, internal host-hook and scheduler fixtures use namespaced SDK APIs while deprecated flat API coverage remains elsewhere, explicit Telegram HTML is split as HTML before delivery instead of being Markdown-escaped, Telegram chunker-rendered text keeps HTML mode through outbound delivery while raw direct sends keep Markdown defaults, late captured root and namespaced agent event emission bypass the closed registration guard, session action handlers receive a mutable copy without changing
client.connect.scopes, protocol generation is idempotent, repeated contract-test setup is smaller while preserving coverage, host workflow helpers are split by attachment-vs-scheduler ownership, the review stack remains three commits, and the PR head matches the pushed branch.What was not tested: no additional live Telegram/Codex model call was run after these focused review fixes; previous broad and focused local verification is listed below.
Verification
pnpm test src/plugins/contracts/session-actions.contract.test.ts extensions/codex/media-understanding-provider.test.tsafter TypeBox-backed session-action result validation and shared Codex media-understanding runner refactorpnpm test src/plugins/contracts/session-actions.contract.test.ts src/plugins/contracts/session-attachments.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.ts src/plugins/captured-registration.test.ts src/plugins/loader.test.tsafter the host workflow split and registry loaded-plugin helper refactorpnpm test src/plugins/contracts/session-attachments.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.tsafter the contract fixture LOC-reduction refactorenv -u OPENCLAW_TESTBOX -u OPENCLAW_TESTBOX_REMOTE_RUN -u OPENCLAW_TESTBOX_ID pnpm check:changedafter the host workflow splitpnpm buildafter the host workflow module-boundary splitenv -u OPENCLAW_TESTBOX -u OPENCLAW_TESTBOX_REMOTE_RUN -u OPENCLAW_TESTBOX_ID pnpm check:changedafter the previous LOC-reduction refactorpnpm installafter rebasing onto currentorigin/maindependency changespnpm test src/gateway/method-scopes.test.ts src/plugins/contracts/session-actions.contract.test.ts src/plugins/contracts/session-attachments.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.ts src/media-understanding/runtime.test.ts extensions/codex/media-understanding-provider.test.ts extensions/telegram/src/outbound-adapter.test.ts src/agents/tools/gateway.test.tspnpm test extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/outbound-adapter.test.tsafter the Telegram formatting review fixpnpm protocol:checkafter the Swift generator idempotency review fixpnpm test src/plugins/contracts/session-actions.contract.test.tsafter the session action scope-copy review fixpnpm test src/plugins/loader.test.ts src/plugins/contracts/session-actions.contract.test.tsafter the late event emission policy review fixpnpm test src/infra/outbound/message-plan.test.ts src/infra/outbound/deliver.test.ts extensions/telegram/src/telegram-outbound.test.ts extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/outbound-adapter.test.tsafter the Telegram chunked-text HTML-mode review fixpnpm test extensions/telegram/src/telegram-outbound.test.ts extensions/telegram/src/channel.gateway.test.ts extensions/telegram/src/outbound-adapter.test.ts src/infra/outbound/message-plan.test.ts src/infra/outbound/deliver.test.tsafter the explicit Telegram HTML chunking review fixpnpm test src/plugins/contracts/host-hooks.contract.test.ts src/plugins/contracts/run-context-lifecycle.contract.test.ts src/plugins/contracts/scheduled-turns.contract.test.ts src/plugins/captured-registration.test.ts src/plugins/loader.test.tsafter namespaced internal fixture migrationpnpm check:docspnpm plugin-sdk:api:checkgit diff --checkenv -u OPENCLAW_TESTBOX -u OPENCLAW_TESTBOX_REMOTE_RUN -u OPENCLAW_TESTBOX_ID pnpm check:changedSwiftLint in
check:changedstill reports the pre-existing non-serious type-body-length warnings inapps/macos/Sources/OpenClaw/TalkModeRuntime.swiftandapps/macos/Sources/OpenClaw/NodeMode/MacNodeRuntime.swift; the command exits green.