Skip to content

plugins: preserve qveris runtime surfaces#121

Merged
linfangw merged 6665 commits into
mainfrom
linfangw-upstream-sync-2026-04-15
Apr 17, 2026
Merged

plugins: preserve qveris runtime surfaces#121
linfangw merged 6665 commits into
mainfrom
linfangw-upstream-sync-2026-04-15

Conversation

@linfangw

Copy link
Copy Markdown
Member

Summary

  • Problem: bundled plugin public-surface resolution and legacy QVeris global installs could interfere with the fork's runtime web-search/provider loading after build or update flows.
  • Why it matters: QVerisBot needs the bundled qveris plugin and its web search surface to win consistently in the packaged runtime, and local diagnostics should not report false gateway exposure alarms.
  • What changed: added the extensions/qveris/web-search-provider.ts public surface, taught bundled public-surface resolution to prefer built artifacts, skipped legacy global qveris shadows in the manifest registry, moved dotenv / file-type / ipaddr.js loads behind runtime seams, removed the old bundled web-search registry, and updated the affected tests.
  • What did NOT change (scope boundary): no protocol changes, no upstream repo targeting changes, and no new external service surface beyond the existing QVeris integration.

Change Type

  • Bug fix
  • Feature
  • Refactor required for the fix
  • Docs
  • Security hardening
  • Chore/infra

Scope

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

  • Closes #
  • Related #
  • This PR fixes a bug or regression

Root Cause

  • Root cause: the fork still had mixed source-vs-built plugin public-surface resolution and a legacy global qveris install path could shadow the bundled plugin during manifest loading.
  • Missing detection / guardrail: runtime path selection and duplicate-manifest handling did not have enough coverage for the fork's packaged/runtime layout.
  • Contributing context (if known): the fork carries QVeris-specific plugin wiring on top of upstream changes, so runtime path assumptions need to stay explicit.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
    • Seam / integration test
    • End-to-end test
    • Existing coverage already sufficient
  • Target test or file: src/plugins/public-surface-runtime.test.ts, src/commands/gateway-status.test.ts, src/cli/update-cli.test.ts, test/scripts/test-install-sh-docker.test.ts
  • Scenario the test should lock in: packaged/runtime resolution prefers built bundled artifacts, gateway diagnostics stay deterministic, and install/update flows keep the expected runtime plugin surfaces.
  • Why this is the smallest reliable guardrail: the regression lives at the runtime seam between bundled plugin metadata, dist layout, and fork-specific plugin wiring.
  • Existing test that already covers this (if any): src/plugins/public-surface-runtime.test.ts
  • If no new test is added, why not: N/A

User-visible / Behavior Changes

  • Bundled QVeris runtime/provider loading now prefers the packaged public surface instead of drifting to source-layout assumptions.
  • Legacy global QVeris plugin leftovers under the state dir no longer shadow the bundled plugin.
  • Doctor network exposure warnings now use deterministic host-side bind resolution for diagnostics.

Diagram

Before:
[bundled qveris runtime] -> [mixed source/dist lookup or legacy global shadow] -> [wrong plugin surface picked]

After:
[bundled qveris runtime] -> [prefer built public artifact + ignore legacy shadow] -> [stable bundled provider surface]

Security Impact

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation: N/A

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: local Node 22 workspace
  • Model/provider: N/A
  • Integration/channel (if any): QVeris bundled plugin runtime surfaces
  • Relevant config (redacted): default local fork setup

Steps

  1. Run env OPENCLAW_LOCAL_CHECK=0 pnpm test src/plugins/public-surface-runtime.test.ts src/commands/gateway-status.test.ts src/cli/update-cli.test.ts test/scripts/test-install-sh-docker.test.ts.
  2. Run pnpm build and inspect the runtime-postbuild chain.
  3. Verify the branch pushes cleanly to QVerisAI/QVerisBot and opens against main.

Expected

  • Bundled runtime/public-surface resolution stays stable and the targeted tests pass.

Actual

  • Targeted tests passed locally. pnpm build reached runtime-postbuild without surfacing a compile error, but the local run did not terminate cleanly in this sandboxed session, so I did not record a green full-build exit.

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification

  • Verified scenarios: targeted tests above, clean commit, clean push to origin/QVerisAI/QVerisBot, and PR target set to main.
  • Edge cases checked: source checkout vs built artifact resolution, legacy global qveris shadow handling, deterministic doctor bind-host resolution.
  • What you did not verify: a fully completed local pnpm build exit in this sandbox session.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps: N/A

Risks and Mitigations

  • Risk: fork-specific runtime path logic can drift again if upstream changes the bundled plugin dist layout.
    • Mitigation: keep the public-surface runtime tests and install/update regression tests covering the packaged layout.

