refactor: move rare sdk seams into owners

This commit is contained in:
Peter Steinberger
2026-05-10 12:03:38 +01:00
parent 3363528720
commit 4f32a32ed6
35 changed files with 336 additions and 243 deletions

View File

@@ -1,2 +1,2 @@
a25794a905166b6cc5879855f0220d93a3686b3d7d46ef6eb931cff9f42a9c36 plugin-sdk-api-baseline.json
aeaee8496792b31443bdd37ab6b8499c590663500463d3a6a2033c6b804d9c73 plugin-sdk-api-baseline.jsonl
6db339525e3027401485b0979f97045fbe2a26af2d9d4868417ad81d4ea8987e plugin-sdk-api-baseline.json
40de1a9eb5c33666973530a0e5b199f5d039a243f41e2ea56adbdfe98db94bbb plugin-sdk-api-baseline.jsonl

View File

@@ -635,7 +635,7 @@ barrel when authoring new plugins. Core subpaths:
| `openclaw/plugin-sdk/config-schema` | Root `openclaw.json` Zod schema (`OpenClawSchema`) |
Channel plugins pick from a family of narrow seams — `channel-setup`,
`setup-runtime`, `setup-adapter-runtime`, `setup-tools`, `channel-pairing`,
`setup-runtime`, `setup-tools`, `channel-pairing`,
`channel-contract`, `channel-feedback`, `channel-inbound`, `channel-lifecycle`,
`channel-reply-pipeline`, `command-auth`, `secret-input`, `webhook-ingress`,
`channel-targets`, and `channel-actions`. Approval behavior should consolidate

View File

@@ -187,7 +187,7 @@ need one part of that family:
- `openclaw/plugin-sdk/channel-runtime-context`
Likewise, prefer `openclaw/plugin-sdk/setup-runtime`,
`openclaw/plugin-sdk/setup-adapter-runtime`,
`openclaw/plugin-sdk/setup-runtime`,
`openclaw/plugin-sdk/reply-runtime`,
`openclaw/plugin-sdk/reply-dispatch-runtime`,
`openclaw/plugin-sdk/reply-reference`, and
@@ -202,8 +202,8 @@ For setup specifically:
`createSetupInputPresenceValidator`), lookup-note output,
`promptResolvedAllowFrom`, `splitSetupEntries`, and the delegated
setup-proxy builders
- `openclaw/plugin-sdk/setup-adapter-runtime` is the narrow env-aware adapter
seam for `createEnvPatchedAccountSetupAdapter`
- `openclaw/plugin-sdk/setup-runtime` includes the env-aware adapter seam for
`createEnvPatchedAccountSetupAdapter`
- `openclaw/plugin-sdk/channel-setup` covers the optional-install setup
builders plus a few setup-safe primitives:
`createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`,

View File

@@ -500,7 +500,7 @@ releases.
| `plugin-sdk/channel-core` | Focused channel entry definitions and builders | `defineChannelPluginEntry`, `defineSetupPluginEntry`, `createChatChannelPlugin`, `createChannelPluginBase` |
| `plugin-sdk/setup` | Shared setup wizard helpers | Allowlist prompts, setup status builders |
| `plugin-sdk/setup-runtime` | Setup-time runtime helpers | Import-safe setup patch adapters, lookup-note helpers, `promptResolvedAllowFrom`, `splitSetupEntries`, delegated setup proxies |
| `plugin-sdk/setup-adapter-runtime` | Setup adapter helpers | `createEnvPatchedAccountSetupAdapter` |
| `plugin-sdk/setup-adapter-runtime` | Deprecated setup adapter alias | Use `plugin-sdk/setup-runtime` |
| `plugin-sdk/setup-tools` | Setup tooling helpers | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` |
| `plugin-sdk/account-core` | Multi-account helpers | Account list/config/action-gate helpers |
| `plugin-sdk/account-id` | Account-id helpers | `DEFAULT_ACCOUNT_ID`, account-id normalization |
@@ -635,7 +635,7 @@ releases.
| `plugin-sdk/direct-dm` | Direct-DM helpers | Shared direct-DM auth/guard helpers |
| `plugin-sdk/extension-shared` | Shared extension helpers | Passive-channel/status and ambient proxy helper primitives |
| `plugin-sdk/webhook-targets` | Webhook target helpers | Webhook target registry and route-install helpers |
| `plugin-sdk/webhook-path` | Webhook path helpers | Webhook path normalization helpers |
| `plugin-sdk/webhook-path` | Deprecated webhook path alias | Use `plugin-sdk/webhook-ingress` |
| `plugin-sdk/web-media` | Shared web media helpers | Remote/local media loading helpers |
| `plugin-sdk/zod` | Deprecated Zod compatibility re-export | Import `zod` from `zod` directly |
| `plugin-sdk/memory-core` | Bundled memory-core helpers | Memory manager/config/file/CLI helper surface |
@@ -647,17 +647,17 @@ releases.
| `plugin-sdk/memory-core-host-multimodal` | Memory host multimodal helpers | Memory host multimodal helpers |
| `plugin-sdk/memory-core-host-query` | Memory host query helpers | Memory host query helpers |
| `plugin-sdk/memory-core-host-secret` | Memory host secret helpers | Memory host secret helpers |
| `plugin-sdk/memory-core-host-events` | Memory host event journal helpers | Memory host event journal helpers |
| `plugin-sdk/memory-core-host-events` | Deprecated memory event alias | Use `plugin-sdk/memory-host-events` |
| `plugin-sdk/memory-core-host-status` | Memory host status helpers | Memory host status helpers |
| `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI runtime | Memory host CLI runtime helpers |
| `plugin-sdk/memory-core-host-runtime-core` | Memory host core runtime | Memory host core runtime helpers |
| `plugin-sdk/memory-core-host-runtime-files` | Memory host file/runtime helpers | Memory host file/runtime helpers |
| `plugin-sdk/memory-host-core` | Memory host core runtime alias | Vendor-neutral alias for memory host core runtime helpers |
| `plugin-sdk/memory-host-events` | Memory host event journal alias | Vendor-neutral alias for memory host event journal helpers |
| `plugin-sdk/memory-host-files` | Memory host file/runtime alias | Vendor-neutral alias for memory host file/runtime helpers |
| `plugin-sdk/memory-host-files` | Deprecated memory file/runtime alias | Use `plugin-sdk/memory-core-host-runtime-files` |
| `plugin-sdk/memory-host-markdown` | Managed markdown helpers | Shared managed-markdown helpers for memory-adjacent plugins |
| `plugin-sdk/memory-host-search` | Active memory search facade | Lazy active-memory search-manager runtime facade |
| `plugin-sdk/memory-host-status` | Memory host status alias | Vendor-neutral alias for memory host status helpers |
| `plugin-sdk/memory-host-status` | Deprecated memory host status alias | Use `plugin-sdk/memory-core-host-status` |
| `plugin-sdk/testing` | Test utilities | Repo-local deprecated compatibility barrel; use focused repo-local test subpaths such as `plugin-sdk/plugin-test-runtime`, `plugin-sdk/channel-test-helpers`, `plugin-sdk/channel-target-testing`, `plugin-sdk/test-env`, and `plugin-sdk/test-fixtures` |
</Accordion>

