diff --git a/CHANGELOG.md b/CHANGELOG.md index fb0e02c7125..7e1bb73e9fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -110,6 +110,7 @@ Docs: https://docs.openclaw.ai - Memory/LanceDB: keep auto-recall and auto-capture hooks wired when those settings start disabled, so turning them on in live config starts recall and capture without waiting for a restart. Thanks @vincentkoc. - Skill Workshop: keep the tool plus `before_prompt_build` / `agent_end` hooks wired while the plugin is disabled at startup, so turning the plugin back on in live config starts guidance and capture without waiting for a restart. Thanks @vincentkoc. - Active Memory: stop reviving removed live `active-memory` config from startup snapshots, so removing the plugin entry turns the hook off immediately instead of waiting for a restart. Thanks @vincentkoc. +- GitHub Copilot: re-read plugin discovery config from the live runtime snapshot, so toggling `plugins.entries.github-copilot.config.discovery.enabled` takes effect without a restart. Thanks @vincentkoc. - Agents/subagents: drop bare `NO_REPLY` from the parent turn when the session still has pending spawned children, so direct-conversation surfaces such as Telegram DMs no longer rewrite the sentinel into visible fallback chatter while waiting for the child completion event. (#69942) Thanks @neeravmakwana. - Plugins/install: keep bundled plugin dependencies off npm install while repairing them when plugins activate from a packaged install, including Feishu/Lark, Browser, and direct bundled channel setup-entry loads. - CLI/channels: skip and cache bundled channel plugin, setup, and secrets load failures during read-only discovery, so one broken unused bundled channel cannot crash `openclaw status` or bootstrap secret scans. diff --git a/extensions/github-copilot/index.test.ts b/extensions/github-copilot/index.test.ts index 3f68d8748a7..bdb15174230 100644 --- a/extensions/github-copilot/index.test.ts +++ b/extensions/github-copilot/index.test.ts @@ -61,7 +61,17 @@ describe("github-copilot plugin", () => { const provider = registerProviderWithPluginConfig({ discovery: { enabled: false } }); const result = await provider.catalog.run({ - config: {}, + config: { + plugins: { + entries: { + "github-copilot": { + config: { + discovery: { enabled: false }, + }, + }, + }, + }, + }, agentDir: "/tmp/agent", env: { GH_TOKEN: "gh_test_token" }, resolveProviderApiKey: () => ({ apiKey: "gh_test_token" }), @@ -70,4 +80,40 @@ describe("github-copilot plugin", () => { expect(result).toBeNull(); expect(resolveCopilotApiTokenMock).not.toHaveBeenCalled(); }); + + it("uses live plugin config to re-enable discovery after startup disable", async () => { + resolveCopilotApiTokenMock.mockResolvedValueOnce({ + token: "copilot_api_token", + baseUrl: "https://api.githubcopilot.live", + }); + const provider = registerProviderWithPluginConfig({ discovery: { enabled: false } }); + + const result = await provider.catalog.run({ + config: { + plugins: { + entries: { + "github-copilot": { + config: { + discovery: { enabled: true }, + }, + }, + }, + }, + }, + agentDir: "/tmp/agent", + env: { GH_TOKEN: "gh_test_token" }, + resolveProviderApiKey: () => ({ apiKey: "gh_test_token" }), + } as never); + + expect(resolveCopilotApiTokenMock).toHaveBeenCalledWith({ + githubToken: "gh_test_token", + env: { GH_TOKEN: "gh_test_token" }, + }); + expect(result).toEqual({ + provider: { + baseUrl: "https://api.githubcopilot.live", + models: [], + }, + }); + }); }); diff --git a/extensions/github-copilot/index.ts b/extensions/github-copilot/index.ts index e335c085b51..a22d7732234 100644 --- a/extensions/github-copilot/index.ts +++ b/extensions/github-copilot/index.ts @@ -1,3 +1,7 @@ +import { + resolvePluginConfigObject, + type OpenClawConfig, +} from "openclaw/plugin-sdk/config-runtime"; import { definePluginEntry, type ProviderAuthContext } from "openclaw/plugin-sdk/plugin-entry"; import { ensureAuthProfileStore } from "openclaw/plugin-sdk/provider-auth"; import { normalizeOptionalLowercaseString } from "openclaw/plugin-sdk/text-runtime"; @@ -24,7 +28,15 @@ export default definePluginEntry({ name: "GitHub Copilot Provider", description: "Bundled GitHub Copilot provider plugin", register(api) { - const pluginConfig = (api.pluginConfig ?? {}) as GithubCopilotPluginConfig; + const startupPluginConfig = (api.pluginConfig ?? {}) as GithubCopilotPluginConfig; + + function resolveCurrentPluginConfig(config?: OpenClawConfig): GithubCopilotPluginConfig { + const runtimePluginConfig = resolvePluginConfigObject(config, "github-copilot"); + if (runtimePluginConfig) { + return runtimePluginConfig as GithubCopilotPluginConfig; + } + return config ? {} : startupPluginConfig; + } async function runGitHubCopilotAuth(ctx: ProviderAuthContext) { const { githubCopilotLoginCommand } = await loadGithubCopilotRuntime(); @@ -100,6 +112,7 @@ export default definePluginEntry({ catalog: { order: "late", run: async (ctx) => { + const pluginConfig = resolveCurrentPluginConfig(ctx.config); const discoveryEnabled = pluginConfig.discovery?.enabled ?? ctx.config?.models?.copilotDiscovery?.enabled; if (discoveryEnabled === false) {