refactor(plugin-sdk): add shared helper utilities

This commit is contained in:
Peter Steinberger
2026-02-15 19:35:38 +00:00
parent 108f0ef8c4
commit 80eb91d9e7
5 changed files with 168 additions and 0 deletions

View File

@@ -0,0 +1,24 @@
export type AgentMediaPayload = {
MediaPath?: string;
MediaType?: string;
MediaUrl?: string;
MediaPaths?: string[];
MediaUrls?: string[];
MediaTypes?: string[];
};
export function buildAgentMediaPayload(
mediaList: Array<{ path: string; contentType?: string | null }>,
): AgentMediaPayload {
const first = mediaList[0];
const mediaPaths = mediaList.map((media) => media.path);
const mediaTypes = mediaList.map((media) => media.contentType).filter(Boolean) as string[];
return {
MediaPath: first?.path,
MediaType: first?.contentType ?? undefined,
MediaUrl: first?.path,
MediaPaths: mediaPaths.length > 0 ? mediaPaths : undefined,
MediaUrls: mediaPaths.length > 0 ? mediaPaths : undefined,
MediaTypes: mediaTypes.length > 0 ? mediaTypes : undefined,
};
}

View File

@@ -83,6 +83,15 @@ export type { OpenClawConfig as ClawdbotConfig } from "../config/config.js";
export type { FileLockHandle, FileLockOptions } from "./file-lock.js";
export { acquireFileLock, withFileLock } from "./file-lock.js";
export { normalizeWebhookPath, resolveWebhookPath } from "./webhook-path.js";
export type { AgentMediaPayload } from "./agent-media-payload.js";
export { buildAgentMediaPayload } from "./agent-media-payload.js";
export {
buildBaseChannelStatusSummary,
collectStatusIssuesFromLastError,
createDefaultChannelRuntimeState,
} from "./status-helpers.js";
export { buildOauthProviderAuthResult } from "./provider-auth-result.js";
export type { ChannelDock } from "../channels/dock.js";
export { getChatChannelMeta } from "../channels/registry.js";
export type {

View File

@@ -0,0 +1,47 @@
import type { AuthProfileCredential } from "../agents/auth-profiles/types.js";
import type { OpenClawConfig } from "../config/config.js";
import type { ProviderAuthResult } from "../plugins/types.js";
export function buildOauthProviderAuthResult(params: {
providerId: string;
defaultModel: string;
access: string;
refresh?: string | null;
expires?: number | null;
email?: string | null;
profilePrefix?: string;
credentialExtra?: Record<string, unknown>;
configPatch?: Partial<OpenClawConfig>;
notes?: string[];
}): ProviderAuthResult {
const email = params.email ?? undefined;
const profilePrefix = params.profilePrefix ?? params.providerId;
const profileId = `${profilePrefix}:${email ?? "default"}`;
const credential: AuthProfileCredential = {
type: "oauth",
provider: params.providerId,
access: params.access,
...(params.refresh ? { refresh: params.refresh } : {}),
...(Number.isFinite(params.expires) ? { expires: params.expires as number } : {}),
...(email ? { email } : {}),
...params.credentialExtra,
} as AuthProfileCredential;
return {
profiles: [{ profileId, credential }],
configPatch:
params.configPatch ??
({
agents: {
defaults: {
models: {
[params.defaultModel]: {},
},
},
},
} as Partial<OpenClawConfig>),
defaultModel: params.defaultModel,
notes: params.notes,
};
}

View File

@@ -0,0 +1,57 @@
import type { ChannelStatusIssue } from "../channels/plugins/types.js";
export function createDefaultChannelRuntimeState<T extends Record<string, unknown>>(
accountId: string,
extra?: T,
): {
accountId: string;
running: false;
lastStartAt: null;
lastStopAt: null;
lastError: null;
} & T {
return {
accountId,
running: false,
lastStartAt: null,
lastStopAt: null,
lastError: null,
...(extra ?? ({} as T)),
};
}
export function buildBaseChannelStatusSummary(snapshot: {
configured?: boolean | null;
running?: boolean | null;
lastStartAt?: number | null;
lastStopAt?: number | null;
lastError?: string | null;
}) {
return {
configured: snapshot.configured ?? false,
running: snapshot.running ?? false,
lastStartAt: snapshot.lastStartAt ?? null,
lastStopAt: snapshot.lastStopAt ?? null,
lastError: snapshot.lastError ?? null,
};
}
export function collectStatusIssuesFromLastError(
channel: string,
accounts: Array<{ accountId: string; lastError?: unknown }>,
): ChannelStatusIssue[] {
return accounts.flatMap((account) => {
const lastError = typeof account.lastError === "string" ? account.lastError.trim() : "";
if (!lastError) {
return [];
}
return [
{
channel,
accountId: account.accountId,
kind: "runtime",
message: `Channel error: ${lastError}`,
},
];
});
}

View File

@@ -0,0 +1,31 @@
export function normalizeWebhookPath(raw: string): string {
const trimmed = raw.trim();
if (!trimmed) {
return "/";
}
const withSlash = trimmed.startsWith("/") ? trimmed : `/${trimmed}`;
if (withSlash.length > 1 && withSlash.endsWith("/")) {
return withSlash.slice(0, -1);
}
return withSlash;
}
export function resolveWebhookPath(params: {
webhookPath?: string;
webhookUrl?: string;
defaultPath?: string | null;
}): string | null {
const trimmedPath = params.webhookPath?.trim();
if (trimmedPath) {
return normalizeWebhookPath(trimmedPath);
}
if (params.webhookUrl?.trim()) {
try {
const parsed = new URL(params.webhookUrl);
return normalizeWebhookPath(parsed.pathname || "/");
} catch {
return null;
}
}
return params.defaultPath ?? null;
}