View File

@@ -327,7 +327,7 @@ For hot setup-only paths, prefer the narrow setup helper seams over the broader
| Import path | Use it for | Key exports |
| ---------------------------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `plugin-sdk/setup-runtime` | setup-time runtime helpers that stay available in `setupEntry` / deferred channel startup | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` |
| `plugin-sdk/setup-adapter-runtime` | environment-aware account setup adapters | `createEnvPatchedAccountSetupAdapter` |
| `plugin-sdk/setup-adapter-runtime` | deprecated compatibility alias; use `plugin-sdk/setup-runtime` | `createEnvPatchedAccountSetupAdapter` |
| `plugin-sdk/setup-tools` | setup/install CLI/archive/docs helpers | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` |
Use the broader `plugin-sdk/setup` seam when you want the full shared setup toolbox, including config-patch helpers such as `moveSingleAccountChannelSectionToDefaultAccount(...)`.

View File

@@ -86,7 +86,7 @@ focused channel/runtime subpaths, `config-contracts`, `string-coerce-runtime`,
| `plugin-sdk/channel-setup` | `createOptionalChannelSetupSurface`, `createOptionalChannelSetupAdapter`, `createOptionalChannelSetupWizard`, plus `DEFAULT_ACCOUNT_ID`, `createTopLevelChannelDmPolicy`, `setSetupChannelEnabled`, `splitSetupEntries` |
| `plugin-sdk/setup` | Shared setup wizard helpers, allowlist prompts, setup status builders |
| `plugin-sdk/setup-runtime` | `createPatchedAccountSetupAdapter`, `createEnvPatchedAccountSetupAdapter`, `createSetupInputPresenceValidator`, `noteChannelLookupFailure`, `noteChannelLookupSummary`, `promptResolvedAllowFrom`, `splitSetupEntries`, `createAllowlistSetupWizardProxy`, `createDelegatedSetupWizardProxy` |
| `plugin-sdk/setup-adapter-runtime` | `createEnvPatchedAccountSetupAdapter` |
| `plugin-sdk/setup-adapter-runtime` | Deprecated compatibility alias; use `plugin-sdk/setup-runtime` |
| `plugin-sdk/setup-tools` | `formatCliCommand`, `detectBinary`, `extractArchive`, `resolveBrewExecutable`, `formatDocsLink`, `CONFIG_DIR` |
| `plugin-sdk/account-core` | Multi-account config/action-gate helpers, default-account fallback helpers |
| `plugin-sdk/account-id` | `DEFAULT_ACCOUNT_ID`, account-id normalization helpers |
@@ -269,7 +269,7 @@ focused channel/runtime subpaths, `config-contracts`, `string-coerce-runtime`,
| `plugin-sdk/skill-commands-runtime` | Skill command listing helpers |
| `plugin-sdk/native-command-registry` | Native command registry/build/serialize helpers |
| `plugin-sdk/agent-harness` | Experimental trusted-plugin surface for low-level agent harnesses: harness types, active-run steer/abort helpers, OpenClaw tool bridge helpers, runtime-plan tool policy helpers, terminal outcome classification, tool progress formatting/detail helpers, and attempt result utilities |
| `plugin-sdk/provider-zai-endpoint` | Z.AI endpoint detection helpers |
| `plugin-sdk/provider-zai-endpoint` | Deprecated Z.AI provider-owned endpoint detection facade; use the Z.AI plugin public API |
| `plugin-sdk/async-lock-runtime` | Process-local async lock helper for small runtime state files |
| `plugin-sdk/channel-activity-runtime` | Channel activity telemetry helper |
| `plugin-sdk/concurrency-runtime` | Bounded async task concurrency helper |
@@ -320,7 +320,7 @@ focused channel/runtime subpaths, `config-contracts`, `string-coerce-runtime`,
| `plugin-sdk/video-generation` | Video generation provider/request/result types |
| `plugin-sdk/video-generation-core` | Shared video-generation types, failover helpers, provider lookup, and model-ref parsing |
| `plugin-sdk/webhook-targets` | Webhook target registry and route-install helpers |
| `plugin-sdk/webhook-path` | Webhook path normalization helpers |
| `plugin-sdk/webhook-path` | Deprecated compatibility alias; use `plugin-sdk/webhook-ingress` |
| `plugin-sdk/web-media` | Shared remote/local media loading helpers |
| `plugin-sdk/zod` | Deprecated compatibility re-export; import `zod` from `zod` directly |
| `plugin-sdk/testing` | Repo-local deprecated compatibility barrel for legacy OpenClaw tests. New repo tests should import focused local test subpaths such as `plugin-sdk/agent-runtime-test-contracts`, `plugin-sdk/plugin-test-runtime`, `plugin-sdk/channel-test-helpers`, `plugin-sdk/test-env`, or `plugin-sdk/test-fixtures` instead |
@@ -347,17 +347,17 @@ focused channel/runtime subpaths, `config-contracts`, `string-coerce-runtime`,
| `plugin-sdk/memory-core-host-multimodal` | Memory host multimodal helpers |
| `plugin-sdk/memory-core-host-query` | Memory host query helpers |
| `plugin-sdk/memory-core-host-secret` | Memory host secret helpers |
| `plugin-sdk/memory-core-host-events` | Memory host event journal helpers |
| `plugin-sdk/memory-core-host-events` | Deprecated compatibility alias; use `plugin-sdk/memory-host-events` |
| `plugin-sdk/memory-core-host-status` | Memory host status helpers |
| `plugin-sdk/memory-core-host-runtime-cli` | Memory host CLI runtime helpers |
| `plugin-sdk/memory-core-host-runtime-core` | Memory host core runtime helpers |
| `plugin-sdk/memory-core-host-runtime-files` | Memory host file/runtime helpers |
| `plugin-sdk/memory-host-core` | Vendor-neutral alias for memory host core runtime helpers |
| `plugin-sdk/memory-host-events` | Vendor-neutral alias for memory host event journal helpers |
| `plugin-sdk/memory-host-files` | Vendor-neutral alias for memory host file/runtime helpers |
| `plugin-sdk/memory-host-files` | Deprecated compatibility alias; use `plugin-sdk/memory-core-host-runtime-files` |
| `plugin-sdk/memory-host-markdown` | Shared managed-markdown helpers for memory-adjacent plugins |
| `plugin-sdk/memory-host-search` | Active memory runtime facade for search-manager access |
| `plugin-sdk/memory-host-status` | Vendor-neutral alias for memory host status helpers |
| `plugin-sdk/memory-host-status` | Deprecated compatibility alias; use `plugin-sdk/memory-core-host-status` |
</Accordion>
<Accordion title="Reserved bundled-helper subpaths">