vincentkoc and others added 30 commits April 14, 2026 16:07
* fix(memory): align qmd read paths

Co-authored-by: zsx <git@zsxsoft.com>

* fix(memory): add qmd exact-path read fast path

* fix(memory): tighten qmd read-path guards

* changelog: note QMD memory_get canonical-path restriction (openclaw#66026)

---------

Co-authored-by: zsx <git@zsxsoft.com>
Co-authored-by: Devin Robison <drobison@nvidia.com>
…hexsprite)

* fix: forward optional params dropped at the runEmbeddedAttempt call site

runEmbeddedPiAgent in pi-embedded-runner/run.ts hand-enumerates ~85 fields
when calling runEmbeddedAttempt({...}). Several optional fields on
RunEmbeddedPiAgentParams were added to the type and to attempt.ts (the
consumer) but were never wired at this specific call site. Because every
field is declared as ?: optional on EmbeddedRunAttemptParams, TypeScript
does not flag the missing fields and the attempt silently receives
undefined for each.

Four fields were affected:

- toolsAllow (openclaw#58504, openclaw#62569): cron's --tools allow-list. Persisted in
  jobs.json by the CLI, forwarded by cron/isolated-agent/run-executor.ts
  to runEmbeddedPiAgent, but dropped here. Result: provider request
  ships the full tool catalog on every cron run regardless of toolsAllow,
  defeating the ~95% input-token reduction documented in openclaw#58504 and the
  --tools restriction documented in docs/automation/cron-jobs.md:85.

- disableMessageTool: cron/isolated-agent/run-executor.ts:164 sets it
  from toolPolicy.disableMessageTool, derived at run.ts:110 as
  `params.deliveryContract === "cron-owned" ? true : params.deliveryRequested`.
  Every cron-owned delivery (the default per docs) is supposed to disable
  the message tool so the runner owns the final delivery path. Without
  forwarding, the agent can call messaging tools mid-cron and cause
  duplicate or wrong-channel sends.

- requireExplicitMessageTarget: cron/isolated-agent/run-executor.ts:163
  sets it from toolPolicy.requireExplicitMessageTarget. Has a fallback at
  attempt.ts:568-569 to `?? isSubagentSessionKey(params.sessionKey)`, so
  non-subagent crons silently get false instead of the intended value.

- internalEvents: agents/command/attempt-execution.ts:478 passes it via
  params.opts.internalEvents. Different caller path from cron, but the
  same drop point. Internal events array silently dropped before reaching
  the consumer at attempt.ts:1480.

The fix is four lines in the runEmbeddedAttempt({...}) call, immediately
after the bootstrapContextMode/bootstrapContextRunKind lines added by
PR openclaw#62264 (which fixed two more fields with the identical pattern at the
same call site).

A regression test (run.attempt-param-forwarding.test.ts) covers all six
optional fields shown to have been bitten by this class of bug at this
seam. The next ?: optional field added to RunEmbeddedPiAgentParams without
wiring at the runEmbeddedAttempt call site will fail a test instead of
silently shipping broken — addressing the missing-guardrail concern PR
openclaw#60776's writeup explicitly noted.

Verified locally: 6/6 forwarding tests pass, 258 pi-embedded-runner/run*
tests pass, 176 cron/isolated-agent tests pass, oxlint and tsgo deltas
versus origin/main are zero.

Fixes openclaw#62569

* test: distill param forwarding guardrails

