diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index 13f4915848e..30567418aeb 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -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 diff --git a/docs/plugins/architecture-internals.md b/docs/plugins/architecture-internals.md index f67ec413ba8..9856a33015f 100644 --- a/docs/plugins/architecture-internals.md +++ b/docs/plugins/architecture-internals.md @@ -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 diff --git a/docs/plugins/sdk-channel-plugins.md b/docs/plugins/sdk-channel-plugins.md index c77661b085f..f13ea01378d 100644 --- a/docs/plugins/sdk-channel-plugins.md +++ b/docs/plugins/sdk-channel-plugins.md @@ -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`, diff --git a/docs/plugins/sdk-migration.md b/docs/plugins/sdk-migration.md index c98e883e22b..f9250578acc 100644 --- a/docs/plugins/sdk-migration.md +++ b/docs/plugins/sdk-migration.md @@ -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` | diff --git a/docs/plugins/sdk-setup.md b/docs/plugins/sdk-setup.md index 2ccc6b8cd7c..50aa17b3a64 100644 --- a/docs/plugins/sdk-setup.md +++ b/docs/plugins/sdk-setup.md @@ -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(...)`. diff --git a/docs/plugins/sdk-subpaths.md b/docs/plugins/sdk-subpaths.md index 911c1c5a3a6..90b1093d134 100644 --- a/docs/plugins/sdk-subpaths.md +++ b/docs/plugins/sdk-subpaths.md @@ -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` | diff --git a/extensions/discord/src/setup-adapter.ts b/extensions/discord/src/setup-adapter.ts index be3b2aa8938..8c8fce5203e 100644 --- a/extensions/discord/src/setup-adapter.ts +++ b/extensions/discord/src/setup-adapter.ts @@ -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; diff --git a/extensions/googlechat/runtime-api.ts b/extensions/googlechat/runtime-api.ts index e6aea683993..1518fa65ae9 100644 --- a/extensions/googlechat/runtime-api.ts +++ b/extensions/googlechat/runtime-api.ts @@ -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, diff --git a/extensions/googlechat/src/secret-contract.test.ts b/extensions/googlechat/src/secret-contract.test.ts index 31ef7aecbce..2a039b05671 100644 --- a/extensions/googlechat/src/secret-contract.test.ts +++ b/extensions/googlechat/src/secret-contract.test.ts @@ -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"; diff --git a/extensions/memory-core/src/public-artifacts.test.ts b/extensions/memory-core/src/public-artifacts.test.ts index 5921f55a500..08e96826355 100644 --- a/extensions/memory-core/src/public-artifacts.test.ts +++ b/extensions/memory-core/src/public-artifacts.test.ts @@ -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"; diff --git a/extensions/memory-core/src/public-artifacts.ts b/extensions/memory-core/src/public-artifacts.ts index 22f4991f5a8..e77c8f3789c 100644 --- a/extensions/memory-core/src/public-artifacts.ts +++ b/extensions/memory-core/src/public-artifacts.ts @@ -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"; diff --git a/extensions/memory-wiki/src/query.ts b/extensions/memory-wiki/src/query.ts index 09a63ff51d5..9e61365846e 100644 --- a/extensions/memory-wiki/src/query.ts +++ b/extensions/memory-wiki/src/query.ts @@ -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, diff --git a/extensions/qa-lab/src/suite-runtime-flow.ts b/extensions/qa-lab/src/suite-runtime-flow.ts index b17168f8e32..477b5dc8d49 100644 --- a/extensions/qa-lab/src/suite-runtime-flow.ts +++ b/extensions/qa-lab/src/suite-runtime-flow.ts @@ -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 { diff --git a/extensions/qqbot/src/secret-contract.test.ts b/extensions/qqbot/src/secret-contract.test.ts index 61e50c86382..e2a72b00bca 100644 --- a/extensions/qqbot/src/secret-contract.test.ts +++ b/extensions/qqbot/src/secret-contract.test.ts @@ -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"; diff --git a/extensions/telegram/src/doctor.test.ts b/extensions/telegram/src/doctor.test.ts index 15b9cec544a..1128e14c8c9 100644 --- a/extensions/telegram/src/doctor.test.ts +++ b/extensions/telegram/src/doctor.test.ts @@ -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, diff --git a/extensions/telegram/src/doctor.ts b/extensions/telegram/src/doctor.ts index cbb7ee3213e..2876fb2fd9a 100644 --- a/extensions/telegram/src/doctor.ts +++ b/extensions/telegram/src/doctor.ts @@ -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, diff --git a/extensions/tlon/src/logger-runtime.ts b/extensions/tlon/src/logger-runtime.ts index 7229cf5794f..bd132e0061a 100644 --- a/extensions/tlon/src/logger-runtime.ts +++ b/extensions/tlon/src/logger-runtime.ts @@ -1 +1 @@ -export { createLoggerBackedRuntime } from "openclaw/plugin-sdk/runtime-logger"; +export { createLoggerBackedRuntime } from "openclaw/plugin-sdk/runtime"; diff --git a/extensions/zai/api.ts b/extensions/zai/api.ts index f2c4dc6a256..17acef6d2b6 100644 --- a/extensions/zai/api.ts +++ b/extensions/zai/api.ts @@ -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, diff --git a/src/commands/zai-endpoint-detect.test.ts b/extensions/zai/detect.test.ts similarity index 96% rename from src/commands/zai-endpoint-detect.test.ts rename to extensions/zai/detect.test.ts index d7762bf11e3..b7131889866 100644 --- a/src/commands/zai-endpoint-detect.test.ts +++ b/extensions/zai/detect.test.ts @@ -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, }, diff --git a/extensions/zai/detect.ts b/extensions/zai/detect.ts index 482c383903b..2c87984c172 100644 --- a/extensions/zai/detect.ts +++ b/extensions/zai/detect.ts @@ -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 -): ReturnType { - 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 { + 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 { + 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 { + // 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; +} diff --git a/extensions/zai/runtime-api.ts b/extensions/zai/runtime-api.ts index f512627cde8..a521f66e95f 100644 --- a/extensions/zai/runtime-api.ts +++ b/extensions/zai/runtime-api.ts @@ -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"; diff --git a/scripts/lib/plugin-sdk-deprecated-public-subpaths.json b/scripts/lib/plugin-sdk-deprecated-public-subpaths.json index 0657d1b7c19..3cb396e419c 100644 --- a/scripts/lib/plugin-sdk-deprecated-public-subpaths.json +++ b/scripts/lib/plugin-sdk-deprecated-public-subpaths.json @@ -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" ] diff --git a/src/commands/auth-choice.test.ts b/src/commands/auth-choice.test.ts index 54ca11c1075..3fa425194db 100644 --- a/src/commands/auth-choice.test.ts +++ b/src/commands/auth-choice.test.ts @@ -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(async () => null)); -vi.mock("../plugins/provider-zai-endpoint.js", () => ({ - detectZaiEndpoint, -})); vi.mock("../agents/agent-scope.js", () => ({ resolveDefaultAgentId: () => "main", diff --git a/src/plugin-sdk/entrypoints.ts b/src/plugin-sdk/entrypoints.ts index 90dbd429ba8..36c46cec513 100644 --- a/src/plugin-sdk/entrypoints.ts +++ b/src/plugin-sdk/entrypoints.ts @@ -46,6 +46,7 @@ export const supportedBundledFacadeSdkEntrypoints = [ "matrix", "mattermost", "memory-core-engine-runtime", + "provider-zai-endpoint", "qa-runner-runtime", "telegram-account", "tts-runtime", diff --git a/src/plugin-sdk/memory-core-host-events.ts b/src/plugin-sdk/memory-core-host-events.ts index 8f68c7d1e6c..2effe90b472 100644 --- a/src/plugin-sdk/memory-core-host-events.ts +++ b/src/plugin-sdk/memory-core-host-events.ts @@ -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"; diff --git a/src/plugin-sdk/memory-host-files.ts b/src/plugin-sdk/memory-host-files.ts index 0776e9641fe..083044a529f 100644 --- a/src/plugin-sdk/memory-host-files.ts +++ b/src/plugin-sdk/memory-host-files.ts @@ -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"; diff --git a/src/plugin-sdk/memory-host-status.ts b/src/plugin-sdk/memory-host-status.ts index bcd3e1865fb..2e329aa6b3f 100644 --- a/src/plugin-sdk/memory-host-status.ts +++ b/src/plugin-sdk/memory-host-status.ts @@ -1 +1,6 @@ +/** + * @deprecated Compatibility alias. Import from + * `openclaw/plugin-sdk/memory-core-host-status` instead. + */ + export * from "./memory-core-host-status.js"; diff --git a/src/plugin-sdk/provider-zai-endpoint.ts b/src/plugin-sdk/provider-zai-endpoint.ts index d2c288b7ed6..750f620be68 100644 --- a/src/plugin-sdk/provider-zai-endpoint.ts +++ b/src/plugin-sdk/provider-zai-endpoint.ts @@ -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; + +type FacadeModule = { + detectZaiEndpoint: DetectZaiEndpoint; +}; + +function loadFacadeModule(): FacadeModule { + return loadBundledPluginPublicSurfaceModuleSync({ + dirName: "zai", + artifactBasename: "api.js", + }); +} + +/** @deprecated Z.AI provider-owned endpoint detection helper. */ +export const detectZaiEndpoint: DetectZaiEndpoint = ((...args) => + loadFacadeModule().detectZaiEndpoint(...args)) as DetectZaiEndpoint; diff --git a/src/plugin-sdk/runtime-logger.ts b/src/plugin-sdk/runtime-logger.ts index 92b1bfcba71..0faf906e1eb 100644 --- a/src/plugin-sdk/runtime-logger.ts +++ b/src/plugin-sdk/runtime-logger.ts @@ -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; diff --git a/src/plugin-sdk/runtime-secret-resolution.ts b/src/plugin-sdk/runtime-secret-resolution.ts index 80133ecd307..bc9903edddf 100644 --- a/src/plugin-sdk/runtime-secret-resolution.ts +++ b/src/plugin-sdk/runtime-secret-resolution.ts @@ -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"; diff --git a/src/plugin-sdk/secret-ref-runtime.ts b/src/plugin-sdk/secret-ref-runtime.ts index 0cb3c3146bd..c0428c29c91 100644 --- a/src/plugin-sdk/secret-ref-runtime.ts +++ b/src/plugin-sdk/secret-ref-runtime.ts @@ -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"; diff --git a/src/plugin-sdk/setup-adapter-runtime.ts b/src/plugin-sdk/setup-adapter-runtime.ts index 1042823c59d..685252f632f 100644 --- a/src/plugin-sdk/setup-adapter-runtime.ts +++ b/src/plugin-sdk/setup-adapter-runtime.ts @@ -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"; diff --git a/src/plugin-sdk/webhook-path.ts b/src/plugin-sdk/webhook-path.ts index fa68c9e20ee..a3db6d20310 100644 --- a/src/plugin-sdk/webhook-path.ts +++ b/src/plugin-sdk/webhook-path.ts @@ -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; diff --git a/src/plugins/contracts/plugin-sdk-runtime-api-guardrails.test.ts b/src/plugins/contracts/plugin-sdk-runtime-api-guardrails.test.ts index c6851c8a436..6fe49bfe741 100644 --- a/src/plugins/contracts/plugin-sdk-runtime-api-guardrails.test.ts +++ b/src/plugins/contracts/plugin-sdk-runtime-api-guardrails.test.ts @@ -63,7 +63,7 @@ const RUNTIME_API_EXPORT_GUARDS: Record = { '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";', diff --git a/src/plugins/provider-zai-endpoint.ts b/src/plugins/provider-zai-endpoint.ts deleted file mode 100644 index e1e5c9b20a6..00000000000 --- a/src/plugins/provider-zai-endpoint.ts +++ /dev/null @@ -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 { - 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 { - // 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; -}