View File

@@ -1,5 +1,7 @@
import { createEnvPatchedAccountSetupAdapter } from "openclaw/plugin-sdk/setup-adapter-runtime";
import type { ChannelSetupAdapter } from "openclaw/plugin-sdk/setup-runtime";
import {
createEnvPatchedAccountSetupAdapter,
type ChannelSetupAdapter,
} from "openclaw/plugin-sdk/setup-runtime";
const channel = "discord" as const;

View File

@@ -44,7 +44,7 @@ export type {
export { extractToolSend } from "openclaw/plugin-sdk/tool-send";
export { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";
export { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-path";
export { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";
export {
registerWebhookTargetWithPluginRoute,
resolveWebhookTargetWithAuthOrReject,

View File

@@ -3,7 +3,7 @@ import {
applyResolvedAssignments,
createResolverContext,
resolveSecretRefValues,
} from "openclaw/plugin-sdk/runtime-secret-resolution";
} from "openclaw/plugin-sdk/secret-ref-runtime";
import { describe, expect, it } from "vitest";
import { collectRuntimeConfigAssignments } from "./secret-contract.js";

View File

@@ -4,7 +4,7 @@ import path from "node:path";
import {
appendMemoryHostEvent,
resolveMemoryHostEventLogPath,
} from "openclaw/plugin-sdk/memory-core-host-events";
} from "openclaw/plugin-sdk/memory-host-events";
import { afterAll, beforeAll, describe, expect, it } from "vitest";
import type { OpenClawConfig } from "../api.js";
import { listMemoryCorePublicArtifacts } from "./public-artifacts.js";

View File

@@ -1,8 +1,8 @@
import fs from "node:fs/promises";
import path from "node:path";
import { resolveMemoryHostEventLogPath } from "openclaw/plugin-sdk/memory-core-host-events";
import { resolveMemoryDreamingWorkspaces } from "openclaw/plugin-sdk/memory-core-host-status";
import type { MemoryPluginPublicArtifact } from "openclaw/plugin-sdk/memory-host-core";
import { resolveMemoryHostEventLogPath } from "openclaw/plugin-sdk/memory-host-events";
import { pathExists } from "openclaw/plugin-sdk/security-runtime";
import type { OpenClawConfig } from "../api.js";

View File

@@ -1,7 +1,7 @@
import fs from "node:fs/promises";
import path from "node:path";
import type { MemorySearchResult } from "openclaw/plugin-sdk/memory-core-host-runtime-files";
import { resolveDefaultAgentId, resolveSessionAgentId } from "openclaw/plugin-sdk/memory-host-core";
import type { MemorySearchResult } from "openclaw/plugin-sdk/memory-host-files";
import { getActiveMemorySearchManager } from "openclaw/plugin-sdk/memory-host-search";
import {
extractTranscriptStemFromSessionsMemoryHit,

View File

@@ -2,8 +2,8 @@ import { randomUUID } from "node:crypto";
import fs from "node:fs/promises";
import path from "node:path";
import { setTimeout as sleep } from "node:timers/promises";
import { formatMemoryDreamingDay } from "openclaw/plugin-sdk/memory-core-host-status";
import { resolveSessionTranscriptsDirForAgent } from "openclaw/plugin-sdk/memory-host-core";
import { formatMemoryDreamingDay } from "openclaw/plugin-sdk/memory-host-status";
import { buildAgentSessionKey } from "openclaw/plugin-sdk/routing";
import { normalizeLowercaseStringOrEmpty } from "openclaw/plugin-sdk/string-coerce-runtime";
import {

View File

@@ -3,7 +3,7 @@ import {
applyResolvedAssignments,
createResolverContext,
resolveSecretRefValues,
} from "openclaw/plugin-sdk/runtime-secret-resolution";
} from "openclaw/plugin-sdk/secret-ref-runtime";
import { describe, expect, it } from "vitest";
import { collectRuntimeConfigAssignments } from "./secret-contract.js";

View File

@@ -20,7 +20,7 @@ const listTelegramAccountIdsMock = vi.hoisted(() => vi.fn());
const inspectTelegramAccountMock = vi.hoisted(() => vi.fn());
const lookupTelegramChatIdMock = vi.hoisted(() => vi.fn());
vi.mock("openclaw/plugin-sdk/runtime-secret-resolution", () => {
vi.mock("openclaw/plugin-sdk/runtime", () => {
return {
getChannelsCommandSecretTargetIds: () => ["channels"],
resolveCommandSecretRefsViaGateway: resolveCommandSecretRefsViaGatewayMock,

View File

@@ -346,7 +346,7 @@ export async function maybeRepairTelegramAllowFromUsernames(cfg: OpenClawConfig)
}
const { getChannelsCommandSecretTargetIds, resolveCommandSecretRefsViaGateway } =
await import("openclaw/plugin-sdk/runtime-secret-resolution");
await import("openclaw/plugin-sdk/runtime");
const { resolvedConfig } = await resolveCommandSecretRefsViaGateway({
config: cfg,

View File

@@ -1 +1 @@
export { createLoggerBackedRuntime } from "openclaw/plugin-sdk/runtime-logger";
export { createLoggerBackedRuntime } from "openclaw/plugin-sdk/runtime";

View File

@@ -1,4 +1,5 @@
export { applyZaiConfig, applyZaiProviderConfig, ZAI_DEFAULT_MODEL_REF } from "./onboard.js";
export { detectZaiEndpoint, type ZaiDetectedEndpoint, type ZaiEndpointId } from "./detect.js";
export {
buildZaiModelDefinition,
resolveZaiBaseUrl,

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { detectZaiEndpoint } from "../plugins/provider-zai-endpoint.js";
import { detectZaiEndpoint } from "./detect.js";
type FetchResponse = { status: number; body?: unknown };
@@ -76,7 +76,9 @@ describe("detectZaiEndpoint", () => {
status: 404,
body: { error: { message: "glm-5.1 unavailable" } },
},
"https://open.bigmodel.cn/api/coding/paas/v4/chat/completions::glm-4.7": { status: 200 },
"https://open.bigmodel.cn/api/coding/paas/v4/chat/completions::glm-4.7": {
status: 200,
},
},
expected: { endpoint: "coding-cn", modelId: "glm-4.7" },
},
@@ -89,7 +91,9 @@ describe("detectZaiEndpoint", () => {
"https://open.bigmodel.cn/api/coding/paas/v4/chat/completions::glm-5.1": {
status: 401,
},
"https://open.bigmodel.cn/api/coding/paas/v4/chat/completions::glm-4.7": { status: 401 },
"https://open.bigmodel.cn/api/coding/paas/v4/chat/completions::glm-4.7": {
status: 401,
},
},
expected: null,
},

View File

@@ -1,17 +1,195 @@
import {
detectZaiEndpoint as detectZaiEndpointCore,
type ZaiDetectedEndpoint,
type ZaiEndpointId,
} from "./runtime-api.js";
ZAI_CN_BASE_URL,
ZAI_CODING_CN_BASE_URL,
ZAI_CODING_GLOBAL_BASE_URL,
ZAI_DEFAULT_MODEL_ID,
ZAI_GLOBAL_BASE_URL,
} from "./model-definitions.js";
type DetectZaiEndpointFn = typeof detectZaiEndpointCore;
export type ZaiEndpointId = "global" | "cn" | "coding-global" | "coding-cn";
let detectZaiEndpointImpl: DetectZaiEndpointFn = detectZaiEndpointCore;
export type ZaiDetectedEndpoint = {
endpoint: ZaiEndpointId;
/** Provider baseUrl to store in config. */
baseUrl: string;
/** Recommended default model id for that endpoint. */
modelId: string;
/** Human-readable note explaining the choice. */
note: string;
};
export async function detectZaiEndpoint(
...args: Parameters<DetectZaiEndpointFn>
): ReturnType<DetectZaiEndpointFn> {
return await detectZaiEndpointImpl(...args);
type ProbeResult =
| { ok: true }
| {
ok: false;
status?: number;
errorCode?: string;
errorMessage?: string;
};
async function fetchWithTimeoutLocal(
fetchFn: typeof fetch,
url: string,
init: RequestInit,
timeoutMs: number,
): Promise<Response> {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), timeoutMs);
try {
return await fetchFn(url, { ...init, signal: controller.signal });
} finally {
clearTimeout(timeout);
}
}
export type { ZaiDetectedEndpoint, ZaiEndpointId };
async function probeZaiChatCompletions(params: {
baseUrl: string;
apiKey: string;
modelId: string;
timeoutMs: number;
fetchFn?: typeof fetch;
}): Promise<ProbeResult> {
try {
const fetchFn = params.fetchFn ?? globalThis.fetch;
const res = await fetchWithTimeoutLocal(
fetchFn,
`${params.baseUrl}/chat/completions`,
{
method: "POST",
headers: {
authorization: `Bearer ${params.apiKey}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: params.modelId,
stream: false,
max_tokens: 1,
messages: [{ role: "user", content: "ping" }],
}),
},
params.timeoutMs,
);
if (res.ok) {
return { ok: true };
}
let errorCode: string | undefined;
let errorMessage: string | undefined;
try {
const json = (await res.json()) as {
error?: { code?: unknown; message?: unknown };
msg?: unknown;
message?: unknown;
};
const code = json?.error?.code;
const msg = json?.error?.message ?? json?.msg ?? json?.message;
if (typeof code === "string") {
errorCode = code;
} else if (typeof code === "number") {
errorCode = String(code);
}
if (typeof msg === "string") {
errorMessage = msg;
}
} catch {
// ignore malformed error bodies
}
return { ok: false, status: res.status, errorCode, errorMessage };
} catch {
return { ok: false };
}
}
export async function detectZaiEndpoint(params: {
apiKey: string;
endpoint?: ZaiEndpointId;
timeoutMs?: number;
fetchFn?: typeof fetch;
}): Promise<ZaiDetectedEndpoint | null> {
// Never auto-probe in vitest; it would create flaky network behavior.
if (process.env.VITEST && !params.fetchFn) {
return null;
}
const timeoutMs = params.timeoutMs ?? 5_000;
const probeCandidates = (() => {
const general = [
{
endpoint: "global" as const,
baseUrl: ZAI_GLOBAL_BASE_URL,
modelId: ZAI_DEFAULT_MODEL_ID,
note: "Verified GLM-5.1 on global endpoint.",
},
{
endpoint: "cn" as const,
baseUrl: ZAI_CN_BASE_URL,
modelId: ZAI_DEFAULT_MODEL_ID,
note: "Verified GLM-5.1 on cn endpoint.",
},
];
const codingGlm51 = [
{
endpoint: "coding-global" as const,
baseUrl: ZAI_CODING_GLOBAL_BASE_URL,
modelId: ZAI_DEFAULT_MODEL_ID,
note: "Verified GLM-5.1 on coding-global endpoint.",
},
{
endpoint: "coding-cn" as const,
baseUrl: ZAI_CODING_CN_BASE_URL,
modelId: ZAI_DEFAULT_MODEL_ID,
note: "Verified GLM-5.1 on coding-cn endpoint.",
},
];
const codingFallback = [
{
endpoint: "coding-global" as const,
baseUrl: ZAI_CODING_GLOBAL_BASE_URL,
modelId: "glm-4.7",
note: "Coding Plan endpoint verified, but this key/plan does not expose GLM-5.1 there. Defaulting to GLM-4.7.",
},
{
endpoint: "coding-cn" as const,
baseUrl: ZAI_CODING_CN_BASE_URL,
modelId: "glm-4.7",
note: "Coding Plan CN endpoint verified, but this key/plan does not expose GLM-5.1 there. Defaulting to GLM-4.7.",
},
];
switch (params.endpoint) {
case "global":
return general.filter((candidate) => candidate.endpoint === "global");
case "cn":
return general.filter((candidate) => candidate.endpoint === "cn");
case "coding-global":
return [
...codingGlm51.filter((candidate) => candidate.endpoint === "coding-global"),
...codingFallback.filter((candidate) => candidate.endpoint === "coding-global"),
];
case "coding-cn":
return [
...codingGlm51.filter((candidate) => candidate.endpoint === "coding-cn"),
...codingFallback.filter((candidate) => candidate.endpoint === "coding-cn"),
];
default:
return [...general, ...codingGlm51, ...codingFallback];
}
})();
for (const candidate of probeCandidates) {
const result = await probeZaiChatCompletions({
baseUrl: candidate.baseUrl,
apiKey: params.apiKey,
modelId: candidate.modelId,
timeoutMs,
fetchFn: params.fetchFn,
});
if (result.ok) {
return candidate;
}
}
return null;
}

View File

@@ -1,5 +1 @@
export {
detectZaiEndpoint,
type ZaiDetectedEndpoint,
type ZaiEndpointId,
} from "openclaw/plugin-sdk/provider-zai-endpoint";
export { detectZaiEndpoint, type ZaiDetectedEndpoint, type ZaiEndpointId } from "./detect.js";

View File

@@ -20,16 +20,23 @@
"mattermost",
"media-generation-runtime-shared",
"memory-core-engine-runtime",
"memory-core-host-events",
"memory-core-host-multimodal",
"memory-core-host-query",
"memory-host-files",
"memory-host-status",
"music-generation-core",
"plugin-test-api",
"plugin-test-contracts",
"provider-auth-login",
"provider-http-test-mocks",
"provider-test-contracts",
"provider-zai-endpoint",
"reply-dedupe",
"runtime-logger",
"runtime-secret-resolution",
"self-hosted-provider-setup",
"setup-adapter-runtime",
"telegram-account",
"telegram-command-config",
"test-env",
@@ -37,6 +44,7 @@
"test-node-mocks",
"testing",
"text-runtime",
"webhook-path",
"zalouser",
"zod"
]

View File

@@ -17,7 +17,17 @@ import {
setupAuthTestEnv,
} from "./test-wizard-helpers.js";
type DetectZaiEndpoint = typeof import("../plugins/provider-zai-endpoint.js").detectZaiEndpoint;
type DetectZaiEndpoint = (params: {
apiKey: string;
endpoint?: "global" | "cn" | "coding-global" | "coding-cn";
timeoutMs?: number;
fetchFn?: typeof fetch;
}) => Promise<{
endpoint: "global" | "cn" | "coding-global" | "coding-cn";
baseUrl: string;
modelId: string;
note: string;
} | null>;
const GOOGLE_GEMINI_DEFAULT_MODEL = "google/gemini-3.1-pro-preview";
const ZAI_CODING_GLOBAL_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
@@ -67,9 +77,6 @@ vi.mock("./auth-choice.apply.api-providers.js", () => {
});
const detectZaiEndpoint = vi.hoisted(() => vi.fn<DetectZaiEndpoint>(async () => null));
vi.mock("../plugins/provider-zai-endpoint.js", () => ({
detectZaiEndpoint,
}));
vi.mock("../agents/agent-scope.js", () => ({
resolveDefaultAgentId: () => "main",

View File

@@ -46,6 +46,7 @@ export const supportedBundledFacadeSdkEntrypoints = [
"matrix",
"mattermost",
"memory-core-engine-runtime",
"provider-zai-endpoint",
"qa-runner-runtime",
"telegram-account",
"tts-runtime",

View File

@@ -1 +1,6 @@
/**
* @deprecated Compatibility alias. Import memory event helpers from
* `openclaw/plugin-sdk/memory-host-events` instead.
*/
export * from "../memory-host-sdk/events.js";

View File

@@ -1 +1,6 @@
/**
* @deprecated Compatibility alias. Import from
* `openclaw/plugin-sdk/memory-core-host-runtime-files` instead.
*/
export * from "./memory-core-host-runtime-files.js";

View File

@@ -1 +1,6 @@
/**
* @deprecated Compatibility alias. Import from
* `openclaw/plugin-sdk/memory-core-host-status` instead.
*/
export * from "./memory-core-host-status.js";

View File

@@ -1,7 +1,38 @@
// Public Z.AI endpoint detection helpers for provider plugins.
/**
* @deprecated Z.AI provider-owned endpoint detection helper. Use the bundled
* Z.AI plugin public API instead, or keep endpoint probing local to your
* provider plugin.
*/
export {
detectZaiEndpoint,
type ZaiDetectedEndpoint,
type ZaiEndpointId,
} from "../plugins/provider-zai-endpoint.js";
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-loader.js";
export type ZaiEndpointId = "global" | "cn" | "coding-global" | "coding-cn";
export type ZaiDetectedEndpoint = {
endpoint: ZaiEndpointId;
baseUrl: string;
modelId: string;
note: string;
};
type DetectZaiEndpoint = (params: {
apiKey: string;
endpoint?: ZaiEndpointId;
timeoutMs?: number;
fetchFn?: typeof fetch;
}) => Promise<ZaiDetectedEndpoint | null>;
type FacadeModule = {
detectZaiEndpoint: DetectZaiEndpoint;
};
function loadFacadeModule(): FacadeModule {
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
dirName: "zai",
artifactBasename: "api.js",
});
}
/** @deprecated Z.AI provider-owned endpoint detection helper. */
export const detectZaiEndpoint: DetectZaiEndpoint = ((...args) =>
loadFacadeModule().detectZaiEndpoint(...args)) as DetectZaiEndpoint;

View File

@@ -1,3 +1,8 @@
/**
* @deprecated Compatibility subpath. Import logger/runtime helpers from
* `openclaw/plugin-sdk/runtime` instead.
*/
import { format } from "node:util";
import type { OutputRuntimeEnv, RuntimeEnv } from "../runtime.js";
@@ -7,7 +12,7 @@ type LoggerLike = {
error: (message: string) => void;
};
/** Adapt a simple logger into the RuntimeEnv contract used by shared plugin SDK helpers. */
/** @deprecated Import from `openclaw/plugin-sdk/runtime` instead. */
export function createLoggerBackedRuntime(params: {
logger: LoggerLike;
exitError?: (code: number) => Error;
@@ -31,7 +36,7 @@ export function createLoggerBackedRuntime(params: {
};
}
/** Reuse an existing runtime when present, otherwise synthesize one from the provided logger. */
/** @deprecated Import from `openclaw/plugin-sdk/runtime` instead. */
export function resolveRuntimeEnv(params: {
runtime: RuntimeEnv;
logger: LoggerLike;
@@ -50,7 +55,7 @@ export function resolveRuntimeEnv(params: {
return params.runtime ?? createLoggerBackedRuntime(params);
}
/** Resolve a runtime that treats exit requests as unsupported errors instead of process termination. */
/** @deprecated Import from `openclaw/plugin-sdk/runtime` instead. */
export function resolveRuntimeEnvWithUnavailableExit(params: {
runtime: RuntimeEnv;
logger: LoggerLike;

View File

@@ -1,4 +1,14 @@
/**
* @deprecated Compatibility subpath. Import command secret helpers from
* `openclaw/plugin-sdk/runtime` and lower-level secret helpers from
* `openclaw/plugin-sdk/secret-ref-runtime` instead.
*/
/** @deprecated Import from `openclaw/plugin-sdk/runtime` instead. */
export { resolveCommandSecretRefsViaGateway } from "../cli/command-secret-gateway.js";
/** @deprecated Import from `openclaw/plugin-sdk/runtime` instead. */
export { getChannelsCommandSecretTargetIds } from "../cli/command-secret-targets.js";
/** @deprecated Import from `openclaw/plugin-sdk/secret-ref-runtime` instead. */
export { resolveSecretRefValues } from "../secrets/resolve.js";
/** @deprecated Import from `openclaw/plugin-sdk/secret-ref-runtime` instead. */
export { applyResolvedAssignments, createResolverContext } from "../secrets/runtime-shared.js";

View File

@@ -2,3 +2,5 @@
export { coerceSecretRef } from "../config/types.secrets.js";
export type { SecretInput, SecretRef } from "../config/types.secrets.js";
export { resolveSecretRefValues } from "../secrets/resolve.js";
export { applyResolvedAssignments, createResolverContext } from "../secrets/runtime-shared.js";

View File

@@ -1 +1,7 @@
/**
* @deprecated Compatibility subpath. Import setup helpers from
* `openclaw/plugin-sdk/setup-runtime` instead.
*/
/** @deprecated Import from `openclaw/plugin-sdk/setup-runtime` instead. */
export { createEnvPatchedAccountSetupAdapter } from "../channels/plugins/setup-helpers.js";

View File

@@ -1,4 +1,9 @@
/** Normalize webhook paths into the canonical registry form used by route lookup. */
/**
* @deprecated Compatibility subpath. Import webhook path helpers from
* `openclaw/plugin-sdk/webhook-ingress` instead.
*/
/** @deprecated Import from `openclaw/plugin-sdk/webhook-ingress` instead. */
export function normalizeWebhookPath(raw: string): string {
const trimmed = raw.trim();
if (!trimmed) {
@@ -11,7 +16,7 @@ export function normalizeWebhookPath(raw: string): string {
return withSlash;
}
/** Resolve the effective webhook path from explicit path, URL, or default fallback. */
/** @deprecated Import from `openclaw/plugin-sdk/webhook-ingress` instead. */
export function resolveWebhookPath(params: {
webhookPath?: string;
webhookUrl?: string;

View File

@@ -63,7 +63,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record<string, readonly string[]> = {
'export { extractToolSend } from "openclaw/plugin-sdk/tool-send";',
'export { resolveInboundMentionDecision } from "openclaw/plugin-sdk/channel-inbound";',
'export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "openclaw/plugin-sdk/inbound-envelope";',
'export { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-path";',
'export { resolveWebhookPath } from "openclaw/plugin-sdk/webhook-ingress";',
'export { registerWebhookTargetWithPluginRoute, resolveWebhookTargetWithAuthOrReject, withResolvedWebhookRequestPipeline } from "openclaw/plugin-sdk/webhook-targets";',
'export { createWebhookInFlightLimiter, readJsonWebhookBodyOrReject, type WebhookInFlightLimiter } from "openclaw/plugin-sdk/webhook-request-guards";',
'export { setGoogleChatRuntime } from "./src/runtime.js";',

View File

@@ -1,178 +0,0 @@
import { fetchWithTimeout } from "../utils/fetch-timeout.js";
const ZAI_CODING_GLOBAL_BASE_URL = "https://api.z.ai/api/coding/paas/v4";
const ZAI_CODING_CN_BASE_URL = "https://open.bigmodel.cn/api/coding/paas/v4";
const ZAI_GLOBAL_BASE_URL = "https://api.z.ai/api/paas/v4";
const ZAI_CN_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
export type ZaiEndpointId = "global" | "cn" | "coding-global" | "coding-cn";
export type ZaiDetectedEndpoint = {
endpoint: ZaiEndpointId;
/** Provider baseUrl to store in config. */
baseUrl: string;
/** Recommended default model id for that endpoint. */
modelId: string;
/** Human-readable note explaining the choice. */
note: string;
};
type ProbeResult =
| { ok: true }
| {
ok: false;
status?: number;
errorCode?: string;
errorMessage?: string;
};
async function probeZaiChatCompletions(params: {
baseUrl: string;
apiKey: string;
modelId: string;
timeoutMs: number;
fetchFn?: typeof fetch;
}): Promise<ProbeResult> {
try {
const res = await fetchWithTimeout(
`${params.baseUrl}/chat/completions`,
{
method: "POST",
headers: {
authorization: `Bearer ${params.apiKey}`,
"content-type": "application/json",
},
body: JSON.stringify({
model: params.modelId,
stream: false,
max_tokens: 1,
messages: [{ role: "user", content: "ping" }],
}),
},
params.timeoutMs,
params.fetchFn,
);
if (res.ok) {
return { ok: true };
}
let errorCode: string | undefined;
let errorMessage: string | undefined;
try {
const json = (await res.json()) as {
error?: { code?: unknown; message?: unknown };
msg?: unknown;
message?: unknown;
};
const code = json?.error?.code;
const msg = json?.error?.message ?? json?.msg ?? json?.message;
if (typeof code === "string") {
errorCode = code;
} else if (typeof code === "number") {
errorCode = String(code);
}
if (typeof msg === "string") {
errorMessage = msg;
}
} catch {
// ignore
}
return { ok: false, status: res.status, errorCode, errorMessage };
} catch {
return { ok: false };
}
}
export async function detectZaiEndpoint(params: {
apiKey: string;
endpoint?: ZaiEndpointId;
timeoutMs?: number;
fetchFn?: typeof fetch;
}): Promise<ZaiDetectedEndpoint | null> {
// Never auto-probe in vitest; it would create flaky network behavior.
if (process.env.VITEST && !params.fetchFn) {
return null;
}
const timeoutMs = params.timeoutMs ?? 5_000;
const probeCandidates = (() => {
const general = [
{
endpoint: "global" as const,
baseUrl: ZAI_GLOBAL_BASE_URL,
modelId: "glm-5.1",
note: "Verified GLM-5.1 on global endpoint.",
},
{
endpoint: "cn" as const,
baseUrl: ZAI_CN_BASE_URL,
modelId: "glm-5.1",
note: "Verified GLM-5.1 on cn endpoint.",
},
];
const codingGlm51 = [
{
endpoint: "coding-global" as const,
baseUrl: ZAI_CODING_GLOBAL_BASE_URL,
modelId: "glm-5.1",
note: "Verified GLM-5.1 on coding-global endpoint.",
},
{
endpoint: "coding-cn" as const,
baseUrl: ZAI_CODING_CN_BASE_URL,
modelId: "glm-5.1",
note: "Verified GLM-5.1 on coding-cn endpoint.",
},
];
const codingFallback = [
{
endpoint: "coding-global" as const,
baseUrl: ZAI_CODING_GLOBAL_BASE_URL,
modelId: "glm-4.7",
note: "Coding Plan endpoint verified, but this key/plan does not expose GLM-5.1 there. Defaulting to GLM-4.7.",
},
{
endpoint: "coding-cn" as const,
baseUrl: ZAI_CODING_CN_BASE_URL,
modelId: "glm-4.7",
note: "Coding Plan CN endpoint verified, but this key/plan does not expose GLM-5.1 there. Defaulting to GLM-4.7.",
},
];
switch (params.endpoint) {
case "global":
return general.filter((candidate) => candidate.endpoint === "global");
case "cn":
return general.filter((candidate) => candidate.endpoint === "cn");
case "coding-global":
return [
...codingGlm51.filter((candidate) => candidate.endpoint === "coding-global"),
...codingFallback.filter((candidate) => candidate.endpoint === "coding-global"),
];
case "coding-cn":
return [
...codingGlm51.filter((candidate) => candidate.endpoint === "coding-cn"),
...codingFallback.filter((candidate) => candidate.endpoint === "coding-cn"),
];
default:
return [...general, ...codingGlm51, ...codingFallback];
}
})();
for (const candidate of probeCandidates) {
const result = await probeZaiChatCompletions({
baseUrl: candidate.baseUrl,
apiKey: params.apiKey,
modelId: candidate.modelId,
timeoutMs,
fetchFn: params.fetchFn,
});
if (result.ok) {
return candidate;
}
}
return null;
}