mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-18 21:40:53 +00:00
* ACPX: keep plugin-local runtime installs out of dist * Gateway: harden ACP startup and service PATH * ACP: reinitialize error-state configured bindings * ACP: classify pre-turn runtime failures as session init failures * Plugins: move configured ACP routing behind channel seams * Telegram tests: align startup probe assertions after rebase * Discord: harden ACP configured binding recovery * ACP: recover Discord bindings after stale runtime exits * ACPX: replace dead sessions during ensure * Discord: harden ACP binding recovery * Discord: fix review follow-ups * ACP bindings: load channel snapshots across workspaces * ACP bindings: cache snapshot channel plugin resolution * Experiments: add ACP pluginification holy grail plan * Experiments: rename ACP pluginification plan doc * Experiments: drop old ACP pluginification doc path * ACP: move configured bindings behind plugin services * Experiments: update bindings capability architecture plan * Bindings: isolate configured binding routing and targets * Discord tests: fix runtime env helper path * Tests: fix channel binding CI regressions * Tests: normalize ACP workspace assertion on Windows * Bindings: isolate configured binding registry * Bindings: finish configured binding cleanup * Bindings: finish generic cleanup * Bindings: align runtime approval callbacks * ACP: delete residual bindings barrel * Bindings: restore legacy compatibility * Revert "Bindings: restore legacy compatibility" This reverts commit ac2ed68fa2426ecc874d68278c71c71ad363fcfe. * Tests: drop ACP route legacy helper names * Discord/ACP: fix binding regressions --------- Co-authored-by: Onur <2453968+osolmaz@users.noreply.github.com>
172 lines
4.2 KiB
TypeScript
172 lines
4.2 KiB
TypeScript
import type { OpenClawConfig } from "../../config/config.js";
|
|
import { loadConfig } from "../../config/config.js";
|
|
import {
|
|
loadSessionStore,
|
|
resolveAllAgentSessionStoreTargets,
|
|
resolveStorePath,
|
|
updateSessionStore,
|
|
} from "../../config/sessions.js";
|
|
import {
|
|
mergeSessionEntry,
|
|
type SessionAcpMeta,
|
|
type SessionEntry,
|
|
} from "../../config/sessions/types.js";
|
|
import { parseAgentSessionKey } from "../../routing/session-key.js";
|
|
|
|
export type AcpSessionStoreEntry = {
|
|
cfg: OpenClawConfig;
|
|
storePath: string;
|
|
sessionKey: string;
|
|
storeSessionKey: string;
|
|
entry?: SessionEntry;
|
|
acp?: SessionAcpMeta;
|
|
storeReadFailed?: boolean;
|
|
};
|
|
|
|
function resolveStoreSessionKey(store: Record<string, SessionEntry>, sessionKey: string): string {
|
|
const normalized = sessionKey.trim();
|
|
if (!normalized) {
|
|
return "";
|
|
}
|
|
if (store[normalized]) {
|
|
return normalized;
|
|
}
|
|
const lower = normalized.toLowerCase();
|
|
if (store[lower]) {
|
|
return lower;
|
|
}
|
|
for (const key of Object.keys(store)) {
|
|
if (key.toLowerCase() === lower) {
|
|
return key;
|
|
}
|
|
}
|
|
return lower;
|
|
}
|
|
|
|
export function resolveSessionStorePathForAcp(params: {
|
|
sessionKey: string;
|
|
cfg?: OpenClawConfig;
|
|
}): { cfg: OpenClawConfig; storePath: string } {
|
|
const cfg = params.cfg ?? loadConfig();
|
|
const parsed = parseAgentSessionKey(params.sessionKey);
|
|
const storePath = resolveStorePath(cfg.session?.store, {
|
|
agentId: parsed?.agentId,
|
|
});
|
|
return { cfg, storePath };
|
|
}
|
|
|
|
export function readAcpSessionEntry(params: {
|
|
sessionKey: string;
|
|
cfg?: OpenClawConfig;
|
|
}): AcpSessionStoreEntry | null {
|
|
const sessionKey = params.sessionKey.trim();
|
|
if (!sessionKey) {
|
|
return null;
|
|
}
|
|
const { cfg, storePath } = resolveSessionStorePathForAcp({
|
|
sessionKey,
|
|
cfg: params.cfg,
|
|
});
|
|
let store: Record<string, SessionEntry>;
|
|
let storeReadFailed = false;
|
|
try {
|
|
store = loadSessionStore(storePath);
|
|
} catch {
|
|
storeReadFailed = true;
|
|
store = {};
|
|
}
|
|
const storeSessionKey = resolveStoreSessionKey(store, sessionKey);
|
|
const entry = store[storeSessionKey];
|
|
return {
|
|
cfg,
|
|
storePath,
|
|
sessionKey,
|
|
storeSessionKey,
|
|
entry,
|
|
acp: entry?.acp,
|
|
storeReadFailed,
|
|
};
|
|
}
|
|
|
|
export async function listAcpSessionEntries(params: {
|
|
cfg?: OpenClawConfig;
|
|
env?: NodeJS.ProcessEnv;
|
|
}): Promise<AcpSessionStoreEntry[]> {
|
|
const cfg = params.cfg ?? loadConfig();
|
|
const storeTargets = await resolveAllAgentSessionStoreTargets(
|
|
cfg,
|
|
params.env ? { env: params.env } : undefined,
|
|
);
|
|
const entries: AcpSessionStoreEntry[] = [];
|
|
|
|
for (const target of storeTargets) {
|
|
const storePath = target.storePath;
|
|
let store: Record<string, SessionEntry>;
|
|
try {
|
|
store = loadSessionStore(storePath);
|
|
} catch {
|
|
continue;
|
|
}
|
|
for (const [sessionKey, entry] of Object.entries(store)) {
|
|
if (!entry?.acp) {
|
|
continue;
|
|
}
|
|
entries.push({
|
|
cfg,
|
|
storePath,
|
|
sessionKey,
|
|
storeSessionKey: sessionKey,
|
|
entry,
|
|
acp: entry.acp,
|
|
});
|
|
}
|
|
}
|
|
|
|
return entries;
|
|
}
|
|
|
|
export async function upsertAcpSessionMeta(params: {
|
|
sessionKey: string;
|
|
cfg?: OpenClawConfig;
|
|
mutate: (
|
|
current: SessionAcpMeta | undefined,
|
|
entry: SessionEntry | undefined,
|
|
) => SessionAcpMeta | null | undefined;
|
|
}): Promise<SessionEntry | null> {
|
|
const sessionKey = params.sessionKey.trim();
|
|
if (!sessionKey) {
|
|
return null;
|
|
}
|
|
const { storePath } = resolveSessionStorePathForAcp({
|
|
sessionKey,
|
|
cfg: params.cfg,
|
|
});
|
|
return await updateSessionStore(
|
|
storePath,
|
|
(store) => {
|
|
const storeSessionKey = resolveStoreSessionKey(store, sessionKey);
|
|
const currentEntry = store[storeSessionKey];
|
|
const nextMeta = params.mutate(currentEntry?.acp, currentEntry);
|
|
if (nextMeta === undefined) {
|
|
return currentEntry ?? null;
|
|
}
|
|
if (nextMeta === null && !currentEntry) {
|
|
return null;
|
|
}
|
|
|
|
const nextEntry = mergeSessionEntry(currentEntry, {
|
|
acp: nextMeta ?? undefined,
|
|
});
|
|
if (nextMeta === null) {
|
|
delete nextEntry.acp;
|
|
}
|
|
store[storeSessionKey] = nextEntry;
|
|
return nextEntry;
|
|
},
|
|
{
|
|
activeSessionKey: sessionKey.toLowerCase(),
|
|
allowDropAcpMetaSessionKeys: [sessionKey],
|
|
},
|
|
);
|
|
}
|