* fix: restore embedded-run param forwarding (openclaw#62675) (thanks @hexsprite)

---------

Co-authored-by: Ayaan Zaidi <hi@obviy.us>
vincentkoc and others added 27 commits April 15, 2026 10:46
… (openclaw#64790)

Merged via squash.

Prepared head SHA: 324202d
Co-authored-by: feiskyer <676637+feiskyer@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Reviewed-by: @vincentkoc
… race (openclaw#64188) (openclaw#66528)

Merged via squash.

Prepared head SHA: 0c4003a
Co-authored-by: feiskyer <676637+feiskyer@users.noreply.github.com>
Co-authored-by: vincentkoc <25068+vincentkoc@users.noreply.github.com>
Reviewed-by: @vincentkoc
Merged via squash.

Prepared head SHA: 29c8068
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Co-authored-by: hxy91819 <8814856+hxy91819@users.noreply.github.com>
Reviewed-by: @hxy91819
…7099)

* fix(plugins): localize bundled runtime deps to extensions

* fix(plugins): move staged runtime deps out of root

* fix(packaging): harden prepack and runtime dep staging

* fix(packaging): preserve optional runtime dep staging

* Update CHANGELOG.md

* fix(packaging): harden runtime staging filesystem writes

* fix(docker): ship preinstall warning in bootstrap layers

* fix(packaging): exclude staged plugin node_modules from npm pack
…claw#67047)

Merged via squash.

Prepared head SHA: 5ce11d0
Co-authored-by: Unayung <1853105+Unayung@users.noreply.github.com>
Co-authored-by: frankekn <712880+frankekn@users.noreply.github.com>
Reviewed-by: @frankekn
…ync-2026-04-15

# Conflicts:
#	.github/workflows/install-smoke.yml
#	docs/.generated/config-baseline.json
#	docs/.generated/config-baseline.jsonl
#	docs/.generated/plugin-sdk-api-baseline.json
#	docs/.generated/plugin-sdk-api-baseline.jsonl
#	docs/channels/feishu.md
#	docs/ci.md
#	extensions/acpx/package.json
#	extensions/amazon-bedrock/package.json
#	extensions/anthropic-vertex/package.json
#	extensions/anthropic/package.json
#	extensions/bluebubbles/package.json
#	extensions/brave/package.json
#	extensions/browser/package.json
#	extensions/browser/src/browser/routes/agent.debug.ts
#	extensions/browser/src/browser/routes/agent.snapshot.ts
#	extensions/browser/src/browser/routes/agent.storage.ts
#	extensions/byteplus/package.json
#	extensions/chutes/package.json
#	extensions/cloudflare-ai-gateway/package.json
#	extensions/copilot-proxy/package.json
#	extensions/deepgram/package.json
#	extensions/deepseek/package.json
#	extensions/diagnostics-otel/package.json
#	extensions/diffs/package.json
#	extensions/discord/package.json
#	extensions/discord/src/monitor/agent-components-helpers.ts
#	extensions/discord/src/monitor/agent-components.ts
#	extensions/discord/src/monitor/native-command.ts
#	extensions/discord/src/monitor/provider.ts
#	extensions/duckduckgo/package.json
#	extensions/elevenlabs/package.json
#	extensions/exa/package.json
#	extensions/fal/package.json
#	extensions/feishu/package.json
#	extensions/firecrawl/package.json
#	extensions/github-copilot/package.json
#	extensions/google/package.json
#	extensions/googlechat/package.json
#	extensions/groq/package.json
#	extensions/huggingface/package.json
#	extensions/image-generation-core/package.json
#	extensions/imessage/package.json
#	extensions/irc/package.json
#	extensions/kilocode/package.json
#	extensions/kimi-coding/package.json
#	extensions/line/package.json
#	extensions/line/src/bot-message-context.ts
#	extensions/litellm/package.json
#	extensions/llm-task/package.json
#	extensions/lobster/package.json
#	extensions/matrix/CHANGELOG.md
#	extensions/matrix/package.json
#	extensions/mattermost/package.json
#	extensions/media-understanding-core/package.json
#	extensions/memory-core/package.json
#	extensions/memory-lancedb/package.json
#	extensions/microsoft-foundry/package.json
#	extensions/microsoft/package.json
#	extensions/minimax/package.json
#	extensions/mistral/package.json
#	extensions/modelstudio/package.json
#	extensions/moonshot/package.json
#	extensions/msteams/CHANGELOG.md
#	extensions/msteams/package.json
#	extensions/nextcloud-talk/package.json
#	extensions/nostr/CHANGELOG.md
#	extensions/nostr/package.json
#	extensions/nvidia/package.json
#	extensions/ollama/package.json
#	extensions/open-prose/package.json
#	extensions/openai/package.json
#	extensions/opencode-go/package.json
#	extensions/opencode/package.json
#	extensions/openrouter/package.json
#	extensions/openshell/package.json
#	extensions/perplexity/package.json
#	extensions/qianfan/package.json
#	extensions/qqbot/package.json
#	extensions/searxng/package.json
#	extensions/sglang/package.json
#	extensions/signal/package.json
#	extensions/slack/package.json
#	extensions/speech-core/package.json
#	extensions/stepfun/package.json
#	extensions/synology-chat/package.json
#	extensions/synthetic/package.json
#	extensions/tavily/package.json
#	extensions/telegram/package.json
#	extensions/telegram/src/bot-handlers.buffers.ts
#	extensions/telegram/src/bot.ts
#	extensions/telegram/src/bot/delivery.resolve-media-retry.test.ts
#	extensions/telegram/src/fetch.network-policy.test.ts
#	extensions/tlon/package.json
#	extensions/together/package.json
#	extensions/twitch/CHANGELOG.md
#	extensions/twitch/package.json
#	extensions/venice/package.json
#	extensions/vercel-ai-gateway/package.json
#	extensions/vllm/package.json
#	extensions/voice-call/CHANGELOG.md
#	extensions/voice-call/package.json
#	extensions/volcengine/package.json
#	extensions/whatsapp/package.json
#	extensions/whatsapp/src/auto-reply.test-harness.ts
#	extensions/xai/package.json
#	extensions/xiaomi/package.json
#	extensions/zai/package.json
#	extensions/zalo/CHANGELOG.md
#	extensions/zalo/package.json
#	extensions/zalo/src/monitor.webhook.ts
#	extensions/zalouser/CHANGELOG.md
#	extensions/zalouser/package.json
#	package.json
#	pnpm-lock.yaml
#	scripts/docker/install-sh-e2e/run.sh
#	scripts/docker/install-sh-smoke/run.sh
#	scripts/lib/plugin-sdk-entrypoints.json
#	scripts/test-install-sh-docker.sh
#	scripts/test-planner/executor.mjs
#	src/agents/openclaw-tools.ts
#	src/agents/pi-embedded-runner/compact.ts
#	src/agents/pi-embedded-runner/run/types.ts
#	src/agents/pi-tools.create-openclaw-coding-tools.adds-claude-style-aliases-schemas-without-dropping.test.ts
#	src/agents/skills.loadworkspaceskillentries.test.ts
#	src/agents/skills.test.ts
#	src/agents/system-prompt.test.ts
#	src/agents/system-prompt.ts
#	src/agents/tools/message-tool.ts
#	src/agents/tools/session-status-tool.ts
#	src/agents/tools/web-fetch.test-harness.ts
#	src/auto-reply/reply/commands-core.ts
#	src/auto-reply/reply/get-reply-run.ts
#	src/auto-reply/reply/model-selection.ts
#	src/cli/gateway-cli/run.ts
#	src/cli/program/command-registry.ts
#	src/cli/update-cli.test.ts
#	src/commands/onboard-search.test.ts
#	src/config/schema.base.generated.ts
#	src/config/types.models.ts
#	src/config/types.tools.ts
#	src/config/validation.ts
#	src/config/zod-schema.core.ts
#	src/cron/isolated-agent/delivery-target.ts
#	src/cron/service.issue-regressions.test.ts
#	src/daemon/systemd.ts
#	src/gateway/server-reload-handlers.ts
#	src/gateway/server.agent.gateway-server-agent-b.test.ts
#	src/gateway/server.chat.gateway-server-chat.test.ts
#	src/gateway/server.impl.ts
#	src/gateway/server.sessions.gateway-server-sessions-a.test.ts
#	src/gateway/test-helpers.mocks.ts
#	src/hooks/hooks-status.ts
#	src/infra/exec-approvals.ts
#	src/infra/outbound/message-action-runner.ts
#	src/infra/update-global.ts
#	src/infra/update-runner.ts
#	src/plugin-sdk/anthropic-vertex-auth-presence.ts
#	src/plugin-sdk/browser-config.ts
#	src/plugin-sdk/compat.ts
#	src/plugin-sdk/whatsapp-auth-presence.ts
#	src/plugins/bundled-provider-auth-env-vars.generated.ts
#	src/plugins/manifest-registry.ts
#	src/plugins/runtime/runtime-channel.ts
#	src/plugins/runtime/types-channel.ts
#	src/plugins/web-search-providers.test.ts
#	src/security/audit-channel.ts
#	src/wizard/setup.ts
#	test/helpers/plugins/plugin-runtime-mock.ts
#	ui/src/ui/views/chat.ts

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the OpenClaw ecosystem to version 2026.4.14, introducing new agent skills for QA testing and secret scanning, an incident response plan, and stricter contribution limits. Key technical changes include local MLX-based speech synthesis for macOS, remote TTS support for Android, and a new execution approval workflow for iOS and Apple Watch. Feedback for the Android app identifies a logic discrepancy where manual gateway connections fail if the port is left blank, despite UI placeholders suggesting a default of 18789.

Comment on lines +247 to +251
val port = if (portTrimmed.isEmpty()) {
if (tls) 443 else return null
} else {
portTrimmed.toIntOrNull() ?: return null
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The composeGatewayManualUrl function returns null for non-TLS connections if the port is empty. However, the UI placeholder in ConnectTabScreen and OnboardingFlow suggests a default port of 18789 for non-TLS connections. This discrepancy causes a validation error when a user leaves the port field blank, expecting the default behavior. It should default to 18789 to match the parseGatewayEndpoint logic and UI expectations.

Suggested change
val port = if (portTrimmed.isEmpty()) {
if (tls) 443 else return null
} else {
portTrimmed.toIntOrNull() ?: return null
}
val port = if (portTrimmed.isEmpty()) {
if (tls) 443 else 18789
} else {
portTrimmed.toIntOrNull() ?: return null
}

@linfangw
linfangw marked this pull request as ready for review April 17, 2026 09:05
@linfangw
linfangw merged commit b460421 into main Apr 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.