Files
openclaw/extensions/copilot/index.ts
Peter Steinberger ece92bcbde fix: persist Copilot SDK session bindings
Persist GitHub Copilot SDK session ids in the plugin-state SQLite store so separate OpenClaw process turns can resume the same Copilot-side session when the compatibility fingerprint still matches.

The fingerprint covers provider/model/cwd, resolved agent id, resolved Copilot home, and auth identity. Plugin-state lookup/register/delete failures are non-fatal, stale rows are invalidated, and reset delete failures use an in-process tombstone so reset does not accidentally reuse a durable binding.

Also routes the QQBot token POST through the plugin SDK SSRF guard with capture disabled for the secret-bearing request, preserving the current token lifetime validation from main.

Verification: focused Copilot and QQBot Vitest suites, raw channel fetch guard, autoreview clean, Blacksmith Testbox pnpm check:changed tbx_01kst9fwjmsfzwaxqatszcbf40, live local Copilot two-turn smoke with the same SDK session id persisted in SQLite.

Refs #88064
2026-05-29 18:46:03 +02:00

46 lines
1.3 KiB
TypeScript

import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
import { createCopilotAgentHarness, type CopilotSessionBinding } from "./harness.js";
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function readPoolOptions(pluginConfig: unknown): { idleTtlMs: number } | undefined {
if (!isRecord(pluginConfig)) {
return undefined;
}
const pool = pluginConfig.pool;
if (!isRecord(pool)) {
return undefined;
}
const idleTtlMs = pool.idleTtlMs;
if (typeof idleTtlMs !== "number" || !Number.isFinite(idleTtlMs) || idleTtlMs < 1) {
return undefined;
}
return { idleTtlMs };
}
export default definePluginEntry({
id: "copilot",
name: "GitHub Copilot agent runtime",
description: "Registers the GitHub Copilot agent runtime.",
register(api) {
const poolOptions = readPoolOptions(api.pluginConfig);
const sessionStore = api.runtime.state.openSyncKeyedStore<CopilotSessionBinding>({
namespace: "sdk-sessions",
maxEntries: 5000,
defaultTtlMs: 90 * 24 * 60 * 60 * 1000,
});
api.registerAgentHarness(
createCopilotAgentHarness({
...(poolOptions ? { poolOptions } : {}),
sessionStore,
}),
);
},
});