Covers the P1 scenario: session A holds SHARED_KEY via global env,
session B overrides it with a per-skill value. After B reverts,
process.env.SHARED_KEY must revert to 'global-value' (not remain as
the skill value). After A reverts, the key must be cleaned up entirely.
When session A holds SHARED_KEY via skills.env (global) and session B
temporarily overrides it with a per-skill value, reverting B previously
left process.env reflecting the skill value instead of restoring to the
global value — causing A to run under the wrong credential for the rest
of its lifetime.
Fix: track skillOwnerCount and globalValue on ActiveSkillEnvEntry.
When the last per-skill session releases a key that still has global
owners, downgrade active.value to the saved globalValue and update
process.env immediately. releaseActiveSkillEnvKey and createEnvReverter
now carry an isSkillOverride flag to drive this logic correctly.
Add hasSkillOwner flag to ActiveSkillEnvEntry. When a per-skill acquisition
comes in on a key that was previously only held by global-env passes, upgrade
the stored value and process.env to the skill's value. This ensures the
skill > global precedence invariant holds even when sessions overlap and the
global pass executes before the per-skill pass of a concurrent session.
Also add a concurrent-session regression test covering this scenario.
Add a top-level `skills.env` field in openclaw.json that provides
environment variable defaults shared across all skills. Individual
skill-level `env` entries still take precedence (skill > global).
Problem:
Users with multiple skills that share common env vars (e.g. OPENAI_API_KEY)
had to either repeat the key under each skill's `entries` block, or use
a .env file which is not visible in the JSON config and lacks per-skill
override capability.
Solution:
{
"skills": {
"env": { "OPENAI_API_KEY": "sk-..." },
"entries": {
"my-skill": {
"env": { "MY_SKILL_KEY": "..." }
}
}
}
}
Changes:
- src/config/types.skills.ts: add `env?` to SkillsConfig type
- src/config/zod-schema.ts: add `env` field to skills Zod schema (strict)
- src/agents/skills/env-overrides.ts: merge global env before skill-level
env; add global env keys to allowedSensitiveKeys so API keys pass
sanitization; thread globalEnv through both apply functions
- src/agents/skills/config.ts: hasEnv check now also resolves global env
Testing:
5 new unit tests in env-overrides.skills-global-env.test.ts:
- global env injected into process.env
- skill-level env overrides global for same key
- global env injected even when skill has no entries config
- global env does not override existing process.env values
- global env reverted after skill deactivation
- Added a test to ensure no warnings for legacy Brave config when bundled web search allowlist compatibility is applied.
- Updated validation logic to incorporate compatibility configuration for bundled web search plugins.
- Refactored the ensureRegistry function to utilize the new compatibility handling.
* test: align extension runtime mocks with plugin-sdk
Update stale extension tests to mock the plugin-sdk runtime barrels that production code now imports, and harden the Signal tool-result harness around system-event assertions so the channels lane matches current extension boundaries.
Regeneration-Prompt: |
Verify the failing channels-lane tests against current origin/main in an isolated worktree before changing anything. If the failures reproduce on main, keep the fix test-only unless production behavior is clearly wrong. Recent extension refactors moved Telegram, WhatsApp, and Signal code onto plugin-sdk runtime barrels, so update stale tests that still mock old core module paths to intercept the seams production code now uses. For Signal reaction notifications, avoid brittle assertions that depend on shared queued system-event state when a direct harness spy on enqueue behavior is sufficient. Preserve scope: only touch the failing tests and their local harness, then rerun the reproduced targeted tests plus the full channels lane and repo check gate.
* test: fix extension test drift on main
* fix: lazy-load bundled web search plugin registry
* test: make matrix sweeper failure injection portable
* fix: split heavy matrix runtime-api seams
* fix: simplify bundled web search id lookup
* test: tolerate windows env key casing
Reuse pi-ai's Anthropic client injection seam for streaming, and add
the OpenClaw-side provider discovery, auth, model catalog, and tests
needed to expose anthropic-vertex cleanly.
Signed-off-by: sallyom <somalley@redhat.com>