refactor: unify plugin sdk primitives
This commit is contained in:
parent
bea90b72e6
commit
07d9f725b6
@ -925,6 +925,12 @@ authoring plugins:
|
|||||||
|
|
||||||
- `openclaw/plugin-sdk/plugin-entry` for plugin registration primitives.
|
- `openclaw/plugin-sdk/plugin-entry` for plugin registration primitives.
|
||||||
- `openclaw/plugin-sdk/core` for the generic shared plugin-facing contract.
|
- `openclaw/plugin-sdk/core` for the generic shared plugin-facing contract.
|
||||||
|
- Stable channel primitives such as `openclaw/plugin-sdk/channel-setup`,
|
||||||
|
`openclaw/plugin-sdk/channel-pairing`,
|
||||||
|
`openclaw/plugin-sdk/channel-reply-pipeline`,
|
||||||
|
`openclaw/plugin-sdk/secret-input`, and
|
||||||
|
`openclaw/plugin-sdk/webhook-ingress` for shared setup/auth/reply/webhook
|
||||||
|
wiring.
|
||||||
- Domain subpaths such as `openclaw/plugin-sdk/channel-config-helpers`,
|
- Domain subpaths such as `openclaw/plugin-sdk/channel-config-helpers`,
|
||||||
`openclaw/plugin-sdk/channel-config-schema`,
|
`openclaw/plugin-sdk/channel-config-schema`,
|
||||||
`openclaw/plugin-sdk/channel-policy`,
|
`openclaw/plugin-sdk/channel-policy`,
|
||||||
@ -961,6 +967,9 @@ authoring plugins:
|
|||||||
Compatibility note:
|
Compatibility note:
|
||||||
|
|
||||||
- Avoid the root `openclaw/plugin-sdk` barrel for new code.
|
- Avoid the root `openclaw/plugin-sdk` barrel for new code.
|
||||||
|
- Prefer the narrow stable primitives first. The newer setup/pairing/reply/
|
||||||
|
secret-input/webhook subpaths are the intended contract for new bundled and
|
||||||
|
external plugin work.
|
||||||
- Bundled extension-specific helper barrels are not stable by default. If a
|
- Bundled extension-specific helper barrels are not stable by default. If a
|
||||||
helper is only needed by a bundled extension, keep it behind the extension's
|
helper is only needed by a bundled extension, keep it behind the extension's
|
||||||
local `api.js` or `runtime-api.js` seam instead of promoting it into
|
local `api.js` or `runtime-api.js` seam instead of promoting it into
|
||||||
|
|||||||
@ -95,8 +95,10 @@ subpaths rather than the monolithic root:
|
|||||||
```typescript
|
```typescript
|
||||||
// Correct: focused subpaths
|
// Correct: focused subpaths
|
||||||
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
|
import { defineChannelPluginEntry } from "openclaw/plugin-sdk/core";
|
||||||
import { resolveOutboundSendDep } from "openclaw/plugin-sdk/channel-runtime";
|
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
||||||
|
import { createChannelPairingController } from "openclaw/plugin-sdk/channel-pairing";
|
||||||
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
import { createPluginRuntimeStore } from "openclaw/plugin-sdk/runtime-store";
|
||||||
|
import { createOptionalChannelSetupSurface } from "openclaw/plugin-sdk/channel-setup";
|
||||||
import { resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
import { resolveChannelGroupRequireMention } from "openclaw/plugin-sdk/channel-policy";
|
||||||
|
|
||||||
// Wrong: monolithic root (lint will reject this)
|
// Wrong: monolithic root (lint will reject this)
|
||||||
@ -105,17 +107,24 @@ import { ... } from "openclaw/plugin-sdk";
|
|||||||
|
|
||||||
Common subpaths:
|
Common subpaths:
|
||||||
|
|
||||||
| Subpath | Purpose |
|
| Subpath | Purpose |
|
||||||
| ---------------------------------- | ------------------------------------ |
|
| ----------------------------------- | ------------------------------------ |
|
||||||
| `plugin-sdk/core` | Plugin entry definitions, base types |
|
| `plugin-sdk/core` | Plugin entry definitions, base types |
|
||||||
| `plugin-sdk/channel-runtime` | Channel runtime helpers |
|
| `plugin-sdk/channel-setup` | Optional setup adapters/wizards |
|
||||||
| `plugin-sdk/channel-config-schema` | Config schema builders |
|
| `plugin-sdk/channel-pairing` | DM pairing primitives |
|
||||||
| `plugin-sdk/channel-policy` | Group/DM policy helpers |
|
| `plugin-sdk/channel-reply-pipeline` | Prefix + typing reply wiring |
|
||||||
| `plugin-sdk/setup` | Setup wizard adapters |
|
| `plugin-sdk/channel-config-schema` | Config schema builders |
|
||||||
| `plugin-sdk/runtime-store` | Persistent plugin storage |
|
| `plugin-sdk/channel-policy` | Group/DM policy helpers |
|
||||||
| `plugin-sdk/allow-from` | Allowlist resolution |
|
| `plugin-sdk/secret-input` | Secret input parsing/helpers |
|
||||||
| `plugin-sdk/reply-payload` | Message reply types |
|
| `plugin-sdk/webhook-ingress` | Webhook request/target helpers |
|
||||||
| `plugin-sdk/testing` | Test utilities |
|
| `plugin-sdk/runtime-store` | Persistent plugin storage |
|
||||||
|
| `plugin-sdk/allow-from` | Allowlist resolution |
|
||||||
|
| `plugin-sdk/reply-payload` | Message reply types |
|
||||||
|
| `plugin-sdk/provider-onboard` | Provider onboarding config patches |
|
||||||
|
| `plugin-sdk/testing` | Test utilities |
|
||||||
|
|
||||||
|
Use the narrowest primitive that matches the job. Reach for `channel-runtime`
|
||||||
|
or other larger helper barrels only when a dedicated subpath does not exist yet.
|
||||||
|
|
||||||
## Step 4: Use local barrels for internal imports
|
## Step 4: Use local barrels for internal imports
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,6 @@
|
|||||||
import {
|
|
||||||
hasConfiguredSecretInput,
|
|
||||||
normalizeResolvedSecretInputString,
|
|
||||||
normalizeSecretInputString,
|
|
||||||
} from "openclaw/plugin-sdk/secret-input-runtime";
|
|
||||||
import { buildSecretInputSchema } from "openclaw/plugin-sdk/secret-input-schema";
|
|
||||||
export {
|
export {
|
||||||
buildSecretInputSchema,
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
};
|
} from "openclaw/plugin-sdk/secret-input";
|
||||||
|
|||||||
@ -6,7 +6,7 @@ import {
|
|||||||
} from "openclaw/plugin-sdk/provider-models";
|
} from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyAgentDefaultModelPrimary,
|
||||||
applyProviderConfigWithModelCatalog,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
@ -17,24 +17,20 @@ export { CHUTES_DEFAULT_MODEL_REF };
|
|||||||
* Registers all catalog models and sets provider aliases (chutes-fast, etc.).
|
* Registers all catalog models and sets provider aliases (chutes-fast, etc.).
|
||||||
*/
|
*/
|
||||||
export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyChutesProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
for (const m of CHUTES_MODEL_CATALOG) {
|
|
||||||
models[`chutes/${m.id}`] = {
|
|
||||||
...models[`chutes/${m.id}`],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
models["chutes-fast"] = { alias: "chutes/zai-org/GLM-4.7-FP8" };
|
|
||||||
models["chutes-vision"] = { alias: "chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506" };
|
|
||||||
models["chutes-pro"] = { alias: "chutes/deepseek-ai/DeepSeek-V3.2-TEE" };
|
|
||||||
|
|
||||||
const chutesModels = CHUTES_MODEL_CATALOG.map(buildChutesModelDefinition);
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "chutes",
|
providerId: "chutes",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
baseUrl: CHUTES_BASE_URL,
|
baseUrl: CHUTES_BASE_URL,
|
||||||
catalogModels: chutesModels,
|
catalogModels: CHUTES_MODEL_CATALOG.map(buildChutesModelDefinition),
|
||||||
|
aliases: [
|
||||||
|
...CHUTES_MODEL_CATALOG.map((model) => `chutes/${model.id}`),
|
||||||
|
{ modelRef: "chutes-fast", alias: "chutes/zai-org/GLM-4.7-FP8" },
|
||||||
|
{
|
||||||
|
modelRef: "chutes-vision",
|
||||||
|
alias: "chutes/chutesai/Mistral-Small-3.2-24B-Instruct-2506",
|
||||||
|
},
|
||||||
|
{ modelRef: "chutes-pro", alias: "chutes/deepseek-ai/DeepSeek-V3.2-TEE" },
|
||||||
|
],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { ChannelType, type RequestClient } from "@buape/carbon";
|
import { ChannelType, type RequestClient } from "@buape/carbon";
|
||||||
import { resolveAckReaction, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
import { resolveAckReaction, resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
||||||
import { EmbeddedBlockChunker } from "openclaw/plugin-sdk/agent-runtime";
|
import { EmbeddedBlockChunker } from "openclaw/plugin-sdk/agent-runtime";
|
||||||
|
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
||||||
import { shouldAckReaction as shouldAckReactionGate } from "openclaw/plugin-sdk/channel-runtime";
|
import { shouldAckReaction as shouldAckReactionGate } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { logTypingFailure, logAckFailure } from "openclaw/plugin-sdk/channel-runtime";
|
import { logTypingFailure, logAckFailure } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime";
|
|
||||||
import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime";
|
import { recordInboundSession } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import {
|
import {
|
||||||
createStatusReactionController,
|
createStatusReactionController,
|
||||||
DEFAULT_TIMING,
|
DEFAULT_TIMING,
|
||||||
type StatusReactionAdapter,
|
type StatusReactionAdapter,
|
||||||
} from "openclaw/plugin-sdk/channel-runtime";
|
} from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
||||||
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime";
|
import { isDangerousNameMatchingEnabled } from "openclaw/plugin-sdk/config-runtime";
|
||||||
import { resolveDiscordPreviewStreamMode } from "openclaw/plugin-sdk/config-runtime";
|
import { resolveDiscordPreviewStreamMode } from "openclaw/plugin-sdk/config-runtime";
|
||||||
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
|
||||||
@ -420,11 +419,24 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
|||||||
? deliverTarget.slice("channel:".length)
|
? deliverTarget.slice("channel:".length)
|
||||||
: messageChannelId;
|
: messageChannelId;
|
||||||
|
|
||||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
|
||||||
cfg,
|
cfg,
|
||||||
agentId: route.agentId,
|
agentId: route.agentId,
|
||||||
channel: "discord",
|
channel: "discord",
|
||||||
accountId: route.accountId,
|
accountId: route.accountId,
|
||||||
|
typing: {
|
||||||
|
start: () => sendTyping({ client, channelId: typingChannelId }),
|
||||||
|
onStartError: (err) => {
|
||||||
|
logTypingFailure({
|
||||||
|
log: logVerbose,
|
||||||
|
channel: "discord",
|
||||||
|
target: typingChannelId,
|
||||||
|
error: err,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
// Long tool-heavy runs are expected on Discord; keep heartbeats alive.
|
||||||
|
maxDurationMs: DISCORD_TYPING_MAX_DURATION_MS,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
const tableMode = resolveMarkdownTableMode({
|
const tableMode = resolveMarkdownTableMode({
|
||||||
cfg,
|
cfg,
|
||||||
@ -438,20 +450,6 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
|||||||
});
|
});
|
||||||
const chunkMode = resolveChunkMode(cfg, "discord", accountId);
|
const chunkMode = resolveChunkMode(cfg, "discord", accountId);
|
||||||
|
|
||||||
const typingCallbacks = createTypingCallbacks({
|
|
||||||
start: () => sendTyping({ client, channelId: typingChannelId }),
|
|
||||||
onStartError: (err) => {
|
|
||||||
logTypingFailure({
|
|
||||||
log: logVerbose,
|
|
||||||
channel: "discord",
|
|
||||||
target: typingChannelId,
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
// Long tool-heavy runs are expected on Discord; keep heartbeats alive.
|
|
||||||
maxDurationMs: DISCORD_TYPING_MAX_DURATION_MS,
|
|
||||||
});
|
|
||||||
|
|
||||||
// --- Discord draft stream (edit-based preview streaming) ---
|
// --- Discord draft stream (edit-based preview streaming) ---
|
||||||
const discordStreamMode = resolveDiscordPreviewStreamMode(discordConfig);
|
const discordStreamMode = resolveDiscordPreviewStreamMode(discordConfig);
|
||||||
const draftMaxChars = Math.min(textLimit, 2000);
|
const draftMaxChars = Math.min(textLimit, 2000);
|
||||||
@ -597,9 +595,8 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
|||||||
|
|
||||||
const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } =
|
const { dispatcher, replyOptions, markDispatchIdle, markRunComplete } =
|
||||||
createReplyDispatcherWithTyping({
|
createReplyDispatcherWithTyping({
|
||||||
...prefixOptions,
|
...replyPipeline,
|
||||||
humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
|
humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
|
||||||
typingCallbacks,
|
|
||||||
deliver: async (payload: ReplyPayload, info) => {
|
deliver: async (payload: ReplyPayload, info) => {
|
||||||
if (isProcessAborted(abortSignal)) {
|
if (isProcessAborted(abortSignal)) {
|
||||||
return;
|
return;
|
||||||
@ -715,7 +712,7 @@ export async function processDiscordMessage(ctx: DiscordMessagePreflightContext)
|
|||||||
if (isProcessAborted(abortSignal)) {
|
if (isProcessAborted(abortSignal)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await typingCallbacks.onReplyStart();
|
await replyPipeline.typingCallbacks?.onReplyStart();
|
||||||
await statusReactions.setThinking();
|
await statusReactions.setThinking();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@ -10,10 +10,9 @@ import {
|
|||||||
buildAgentMediaPayload,
|
buildAgentMediaPayload,
|
||||||
buildPendingHistoryContextFromMap,
|
buildPendingHistoryContextFromMap,
|
||||||
clearHistoryEntriesIfEnabled,
|
clearHistoryEntriesIfEnabled,
|
||||||
createScopedPairingAccess,
|
createChannelPairingController,
|
||||||
DEFAULT_GROUP_HISTORY_LIMIT,
|
DEFAULT_GROUP_HISTORY_LIMIT,
|
||||||
type HistoryEntry,
|
type HistoryEntry,
|
||||||
issuePairingChallenge,
|
|
||||||
normalizeAgentId,
|
normalizeAgentId,
|
||||||
recordPendingHistoryEntryIfEnabled,
|
recordPendingHistoryEntryIfEnabled,
|
||||||
resolveAgentOutboundIdentity,
|
resolveAgentOutboundIdentity,
|
||||||
@ -445,7 +444,7 @@ export async function handleFeishuMessage(params: {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
const core = getFeishuRuntime();
|
const core = getFeishuRuntime();
|
||||||
const pairing = createScopedPairingAccess({
|
const pairing = createChannelPairingController({
|
||||||
core,
|
core,
|
||||||
channel: "feishu",
|
channel: "feishu",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
@ -471,12 +470,10 @@ export async function handleFeishuMessage(params: {
|
|||||||
|
|
||||||
if (isDirect && dmPolicy !== "open" && !dmAllowed) {
|
if (isDirect && dmPolicy !== "open" && !dmAllowed) {
|
||||||
if (dmPolicy === "pairing") {
|
if (dmPolicy === "pairing") {
|
||||||
await issuePairingChallenge({
|
await pairing.issueChallenge({
|
||||||
channel: "feishu",
|
|
||||||
senderId: ctx.senderOpenId,
|
senderId: ctx.senderOpenId,
|
||||||
senderIdLine: `Your Feishu user id: ${ctx.senderOpenId}`,
|
senderIdLine: `Your Feishu user id: ${ctx.senderOpenId}`,
|
||||||
meta: { name: ctx.senderName },
|
meta: { name: ctx.senderName },
|
||||||
upsertPairingRequest: pairing.upsertPairingRequest,
|
|
||||||
onCreated: () => {
|
onCreated: () => {
|
||||||
log(`feishu[${account.accountId}]: pairing request sender=${ctx.senderOpenId}`);
|
log(`feishu[${account.accountId}]: pairing request sender=${ctx.senderOpenId}`);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
import {
|
|
||||||
buildSecretInputSchema,
|
|
||||||
hasConfiguredSecretInput,
|
|
||||||
normalizeResolvedSecretInputString,
|
|
||||||
normalizeSecretInputString,
|
|
||||||
} from "../runtime-api.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
buildSecretInputSchema,
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
};
|
} from "openclaw/plugin-sdk/secret-input";
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
GROUP_POLICY_BLOCKED_LABEL,
|
GROUP_POLICY_BLOCKED_LABEL,
|
||||||
createScopedPairingAccess,
|
createChannelPairingController,
|
||||||
evaluateGroupRouteAccessForPolicy,
|
evaluateGroupRouteAccessForPolicy,
|
||||||
issuePairingChallenge,
|
|
||||||
isDangerousNameMatchingEnabled,
|
isDangerousNameMatchingEnabled,
|
||||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||||
resolveDefaultGroupPolicy,
|
resolveDefaultGroupPolicy,
|
||||||
@ -166,7 +165,7 @@ export async function applyGoogleChatInboundAccessPolicy(params: {
|
|||||||
} = params;
|
} = params;
|
||||||
const allowNameMatching = isDangerousNameMatchingEnabled(account.config);
|
const allowNameMatching = isDangerousNameMatchingEnabled(account.config);
|
||||||
const spaceId = space.name ?? "";
|
const spaceId = space.name ?? "";
|
||||||
const pairing = createScopedPairingAccess({
|
const pairing = createChannelPairingController({
|
||||||
core,
|
core,
|
||||||
channel: "googlechat",
|
channel: "googlechat",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
@ -311,12 +310,10 @@ export async function applyGoogleChatInboundAccessPolicy(params: {
|
|||||||
|
|
||||||
if (access.decision !== "allow") {
|
if (access.decision !== "allow") {
|
||||||
if (access.decision === "pairing") {
|
if (access.decision === "pairing") {
|
||||||
await issuePairingChallenge({
|
await pairing.issueChallenge({
|
||||||
channel: "googlechat",
|
|
||||||
senderId,
|
senderId,
|
||||||
senderIdLine: `Your Google Chat user id: ${senderId}`,
|
senderIdLine: `Your Google Chat user id: ${senderId}`,
|
||||||
meta: { name: senderName || undefined, email: senderEmail },
|
meta: { name: senderName || undefined, email: senderEmail },
|
||||||
upsertPairingRequest: pairing.upsertPairingRequest,
|
|
||||||
onCreated: () => {
|
onCreated: () => {
|
||||||
logVerbose(`googlechat pairing request sender=${senderId}`);
|
logVerbose(`googlechat pairing request sender=${senderId}`);
|
||||||
},
|
},
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import {
|
|||||||
} from "openclaw/plugin-sdk/reply-payload";
|
} from "openclaw/plugin-sdk/reply-payload";
|
||||||
import type { OpenClawConfig } from "../runtime-api.js";
|
import type { OpenClawConfig } from "../runtime-api.js";
|
||||||
import {
|
import {
|
||||||
|
createChannelReplyPipeline,
|
||||||
createWebhookInFlightLimiter,
|
createWebhookInFlightLimiter,
|
||||||
createReplyPrefixOptions,
|
|
||||||
registerWebhookTargetWithPluginRoute,
|
registerWebhookTargetWithPluginRoute,
|
||||||
resolveInboundRouteEnvelopeBuilderWithRuntime,
|
resolveInboundRouteEnvelopeBuilderWithRuntime,
|
||||||
resolveWebhookPath,
|
resolveWebhookPath,
|
||||||
@ -307,7 +307,7 @@ async function processMessageWithPipeline(params: {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
|
||||||
cfg: config,
|
cfg: config,
|
||||||
agentId: route.agentId,
|
agentId: route.agentId,
|
||||||
channel: "googlechat",
|
channel: "googlechat",
|
||||||
@ -318,7 +318,7 @@ async function processMessageWithPipeline(params: {
|
|||||||
ctx: ctxPayload,
|
ctx: ctxPayload,
|
||||||
cfg: config,
|
cfg: config,
|
||||||
dispatcherOptions: {
|
dispatcherOptions: {
|
||||||
...prefixOptions,
|
...replyPipeline,
|
||||||
deliver: async (payload) => {
|
deliver: async (payload) => {
|
||||||
await deliverGoogleChatReply({
|
await deliverGoogleChatReply({
|
||||||
payload,
|
payload,
|
||||||
|
|||||||
@ -4,32 +4,27 @@ import {
|
|||||||
HUGGINGFACE_MODEL_CATALOG,
|
HUGGINGFACE_MODEL_CATALOG,
|
||||||
} from "openclaw/plugin-sdk/provider-models";
|
} from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
export const HUGGINGFACE_DEFAULT_MODEL_REF = "huggingface/deepseek-ai/DeepSeek-R1";
|
export const HUGGINGFACE_DEFAULT_MODEL_REF = "huggingface/deepseek-ai/DeepSeek-R1";
|
||||||
|
|
||||||
export function applyHuggingfaceProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function applyHuggingfacePreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
models[HUGGINGFACE_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[HUGGINGFACE_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[HUGGINGFACE_DEFAULT_MODEL_REF]?.alias ?? "Hugging Face",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "huggingface",
|
providerId: "huggingface",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
baseUrl: HUGGINGFACE_BASE_URL,
|
baseUrl: HUGGINGFACE_BASE_URL,
|
||||||
catalogModels: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition),
|
catalogModels: HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition),
|
||||||
|
aliases: [{ modelRef: HUGGINGFACE_DEFAULT_MODEL_REF, alias: "Hugging Face" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyHuggingfaceConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyHuggingfaceProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applyHuggingfacePreset(cfg);
|
||||||
applyHuggingfaceProviderConfig(cfg),
|
}
|
||||||
HUGGINGFACE_DEFAULT_MODEL_REF,
|
|
||||||
);
|
export function applyHuggingfaceConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applyHuggingfacePreset(cfg, HUGGINGFACE_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,10 +9,9 @@ import {
|
|||||||
} from "./policy.js";
|
} from "./policy.js";
|
||||||
import {
|
import {
|
||||||
GROUP_POLICY_BLOCKED_LABEL,
|
GROUP_POLICY_BLOCKED_LABEL,
|
||||||
createScopedPairingAccess,
|
createChannelPairingController,
|
||||||
deliverFormattedTextWithAttachments,
|
deliverFormattedTextWithAttachments,
|
||||||
dispatchInboundReplyWithBase,
|
dispatchInboundReplyWithBase,
|
||||||
issuePairingChallenge,
|
|
||||||
logInboundDrop,
|
logInboundDrop,
|
||||||
isDangerousNameMatchingEnabled,
|
isDangerousNameMatchingEnabled,
|
||||||
readStoreAllowFromForDmPolicy,
|
readStoreAllowFromForDmPolicy,
|
||||||
@ -90,7 +89,7 @@ export async function handleIrcInbound(params: {
|
|||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { message, account, config, runtime, connectedNick, statusSink } = params;
|
const { message, account, config, runtime, connectedNick, statusSink } = params;
|
||||||
const core = getIrcRuntime();
|
const core = getIrcRuntime();
|
||||||
const pairing = createScopedPairingAccess({
|
const pairing = createChannelPairingController({
|
||||||
core,
|
core,
|
||||||
channel: CHANNEL_ID,
|
channel: CHANNEL_ID,
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
@ -208,12 +207,10 @@ export async function handleIrcInbound(params: {
|
|||||||
}).allowed;
|
}).allowed;
|
||||||
if (!dmAllowed) {
|
if (!dmAllowed) {
|
||||||
if (dmPolicy === "pairing") {
|
if (dmPolicy === "pairing") {
|
||||||
await issuePairingChallenge({
|
await pairing.issueChallenge({
|
||||||
channel: CHANNEL_ID,
|
|
||||||
senderId: senderDisplay.toLowerCase(),
|
senderId: senderDisplay.toLowerCase(),
|
||||||
senderIdLine: `Your IRC id: ${senderDisplay}`,
|
senderIdLine: `Your IRC id: ${senderDisplay}`,
|
||||||
meta: { name: message.senderNick || undefined },
|
meta: { name: message.senderNick || undefined },
|
||||||
upsertPairingRequest: pairing.upsertPairingRequest,
|
|
||||||
sendPairingReply: async (text) => {
|
sendPairingReply: async (text) => {
|
||||||
await deliverIrcReply({
|
await deliverIrcReply({
|
||||||
payload: { text },
|
payload: { text },
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithDefaultModelPreset,
|
||||||
applyProviderConfigWithDefaultModel,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import {
|
import {
|
||||||
@ -12,28 +11,30 @@ import {
|
|||||||
export const KIMI_MODEL_REF = `kimi/${KIMI_CODING_DEFAULT_MODEL_ID}`;
|
export const KIMI_MODEL_REF = `kimi/${KIMI_CODING_DEFAULT_MODEL_ID}`;
|
||||||
export const KIMI_CODING_MODEL_REF = KIMI_MODEL_REF;
|
export const KIMI_CODING_MODEL_REF = KIMI_MODEL_REF;
|
||||||
|
|
||||||
export function applyKimiCodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function resolveKimiCodingDefaultModel() {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return buildKimiCodingProvider().models[0];
|
||||||
models[KIMI_MODEL_REF] = {
|
}
|
||||||
...models[KIMI_MODEL_REF],
|
|
||||||
alias: models[KIMI_MODEL_REF]?.alias ?? "Kimi",
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultModel = buildKimiCodingProvider().models[0];
|
function applyKimiCodingPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
|
const defaultModel = resolveKimiCodingDefaultModel();
|
||||||
if (!defaultModel) {
|
if (!defaultModel) {
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
return applyProviderConfigWithDefaultModelPreset(cfg, {
|
||||||
return applyProviderConfigWithDefaultModel(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "kimi",
|
providerId: "kimi",
|
||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
baseUrl: KIMI_CODING_BASE_URL,
|
baseUrl: KIMI_CODING_BASE_URL,
|
||||||
defaultModel,
|
defaultModel,
|
||||||
defaultModelId: KIMI_CODING_DEFAULT_MODEL_ID,
|
defaultModelId: KIMI_CODING_DEFAULT_MODEL_ID,
|
||||||
|
aliases: [{ modelRef: KIMI_MODEL_REF, alias: "Kimi" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyKimiCodeConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyKimiCodeProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(applyKimiCodeProviderConfig(cfg), KIMI_MODEL_REF);
|
return applyKimiCodingPreset(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyKimiCodeConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applyKimiCodingPreset(cfg, KIMI_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
import {
|
|
||||||
buildSecretInputSchema,
|
|
||||||
hasConfiguredSecretInput,
|
|
||||||
normalizeResolvedSecretInputString,
|
|
||||||
normalizeSecretInputString,
|
|
||||||
} from "../runtime-api.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
buildSecretInputSchema,
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
};
|
} from "openclaw/plugin-sdk/secret-input";
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
import {
|
|
||||||
buildSecretInputSchema,
|
|
||||||
hasConfiguredSecretInput,
|
|
||||||
normalizeResolvedSecretInputString,
|
|
||||||
normalizeSecretInputString,
|
|
||||||
} from "./runtime-api.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
buildSecretInputSchema,
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
};
|
} from "openclaw/plugin-sdk/secret-input";
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithDefaultModelPreset,
|
||||||
applyProviderConfigWithDefaultModel,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import {
|
import {
|
||||||
@ -11,23 +10,22 @@ import {
|
|||||||
|
|
||||||
export const MISTRAL_DEFAULT_MODEL_REF = `mistral/${MISTRAL_DEFAULT_MODEL_ID}`;
|
export const MISTRAL_DEFAULT_MODEL_REF = `mistral/${MISTRAL_DEFAULT_MODEL_ID}`;
|
||||||
|
|
||||||
export function applyMistralProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function applyMistralPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithDefaultModelPreset(cfg, {
|
||||||
models[MISTRAL_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[MISTRAL_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[MISTRAL_DEFAULT_MODEL_REF]?.alias ?? "Mistral",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithDefaultModel(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "mistral",
|
providerId: "mistral",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
baseUrl: MISTRAL_BASE_URL,
|
baseUrl: MISTRAL_BASE_URL,
|
||||||
defaultModel: buildMistralModelDefinition(),
|
defaultModel: buildMistralModelDefinition(),
|
||||||
defaultModelId: MISTRAL_DEFAULT_MODEL_ID,
|
defaultModelId: MISTRAL_DEFAULT_MODEL_ID,
|
||||||
|
aliases: [{ modelRef: MISTRAL_DEFAULT_MODEL_REF, alias: "Mistral" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyMistralConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyMistralProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(applyMistralProviderConfig(cfg), MISTRAL_DEFAULT_MODEL_REF);
|
return applyMistralPreset(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyMistralConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applyMistralPreset(cfg, MISTRAL_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import {
|
import {
|
||||||
@ -15,26 +14,19 @@ export { MODELSTUDIO_CN_BASE_URL, MODELSTUDIO_DEFAULT_MODEL_REF, MODELSTUDIO_GLO
|
|||||||
function applyModelStudioProviderConfigWithBaseUrl(
|
function applyModelStudioProviderConfigWithBaseUrl(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
|
primaryModelRef?: string,
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
|
||||||
const provider = buildModelStudioProvider();
|
const provider = buildModelStudioProvider();
|
||||||
for (const model of provider.models ?? []) {
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
const modelRef = `modelstudio/${model.id}`;
|
|
||||||
if (!models[modelRef]) {
|
|
||||||
models[modelRef] = {};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
models[MODELSTUDIO_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[MODELSTUDIO_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[MODELSTUDIO_DEFAULT_MODEL_REF]?.alias ?? "Qwen",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "modelstudio",
|
providerId: "modelstudio",
|
||||||
api: provider.api ?? "openai-completions",
|
api: provider.api ?? "openai-completions",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
catalogModels: provider.models ?? [],
|
catalogModels: provider.models ?? [],
|
||||||
|
aliases: [
|
||||||
|
...(provider.models ?? []).map((model) => `modelstudio/${model.id}`),
|
||||||
|
{ modelRef: MODELSTUDIO_DEFAULT_MODEL_REF, alias: "Qwen" },
|
||||||
|
],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,15 +39,17 @@ export function applyModelStudioProviderConfigCn(cfg: OpenClawConfig): OpenClawC
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyModelStudioConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyModelStudioConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applyModelStudioProviderConfigWithBaseUrl(
|
||||||
applyModelStudioProviderConfig(cfg),
|
cfg,
|
||||||
|
MODELSTUDIO_GLOBAL_BASE_URL,
|
||||||
MODELSTUDIO_DEFAULT_MODEL_REF,
|
MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyModelStudioConfigCn(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyModelStudioConfigCn(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applyModelStudioProviderConfigWithBaseUrl(
|
||||||
applyModelStudioProviderConfigCn(cfg),
|
cfg,
|
||||||
|
MODELSTUDIO_CN_BASE_URL,
|
||||||
MODELSTUDIO_DEFAULT_MODEL_REF,
|
MODELSTUDIO_DEFAULT_MODEL_REF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithDefaultModelPreset,
|
||||||
applyProviderConfigWithDefaultModel,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import {
|
import {
|
||||||
@ -23,38 +22,32 @@ export function applyMoonshotProviderConfigCn(cfg: OpenClawConfig): OpenClawConf
|
|||||||
function applyMoonshotProviderConfigWithBaseUrl(
|
function applyMoonshotProviderConfigWithBaseUrl(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
baseUrl: string,
|
baseUrl: string,
|
||||||
|
primaryModelRef?: string,
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
|
||||||
models[MOONSHOT_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[MOONSHOT_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[MOONSHOT_DEFAULT_MODEL_REF]?.alias ?? "Kimi",
|
|
||||||
};
|
|
||||||
|
|
||||||
const defaultModel = buildMoonshotProvider().models[0];
|
const defaultModel = buildMoonshotProvider().models[0];
|
||||||
if (!defaultModel) {
|
if (!defaultModel) {
|
||||||
return cfg;
|
return cfg;
|
||||||
}
|
}
|
||||||
|
|
||||||
return applyProviderConfigWithDefaultModel(cfg, {
|
return applyProviderConfigWithDefaultModelPreset(cfg, {
|
||||||
agentModels: models,
|
|
||||||
providerId: "moonshot",
|
providerId: "moonshot",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
baseUrl,
|
baseUrl,
|
||||||
defaultModel,
|
defaultModel,
|
||||||
defaultModelId: MOONSHOT_DEFAULT_MODEL_ID,
|
defaultModelId: MOONSHOT_DEFAULT_MODEL_ID,
|
||||||
|
aliases: [{ modelRef: MOONSHOT_DEFAULT_MODEL_REF, alias: "Kimi" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyMoonshotConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyMoonshotConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applyMoonshotProviderConfigWithBaseUrl(cfg, MOONSHOT_BASE_URL, MOONSHOT_DEFAULT_MODEL_REF);
|
||||||
applyMoonshotProviderConfig(cfg),
|
|
||||||
MOONSHOT_DEFAULT_MODEL_REF,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyMoonshotConfigCn(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyMoonshotConfigCn(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applyMoonshotProviderConfigWithBaseUrl(
|
||||||
applyMoonshotProviderConfigCn(cfg),
|
cfg,
|
||||||
|
MOONSHOT_CN_BASE_URL,
|
||||||
MOONSHOT_DEFAULT_MODEL_REF,
|
MOONSHOT_DEFAULT_MODEL_REF,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
GROUP_POLICY_BLOCKED_LABEL,
|
GROUP_POLICY_BLOCKED_LABEL,
|
||||||
createScopedPairingAccess,
|
createChannelPairingController,
|
||||||
deliverFormattedTextWithAttachments,
|
deliverFormattedTextWithAttachments,
|
||||||
dispatchInboundReplyWithBase,
|
dispatchInboundReplyWithBase,
|
||||||
issuePairingChallenge,
|
|
||||||
logInboundDrop,
|
logInboundDrop,
|
||||||
readStoreAllowFromForDmPolicy,
|
readStoreAllowFromForDmPolicy,
|
||||||
resolveDmGroupAccessWithCommandGate,
|
resolveDmGroupAccessWithCommandGate,
|
||||||
@ -58,7 +57,7 @@ export async function handleNextcloudTalkInbound(params: {
|
|||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
const { message, account, config, runtime, statusSink } = params;
|
const { message, account, config, runtime, statusSink } = params;
|
||||||
const core = getNextcloudTalkRuntime();
|
const core = getNextcloudTalkRuntime();
|
||||||
const pairing = createScopedPairingAccess({
|
const pairing = createChannelPairingController({
|
||||||
core,
|
core,
|
||||||
channel: CHANNEL_ID,
|
channel: CHANNEL_ID,
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
@ -172,12 +171,10 @@ export async function handleNextcloudTalkInbound(params: {
|
|||||||
} else {
|
} else {
|
||||||
if (access.decision !== "allow") {
|
if (access.decision !== "allow") {
|
||||||
if (access.decision === "pairing") {
|
if (access.decision === "pairing") {
|
||||||
await issuePairingChallenge({
|
await pairing.issueChallenge({
|
||||||
channel: CHANNEL_ID,
|
|
||||||
senderId,
|
senderId,
|
||||||
senderIdLine: `Your Nextcloud user id: ${senderId}`,
|
senderIdLine: `Your Nextcloud user id: ${senderId}`,
|
||||||
meta: { name: senderName || undefined },
|
meta: { name: senderName || undefined },
|
||||||
upsertPairingRequest: pairing.upsertPairingRequest,
|
|
||||||
sendPairingReply: async (text) => {
|
sendPairingReply: async (text) => {
|
||||||
await sendMessageNextcloudTalk(roomToken, text, { accountId: account.accountId });
|
await sendMessageNextcloudTalk(roomToken, text, { accountId: account.accountId });
|
||||||
statusSink?.({ lastOutboundAt: Date.now() });
|
statusSink?.({ lastOutboundAt: Date.now() });
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
import {
|
|
||||||
buildSecretInputSchema,
|
|
||||||
hasConfiguredSecretInput,
|
|
||||||
normalizeResolvedSecretInputString,
|
|
||||||
normalizeSecretInputString,
|
|
||||||
} from "../runtime-api.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
buildSecretInputSchema,
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
};
|
} from "openclaw/plugin-sdk/secret-input";
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import { OPENCODE_GO_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models";
|
import { OPENCODE_GO_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyAgentDefaultModelPrimary,
|
||||||
|
withAgentModelAliases,
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
@ -13,21 +14,19 @@ const OPENCODE_GO_ALIAS_DEFAULTS: Record<string, string> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function applyOpencodeGoProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyOpencodeGoProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
|
||||||
for (const [modelRef, alias] of Object.entries(OPENCODE_GO_ALIAS_DEFAULTS)) {
|
|
||||||
models[modelRef] = {
|
|
||||||
...models[modelRef],
|
|
||||||
alias: models[modelRef]?.alias ?? alias,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...cfg,
|
...cfg,
|
||||||
agents: {
|
agents: {
|
||||||
...cfg.agents,
|
...cfg.agents,
|
||||||
defaults: {
|
defaults: {
|
||||||
...cfg.agents?.defaults,
|
...cfg.agents?.defaults,
|
||||||
models,
|
models: withAgentModelAliases(
|
||||||
|
cfg.agents?.defaults?.models,
|
||||||
|
Object.entries(OPENCODE_GO_ALIAS_DEFAULTS).map(([modelRef, alias]) => ({
|
||||||
|
modelRef,
|
||||||
|
alias,
|
||||||
|
})),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,25 +1,22 @@
|
|||||||
import { OPENCODE_ZEN_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models";
|
import { OPENCODE_ZEN_DEFAULT_MODEL_REF } from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyAgentDefaultModelPrimary,
|
||||||
|
withAgentModelAliases,
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
export { OPENCODE_ZEN_DEFAULT_MODEL_REF };
|
export { OPENCODE_ZEN_DEFAULT_MODEL_REF };
|
||||||
|
|
||||||
export function applyOpencodeZenProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyOpencodeZenProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
|
||||||
models[OPENCODE_ZEN_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[OPENCODE_ZEN_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[OPENCODE_ZEN_DEFAULT_MODEL_REF]?.alias ?? "Opus",
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...cfg,
|
...cfg,
|
||||||
agents: {
|
agents: {
|
||||||
...cfg.agents,
|
...cfg.agents,
|
||||||
defaults: {
|
defaults: {
|
||||||
...cfg.agents?.defaults,
|
...cfg.agents?.defaults,
|
||||||
models,
|
models: withAgentModelAliases(cfg.agents?.defaults?.models, [
|
||||||
|
{ modelRef: OPENCODE_ZEN_DEFAULT_MODEL_REF, alias: "Opus" },
|
||||||
|
]),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithDefaultModelsPreset,
|
||||||
applyProviderConfigWithDefaultModels,
|
|
||||||
type ModelApi,
|
type ModelApi,
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
@ -12,12 +11,11 @@ import {
|
|||||||
|
|
||||||
export const QIANFAN_DEFAULT_MODEL_REF = `qianfan/${QIANFAN_DEFAULT_MODEL_ID}`;
|
export const QIANFAN_DEFAULT_MODEL_REF = `qianfan/${QIANFAN_DEFAULT_MODEL_ID}`;
|
||||||
|
|
||||||
export function applyQianfanProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function resolveQianfanPreset(cfg: OpenClawConfig): {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
api: ModelApi;
|
||||||
models[QIANFAN_DEFAULT_MODEL_REF] = {
|
baseUrl: string;
|
||||||
...models[QIANFAN_DEFAULT_MODEL_REF],
|
defaultModels: NonNullable<ReturnType<typeof buildQianfanProvider>["models"]>;
|
||||||
alias: models[QIANFAN_DEFAULT_MODEL_REF]?.alias ?? "QIANFAN",
|
} {
|
||||||
};
|
|
||||||
const defaultProvider = buildQianfanProvider();
|
const defaultProvider = buildQianfanProvider();
|
||||||
const existingProvider = cfg.models?.providers?.qianfan as
|
const existingProvider = cfg.models?.providers?.qianfan as
|
||||||
| {
|
| {
|
||||||
@ -27,22 +25,35 @@ export function applyQianfanProviderConfig(cfg: OpenClawConfig): OpenClawConfig
|
|||||||
| undefined;
|
| undefined;
|
||||||
const existingBaseUrl =
|
const existingBaseUrl =
|
||||||
typeof existingProvider?.baseUrl === "string" ? existingProvider.baseUrl.trim() : "";
|
typeof existingProvider?.baseUrl === "string" ? existingProvider.baseUrl.trim() : "";
|
||||||
const resolvedBaseUrl = existingBaseUrl || QIANFAN_BASE_URL;
|
const api =
|
||||||
const resolvedApi =
|
|
||||||
typeof existingProvider?.api === "string"
|
typeof existingProvider?.api === "string"
|
||||||
? (existingProvider.api as ModelApi)
|
? (existingProvider.api as ModelApi)
|
||||||
: "openai-completions";
|
: "openai-completions";
|
||||||
|
|
||||||
return applyProviderConfigWithDefaultModels(cfg, {
|
return {
|
||||||
agentModels: models,
|
api,
|
||||||
providerId: "qianfan",
|
baseUrl: existingBaseUrl || QIANFAN_BASE_URL,
|
||||||
api: resolvedApi,
|
|
||||||
baseUrl: resolvedBaseUrl,
|
|
||||||
defaultModels: defaultProvider.models ?? [],
|
defaultModels: defaultProvider.models ?? [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyQianfanPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
|
const preset = resolveQianfanPreset(cfg);
|
||||||
|
return applyProviderConfigWithDefaultModelsPreset(cfg, {
|
||||||
|
providerId: "qianfan",
|
||||||
|
api: preset.api,
|
||||||
|
baseUrl: preset.baseUrl,
|
||||||
|
defaultModels: preset.defaultModels,
|
||||||
defaultModelId: QIANFAN_DEFAULT_MODEL_ID,
|
defaultModelId: QIANFAN_DEFAULT_MODEL_ID,
|
||||||
|
aliases: [{ modelRef: QIANFAN_DEFAULT_MODEL_REF, alias: "QIANFAN" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyQianfanConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyQianfanProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(applyQianfanProviderConfig(cfg), QIANFAN_DEFAULT_MODEL_REF);
|
return applyQianfanPreset(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyQianfanConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applyQianfanPreset(cfg, QIANFAN_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
import { resolveHumanDelayConfig } from "openclaw/plugin-sdk/agent-runtime";
|
||||||
|
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
||||||
import { removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-runtime";
|
import { removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { logAckFailure, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime";
|
import { logAckFailure, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime";
|
|
||||||
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
||||||
import { resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/config-runtime";
|
import { resolveStorePath, updateLastRoute } from "openclaw/plugin-sdk/config-runtime";
|
||||||
import { resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/infra-runtime";
|
import { resolveAgentOutboundIdentity } from "openclaw/plugin-sdk/infra-runtime";
|
||||||
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
import { resolveSendableOutboundReplyParts } from "openclaw/plugin-sdk/reply-payload";
|
||||||
@ -147,63 +146,62 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
|||||||
|
|
||||||
const typingTarget = statusThreadTs ? `${message.channel}/${statusThreadTs}` : message.channel;
|
const typingTarget = statusThreadTs ? `${message.channel}/${statusThreadTs}` : message.channel;
|
||||||
const typingReaction = ctx.typingReaction;
|
const typingReaction = ctx.typingReaction;
|
||||||
const typingCallbacks = createTypingCallbacks({
|
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
|
||||||
start: async () => {
|
|
||||||
didSetStatus = true;
|
|
||||||
await ctx.setSlackThreadStatus({
|
|
||||||
channelId: message.channel,
|
|
||||||
threadTs: statusThreadTs,
|
|
||||||
status: "is typing...",
|
|
||||||
});
|
|
||||||
if (typingReaction && message.ts) {
|
|
||||||
await reactSlackMessage(message.channel, message.ts, typingReaction, {
|
|
||||||
token: ctx.botToken,
|
|
||||||
client: ctx.app.client,
|
|
||||||
}).catch(() => {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
stop: async () => {
|
|
||||||
if (!didSetStatus) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
didSetStatus = false;
|
|
||||||
await ctx.setSlackThreadStatus({
|
|
||||||
channelId: message.channel,
|
|
||||||
threadTs: statusThreadTs,
|
|
||||||
status: "",
|
|
||||||
});
|
|
||||||
if (typingReaction && message.ts) {
|
|
||||||
await removeSlackReaction(message.channel, message.ts, typingReaction, {
|
|
||||||
token: ctx.botToken,
|
|
||||||
client: ctx.app.client,
|
|
||||||
}).catch(() => {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
onStartError: (err) => {
|
|
||||||
logTypingFailure({
|
|
||||||
log: (message) => runtime.error?.(danger(message)),
|
|
||||||
channel: "slack",
|
|
||||||
action: "start",
|
|
||||||
target: typingTarget,
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
onStopError: (err) => {
|
|
||||||
logTypingFailure({
|
|
||||||
log: (message) => runtime.error?.(danger(message)),
|
|
||||||
channel: "slack",
|
|
||||||
action: "stop",
|
|
||||||
target: typingTarget,
|
|
||||||
error: err,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
|
||||||
cfg,
|
cfg,
|
||||||
agentId: route.agentId,
|
agentId: route.agentId,
|
||||||
channel: "slack",
|
channel: "slack",
|
||||||
accountId: route.accountId,
|
accountId: route.accountId,
|
||||||
|
typing: {
|
||||||
|
start: async () => {
|
||||||
|
didSetStatus = true;
|
||||||
|
await ctx.setSlackThreadStatus({
|
||||||
|
channelId: message.channel,
|
||||||
|
threadTs: statusThreadTs,
|
||||||
|
status: "is typing...",
|
||||||
|
});
|
||||||
|
if (typingReaction && message.ts) {
|
||||||
|
await reactSlackMessage(message.channel, message.ts, typingReaction, {
|
||||||
|
token: ctx.botToken,
|
||||||
|
client: ctx.app.client,
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
stop: async () => {
|
||||||
|
if (!didSetStatus) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
didSetStatus = false;
|
||||||
|
await ctx.setSlackThreadStatus({
|
||||||
|
channelId: message.channel,
|
||||||
|
threadTs: statusThreadTs,
|
||||||
|
status: "",
|
||||||
|
});
|
||||||
|
if (typingReaction && message.ts) {
|
||||||
|
await removeSlackReaction(message.channel, message.ts, typingReaction, {
|
||||||
|
token: ctx.botToken,
|
||||||
|
client: ctx.app.client,
|
||||||
|
}).catch(() => {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onStartError: (err) => {
|
||||||
|
logTypingFailure({
|
||||||
|
log: (message) => runtime.error?.(danger(message)),
|
||||||
|
channel: "slack",
|
||||||
|
action: "start",
|
||||||
|
target: typingTarget,
|
||||||
|
error: err,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
onStopError: (err) => {
|
||||||
|
logTypingFailure({
|
||||||
|
log: (message) => runtime.error?.(danger(message)),
|
||||||
|
channel: "slack",
|
||||||
|
action: "stop",
|
||||||
|
target: typingTarget,
|
||||||
|
error: err,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const slackStreaming = resolveSlackStreamingConfig({
|
const slackStreaming = resolveSlackStreamingConfig({
|
||||||
@ -299,9 +297,8 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
|||||||
};
|
};
|
||||||
|
|
||||||
const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
|
const { dispatcher, replyOptions, markDispatchIdle } = createReplyDispatcherWithTyping({
|
||||||
...prefixOptions,
|
...replyPipeline,
|
||||||
humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
|
humanDelay: resolveHumanDelayConfig(cfg, route.agentId),
|
||||||
typingCallbacks,
|
|
||||||
deliver: async (payload) => {
|
deliver: async (payload) => {
|
||||||
if (useStreaming) {
|
if (useStreaming) {
|
||||||
await deliverWithStreaming(payload);
|
await deliverWithStreaming(payload);
|
||||||
@ -367,7 +364,7 @@ export async function dispatchPreparedSlackMessage(prepared: PreparedSlackMessag
|
|||||||
},
|
},
|
||||||
onError: (err, info) => {
|
onError: (err, info) => {
|
||||||
runtime.error?.(danger(`slack ${info.kind} reply failed: ${String(err)}`));
|
runtime.error?.(danger(`slack ${info.kind} reply failed: ${String(err)}`));
|
||||||
typingCallbacks.onIdle?.();
|
replyPipeline.typingCallbacks?.onIdle?.();
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -5,32 +5,27 @@ import {
|
|||||||
SYNTHETIC_MODEL_CATALOG,
|
SYNTHETIC_MODEL_CATALOG,
|
||||||
} from "openclaw/plugin-sdk/provider-models";
|
} from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
export { SYNTHETIC_DEFAULT_MODEL_REF };
|
export { SYNTHETIC_DEFAULT_MODEL_REF };
|
||||||
|
|
||||||
export function applySyntheticProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function applySyntheticPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
models[SYNTHETIC_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[SYNTHETIC_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[SYNTHETIC_DEFAULT_MODEL_REF]?.alias ?? "MiniMax M2.5",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "synthetic",
|
providerId: "synthetic",
|
||||||
api: "anthropic-messages",
|
api: "anthropic-messages",
|
||||||
baseUrl: SYNTHETIC_BASE_URL,
|
baseUrl: SYNTHETIC_BASE_URL,
|
||||||
catalogModels: SYNTHETIC_MODEL_CATALOG.map(buildSyntheticModelDefinition),
|
catalogModels: SYNTHETIC_MODEL_CATALOG.map(buildSyntheticModelDefinition),
|
||||||
|
aliases: [{ modelRef: SYNTHETIC_DEFAULT_MODEL_REF, alias: "MiniMax M2.5" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applySyntheticConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applySyntheticProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applySyntheticPreset(cfg);
|
||||||
applySyntheticProviderConfig(cfg),
|
}
|
||||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
|
||||||
);
|
export function applySyntheticConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applySyntheticPreset(cfg, SYNTHETIC_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,10 +6,9 @@ import {
|
|||||||
modelSupportsVision,
|
modelSupportsVision,
|
||||||
} from "openclaw/plugin-sdk/agent-runtime";
|
} from "openclaw/plugin-sdk/agent-runtime";
|
||||||
import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
|
import { resolveDefaultModelForAgent } from "openclaw/plugin-sdk/agent-runtime";
|
||||||
|
import { createChannelReplyPipeline } from "openclaw/plugin-sdk/channel-reply-pipeline";
|
||||||
import { removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-runtime";
|
import { removeAckReactionAfterReply } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { logAckFailure, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime";
|
import { logAckFailure, logTypingFailure } from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import { createReplyPrefixOptions } from "openclaw/plugin-sdk/channel-runtime";
|
|
||||||
import { createTypingCallbacks } from "openclaw/plugin-sdk/channel-runtime";
|
|
||||||
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
|
import { resolveMarkdownTableMode } from "openclaw/plugin-sdk/config-runtime";
|
||||||
import {
|
import {
|
||||||
loadSessionStore,
|
loadSessionStore,
|
||||||
@ -381,12 +380,6 @@ export const dispatchTelegramMessage = async ({
|
|||||||
? true
|
? true
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
|
||||||
cfg,
|
|
||||||
agentId: route.agentId,
|
|
||||||
channel: "telegram",
|
|
||||||
accountId: route.accountId,
|
|
||||||
});
|
|
||||||
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
|
const chunkMode = resolveChunkMode(cfg, "telegram", route.accountId);
|
||||||
|
|
||||||
// Handle uncached stickers: get a dedicated vision description before dispatch
|
// Handle uncached stickers: get a dedicated vision description before dispatch
|
||||||
@ -524,15 +517,21 @@ export const dispatchTelegramMessage = async ({
|
|||||||
void statusReactionController.setThinking();
|
void statusReactionController.setThinking();
|
||||||
}
|
}
|
||||||
|
|
||||||
const typingCallbacks = createTypingCallbacks({
|
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
|
||||||
start: sendTyping,
|
cfg,
|
||||||
onStartError: (err) => {
|
agentId: route.agentId,
|
||||||
logTypingFailure({
|
channel: "telegram",
|
||||||
log: logVerbose,
|
accountId: route.accountId,
|
||||||
channel: "telegram",
|
typing: {
|
||||||
target: String(chatId),
|
start: sendTyping,
|
||||||
error: err,
|
onStartError: (err) => {
|
||||||
});
|
logTypingFailure({
|
||||||
|
log: logVerbose,
|
||||||
|
channel: "telegram",
|
||||||
|
target: String(chatId),
|
||||||
|
error: err,
|
||||||
|
});
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -542,8 +541,7 @@ export const dispatchTelegramMessage = async ({
|
|||||||
ctx: ctxPayload,
|
ctx: ctxPayload,
|
||||||
cfg,
|
cfg,
|
||||||
dispatcherOptions: {
|
dispatcherOptions: {
|
||||||
...prefixOptions,
|
...replyPipeline,
|
||||||
typingCallbacks,
|
|
||||||
deliver: async (payload, info) => {
|
deliver: async (payload, info) => {
|
||||||
if (payload.isError === true) {
|
if (payload.isError === true) {
|
||||||
hadErrorReplyFailureOrSkip = true;
|
hadErrorReplyFailureOrSkip = true;
|
||||||
|
|||||||
@ -4,32 +4,27 @@ import {
|
|||||||
TOGETHER_MODEL_CATALOG,
|
TOGETHER_MODEL_CATALOG,
|
||||||
} from "openclaw/plugin-sdk/provider-models";
|
} from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
export const TOGETHER_DEFAULT_MODEL_REF = "together/moonshotai/Kimi-K2.5";
|
export const TOGETHER_DEFAULT_MODEL_REF = "together/moonshotai/Kimi-K2.5";
|
||||||
|
|
||||||
export function applyTogetherProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function applyTogetherPreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
models[TOGETHER_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[TOGETHER_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[TOGETHER_DEFAULT_MODEL_REF]?.alias ?? "Together AI",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "together",
|
providerId: "together",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
baseUrl: TOGETHER_BASE_URL,
|
baseUrl: TOGETHER_BASE_URL,
|
||||||
catalogModels: TOGETHER_MODEL_CATALOG.map(buildTogetherModelDefinition),
|
catalogModels: TOGETHER_MODEL_CATALOG.map(buildTogetherModelDefinition),
|
||||||
|
aliases: [{ modelRef: TOGETHER_DEFAULT_MODEL_REF, alias: "Together AI" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyTogetherConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyTogetherProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(
|
return applyTogetherPreset(cfg);
|
||||||
applyTogetherProviderConfig(cfg),
|
}
|
||||||
TOGETHER_DEFAULT_MODEL_REF,
|
|
||||||
);
|
export function applyTogetherConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applyTogetherPreset(cfg, TOGETHER_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,29 +5,27 @@ import {
|
|||||||
VENICE_MODEL_CATALOG,
|
VENICE_MODEL_CATALOG,
|
||||||
} from "openclaw/plugin-sdk/provider-models";
|
} from "openclaw/plugin-sdk/provider-models";
|
||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
|
|
||||||
export { VENICE_DEFAULT_MODEL_REF };
|
export { VENICE_DEFAULT_MODEL_REF };
|
||||||
|
|
||||||
export function applyVeniceProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
function applyVenicePreset(cfg: OpenClawConfig, primaryModelRef?: string): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
models[VENICE_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[VENICE_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[VENICE_DEFAULT_MODEL_REF]?.alias ?? "Kimi K2.5",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "venice",
|
providerId: "venice",
|
||||||
api: "openai-completions",
|
api: "openai-completions",
|
||||||
baseUrl: VENICE_BASE_URL,
|
baseUrl: VENICE_BASE_URL,
|
||||||
catalogModels: VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition),
|
catalogModels: VENICE_MODEL_CATALOG.map(buildVeniceModelDefinition),
|
||||||
|
aliases: [{ modelRef: VENICE_DEFAULT_MODEL_REF, alias: "Kimi K2.5" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyVeniceConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyVeniceProviderConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(applyVeniceProviderConfig(cfg), VENICE_DEFAULT_MODEL_REF);
|
return applyVenicePreset(cfg);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyVeniceConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
|
return applyVenicePreset(cfg, VENICE_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithDefaultModelsPreset,
|
||||||
applyProviderConfigWithDefaultModels,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import { XAI_BASE_URL, XAI_DEFAULT_MODEL_ID } from "./model-definitions.js";
|
import { XAI_BASE_URL, XAI_DEFAULT_MODEL_ID } from "./model-definitions.js";
|
||||||
@ -11,20 +10,16 @@ export const XAI_DEFAULT_MODEL_REF = `xai/${XAI_DEFAULT_MODEL_ID}`;
|
|||||||
function applyXaiProviderConfigWithApi(
|
function applyXaiProviderConfigWithApi(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
api: "openai-completions" | "openai-responses",
|
api: "openai-completions" | "openai-responses",
|
||||||
|
primaryModelRef?: string,
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
return applyProviderConfigWithDefaultModelsPreset(cfg, {
|
||||||
models[XAI_DEFAULT_MODEL_REF] = {
|
|
||||||
...models[XAI_DEFAULT_MODEL_REF],
|
|
||||||
alias: models[XAI_DEFAULT_MODEL_REF]?.alias ?? "Grok",
|
|
||||||
};
|
|
||||||
|
|
||||||
return applyProviderConfigWithDefaultModels(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "xai",
|
providerId: "xai",
|
||||||
api,
|
api,
|
||||||
baseUrl: XAI_BASE_URL,
|
baseUrl: XAI_BASE_URL,
|
||||||
defaultModels: buildXaiCatalogModels(),
|
defaultModels: buildXaiCatalogModels(),
|
||||||
defaultModelId: XAI_DEFAULT_MODEL_ID,
|
defaultModelId: XAI_DEFAULT_MODEL_ID,
|
||||||
|
aliases: [{ modelRef: XAI_DEFAULT_MODEL_REF, alias: "Grok" }],
|
||||||
|
primaryModelRef,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,5 +32,5 @@ export function applyXaiResponsesApiConfig(cfg: OpenClawConfig): OpenClawConfig
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function applyXaiConfig(cfg: OpenClawConfig): OpenClawConfig {
|
export function applyXaiConfig(cfg: OpenClawConfig): OpenClawConfig {
|
||||||
return applyAgentDefaultModelPrimary(applyXaiProviderConfig(cfg), XAI_DEFAULT_MODEL_REF);
|
return applyXaiProviderConfigWithApi(cfg, "openai-completions", XAI_DEFAULT_MODEL_REF);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
applyAgentDefaultModelPrimary,
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
|
||||||
type OpenClawConfig,
|
type OpenClawConfig,
|
||||||
} from "openclaw/plugin-sdk/provider-onboard";
|
} from "openclaw/plugin-sdk/provider-onboard";
|
||||||
import {
|
import {
|
||||||
@ -19,32 +18,35 @@ const ZAI_DEFAULT_MODELS = [
|
|||||||
buildZaiModelDefinition({ id: "glm-4.7-flashx" }),
|
buildZaiModelDefinition({ id: "glm-4.7-flashx" }),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
function resolveZaiPresetBaseUrl(cfg: OpenClawConfig, endpoint?: string): string {
|
||||||
|
const existingProvider = cfg.models?.providers?.zai;
|
||||||
|
const existingBaseUrl =
|
||||||
|
typeof existingProvider?.baseUrl === "string" ? existingProvider.baseUrl.trim() : "";
|
||||||
|
return endpoint ? resolveZaiBaseUrl(endpoint) : existingBaseUrl || resolveZaiBaseUrl();
|
||||||
|
}
|
||||||
|
|
||||||
|
function applyZaiPreset(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
params?: { endpoint?: string; modelId?: string },
|
||||||
|
primaryModelRef?: string,
|
||||||
|
): OpenClawConfig {
|
||||||
|
const modelId = params?.modelId?.trim() || ZAI_DEFAULT_MODEL_ID;
|
||||||
|
const modelRef = `zai/${modelId}`;
|
||||||
|
return applyProviderConfigWithModelCatalogPreset(cfg, {
|
||||||
|
providerId: "zai",
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: resolveZaiPresetBaseUrl(cfg, params?.endpoint),
|
||||||
|
catalogModels: ZAI_DEFAULT_MODELS,
|
||||||
|
aliases: [{ modelRef, alias: "GLM" }],
|
||||||
|
primaryModelRef,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export function applyZaiProviderConfig(
|
export function applyZaiProviderConfig(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
params?: { endpoint?: string; modelId?: string },
|
params?: { endpoint?: string; modelId?: string },
|
||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const modelId = params?.modelId?.trim() || ZAI_DEFAULT_MODEL_ID;
|
return applyZaiPreset(cfg, params);
|
||||||
const modelRef = `zai/${modelId}`;
|
|
||||||
const existingProvider = cfg.models?.providers?.zai;
|
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
|
||||||
models[modelRef] = {
|
|
||||||
...models[modelRef],
|
|
||||||
alias: models[modelRef]?.alias ?? "GLM",
|
|
||||||
};
|
|
||||||
|
|
||||||
const existingBaseUrl =
|
|
||||||
typeof existingProvider?.baseUrl === "string" ? existingProvider.baseUrl.trim() : "";
|
|
||||||
const baseUrl = params?.endpoint
|
|
||||||
? resolveZaiBaseUrl(params.endpoint)
|
|
||||||
: existingBaseUrl || resolveZaiBaseUrl();
|
|
||||||
|
|
||||||
return applyProviderConfigWithModelCatalog(cfg, {
|
|
||||||
agentModels: models,
|
|
||||||
providerId: "zai",
|
|
||||||
api: "openai-completions",
|
|
||||||
baseUrl,
|
|
||||||
catalogModels: ZAI_DEFAULT_MODELS,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyZaiConfig(
|
export function applyZaiConfig(
|
||||||
@ -53,5 +55,5 @@ export function applyZaiConfig(
|
|||||||
): OpenClawConfig {
|
): OpenClawConfig {
|
||||||
const modelId = params?.modelId?.trim() || ZAI_DEFAULT_MODEL_ID;
|
const modelId = params?.modelId?.trim() || ZAI_DEFAULT_MODEL_ID;
|
||||||
const modelRef = modelId === ZAI_DEFAULT_MODEL_ID ? ZAI_DEFAULT_MODEL_REF : `zai/${modelId}`;
|
const modelRef = modelId === ZAI_DEFAULT_MODEL_ID ? ZAI_DEFAULT_MODEL_REF : `zai/${modelId}`;
|
||||||
return applyAgentDefaultModelPrimary(applyZaiProviderConfig(cfg, params), modelRef);
|
return applyZaiPreset(cfg, params, modelRef);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,11 +30,9 @@ import {
|
|||||||
import { resolveZaloProxyFetch } from "./proxy.js";
|
import { resolveZaloProxyFetch } from "./proxy.js";
|
||||||
import type { MarkdownTableMode, OpenClawConfig, OutboundReplyPayload } from "./runtime-api.js";
|
import type { MarkdownTableMode, OpenClawConfig, OutboundReplyPayload } from "./runtime-api.js";
|
||||||
import {
|
import {
|
||||||
createTypingCallbacks,
|
createChannelPairingController,
|
||||||
createScopedPairingAccess,
|
createChannelReplyPipeline,
|
||||||
createReplyPrefixOptions,
|
|
||||||
deliverTextOrMediaReply,
|
deliverTextOrMediaReply,
|
||||||
issuePairingChallenge,
|
|
||||||
resolveWebhookPath,
|
resolveWebhookPath,
|
||||||
logTypingFailure,
|
logTypingFailure,
|
||||||
resolveDefaultGroupPolicy,
|
resolveDefaultGroupPolicy,
|
||||||
@ -330,7 +328,7 @@ async function processMessageWithPipeline(params: ZaloMessagePipelineParams): Pr
|
|||||||
statusSink,
|
statusSink,
|
||||||
fetcher,
|
fetcher,
|
||||||
} = params;
|
} = params;
|
||||||
const pairing = createScopedPairingAccess({
|
const pairing = createChannelPairingController({
|
||||||
core,
|
core,
|
||||||
channel: "zalo",
|
channel: "zalo",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
@ -406,12 +404,10 @@ async function processMessageWithPipeline(params: ZaloMessagePipelineParams): Pr
|
|||||||
}
|
}
|
||||||
if (directDmOutcome === "unauthorized") {
|
if (directDmOutcome === "unauthorized") {
|
||||||
if (dmPolicy === "pairing") {
|
if (dmPolicy === "pairing") {
|
||||||
await issuePairingChallenge({
|
await pairing.issueChallenge({
|
||||||
channel: "zalo",
|
|
||||||
senderId,
|
senderId,
|
||||||
senderIdLine: `Your Zalo user id: ${senderId}`,
|
senderIdLine: `Your Zalo user id: ${senderId}`,
|
||||||
meta: { name: senderName ?? undefined },
|
meta: { name: senderName ?? undefined },
|
||||||
upsertPairingRequest: pairing.upsertPairingRequest,
|
|
||||||
onCreated: () => {
|
onCreated: () => {
|
||||||
logVerbose(core, runtime, `zalo pairing request sender=${senderId}`);
|
logVerbose(core, runtime, `zalo pairing request sender=${senderId}`);
|
||||||
},
|
},
|
||||||
@ -507,32 +503,32 @@ async function processMessageWithPipeline(params: ZaloMessagePipelineParams): Pr
|
|||||||
channel: "zalo",
|
channel: "zalo",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
});
|
});
|
||||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
|
||||||
cfg: config,
|
cfg: config,
|
||||||
agentId: route.agentId,
|
agentId: route.agentId,
|
||||||
channel: "zalo",
|
channel: "zalo",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
});
|
typing: {
|
||||||
const typingCallbacks = createTypingCallbacks({
|
start: async () => {
|
||||||
start: async () => {
|
await sendChatAction(
|
||||||
await sendChatAction(
|
token,
|
||||||
token,
|
{
|
||||||
{
|
chat_id: chatId,
|
||||||
chat_id: chatId,
|
action: "typing",
|
||||||
action: "typing",
|
},
|
||||||
},
|
fetcher,
|
||||||
fetcher,
|
ZALO_TYPING_TIMEOUT_MS,
|
||||||
ZALO_TYPING_TIMEOUT_MS,
|
);
|
||||||
);
|
},
|
||||||
},
|
onStartError: (err) => {
|
||||||
onStartError: (err) => {
|
logTypingFailure({
|
||||||
logTypingFailure({
|
log: (message) => logVerbose(core, runtime, message),
|
||||||
log: (message) => logVerbose(core, runtime, message),
|
channel: "zalo",
|
||||||
channel: "zalo",
|
action: "start",
|
||||||
action: "start",
|
target: chatId,
|
||||||
target: chatId,
|
error: err,
|
||||||
error: err,
|
});
|
||||||
});
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -540,8 +536,7 @@ async function processMessageWithPipeline(params: ZaloMessagePipelineParams): Pr
|
|||||||
ctx: ctxPayload,
|
ctx: ctxPayload,
|
||||||
cfg: config,
|
cfg: config,
|
||||||
dispatcherOptions: {
|
dispatcherOptions: {
|
||||||
...prefixOptions,
|
...replyPipeline,
|
||||||
typingCallbacks,
|
|
||||||
deliver: async (payload) => {
|
deliver: async (payload) => {
|
||||||
await deliverZaloReply({
|
await deliverZaloReply({
|
||||||
payload,
|
payload,
|
||||||
|
|||||||
@ -1,13 +1,6 @@
|
|||||||
import {
|
|
||||||
buildSecretInputSchema,
|
|
||||||
hasConfiguredSecretInput,
|
|
||||||
normalizeResolvedSecretInputString,
|
|
||||||
normalizeSecretInputString,
|
|
||||||
} from "./runtime-api.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
buildSecretInputSchema,
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
};
|
} from "openclaw/plugin-sdk/secret-input";
|
||||||
|
|||||||
@ -18,13 +18,11 @@ import type {
|
|||||||
RuntimeEnv,
|
RuntimeEnv,
|
||||||
} from "../runtime-api.js";
|
} from "../runtime-api.js";
|
||||||
import {
|
import {
|
||||||
createTypingCallbacks,
|
createChannelPairingController,
|
||||||
createScopedPairingAccess,
|
createChannelReplyPipeline,
|
||||||
createReplyPrefixOptions,
|
|
||||||
deliverTextOrMediaReply,
|
deliverTextOrMediaReply,
|
||||||
evaluateGroupRouteAccessForPolicy,
|
evaluateGroupRouteAccessForPolicy,
|
||||||
isDangerousNameMatchingEnabled,
|
isDangerousNameMatchingEnabled,
|
||||||
issuePairingChallenge,
|
|
||||||
mergeAllowlist,
|
mergeAllowlist,
|
||||||
resolveMentionGatingWithBypass,
|
resolveMentionGatingWithBypass,
|
||||||
resolveOpenProviderRuntimeGroupPolicy,
|
resolveOpenProviderRuntimeGroupPolicy,
|
||||||
@ -252,7 +250,7 @@ async function processMessage(
|
|||||||
historyState: ZalouserGroupHistoryState,
|
historyState: ZalouserGroupHistoryState,
|
||||||
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void,
|
statusSink?: (patch: { lastInboundAt?: number; lastOutboundAt?: number }) => void,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const pairing = createScopedPairingAccess({
|
const pairing = createChannelPairingController({
|
||||||
core,
|
core,
|
||||||
channel: "zalouser",
|
channel: "zalouser",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
@ -389,12 +387,10 @@ async function processMessage(
|
|||||||
|
|
||||||
if (!isGroup && accessDecision.decision !== "allow") {
|
if (!isGroup && accessDecision.decision !== "allow") {
|
||||||
if (accessDecision.decision === "pairing") {
|
if (accessDecision.decision === "pairing") {
|
||||||
await issuePairingChallenge({
|
await pairing.issueChallenge({
|
||||||
channel: "zalouser",
|
|
||||||
senderId,
|
senderId,
|
||||||
senderIdLine: `Your Zalo user id: ${senderId}`,
|
senderIdLine: `Your Zalo user id: ${senderId}`,
|
||||||
meta: { name: senderName || undefined },
|
meta: { name: senderName || undefined },
|
||||||
upsertPairingRequest: pairing.upsertPairingRequest,
|
|
||||||
onCreated: () => {
|
onCreated: () => {
|
||||||
logVerbose(core, runtime, `zalouser pairing request sender=${senderId}`);
|
logVerbose(core, runtime, `zalouser pairing request sender=${senderId}`);
|
||||||
},
|
},
|
||||||
@ -630,24 +626,24 @@ async function processMessage(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const { onModelSelected, ...prefixOptions } = createReplyPrefixOptions({
|
const { onModelSelected, ...replyPipeline } = createChannelReplyPipeline({
|
||||||
cfg: config,
|
cfg: config,
|
||||||
agentId: route.agentId,
|
agentId: route.agentId,
|
||||||
channel: "zalouser",
|
channel: "zalouser",
|
||||||
accountId: account.accountId,
|
accountId: account.accountId,
|
||||||
});
|
typing: {
|
||||||
const typingCallbacks = createTypingCallbacks({
|
start: async () => {
|
||||||
start: async () => {
|
await sendTypingZalouser(chatId, {
|
||||||
await sendTypingZalouser(chatId, {
|
profile: account.profile,
|
||||||
profile: account.profile,
|
isGroup,
|
||||||
isGroup,
|
});
|
||||||
});
|
},
|
||||||
},
|
onStartError: (err) => {
|
||||||
onStartError: (err) => {
|
runtime.error?.(
|
||||||
runtime.error?.(
|
`[${account.accountId}] zalouser typing start failed for ${chatId}: ${String(err)}`,
|
||||||
`[${account.accountId}] zalouser typing start failed for ${chatId}: ${String(err)}`,
|
);
|
||||||
);
|
logVerbose(core, runtime, `zalouser typing failed for ${chatId}: ${String(err)}`);
|
||||||
logVerbose(core, runtime, `zalouser typing failed for ${chatId}: ${String(err)}`);
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -655,8 +651,7 @@ async function processMessage(
|
|||||||
ctx: ctxPayload,
|
ctx: ctxPayload,
|
||||||
cfg: config,
|
cfg: config,
|
||||||
dispatcherOptions: {
|
dispatcherOptions: {
|
||||||
...prefixOptions,
|
...replyPipeline,
|
||||||
typingCallbacks,
|
|
||||||
deliver: async (payload) => {
|
deliver: async (payload) => {
|
||||||
await deliverZalouserReply({
|
await deliverZalouserReply({
|
||||||
payload: payload as { text?: string; mediaUrls?: string[]; mediaUrl?: string },
|
payload: payload as { text?: string; mediaUrls?: string[]; mediaUrl?: string },
|
||||||
|
|||||||
20
package.json
20
package.json
@ -78,6 +78,10 @@
|
|||||||
"types": "./dist/plugin-sdk/setup.d.ts",
|
"types": "./dist/plugin-sdk/setup.d.ts",
|
||||||
"default": "./dist/plugin-sdk/setup.js"
|
"default": "./dist/plugin-sdk/setup.js"
|
||||||
},
|
},
|
||||||
|
"./plugin-sdk/channel-setup": {
|
||||||
|
"types": "./dist/plugin-sdk/channel-setup.d.ts",
|
||||||
|
"default": "./dist/plugin-sdk/channel-setup.js"
|
||||||
|
},
|
||||||
"./plugin-sdk/setup-tools": {
|
"./plugin-sdk/setup-tools": {
|
||||||
"types": "./dist/plugin-sdk/setup-tools.d.ts",
|
"types": "./dist/plugin-sdk/setup-tools.d.ts",
|
||||||
"default": "./dist/plugin-sdk/setup-tools.js"
|
"default": "./dist/plugin-sdk/setup-tools.js"
|
||||||
@ -94,6 +98,10 @@
|
|||||||
"types": "./dist/plugin-sdk/reply-payload.d.ts",
|
"types": "./dist/plugin-sdk/reply-payload.d.ts",
|
||||||
"default": "./dist/plugin-sdk/reply-payload.js"
|
"default": "./dist/plugin-sdk/reply-payload.js"
|
||||||
},
|
},
|
||||||
|
"./plugin-sdk/channel-reply-pipeline": {
|
||||||
|
"types": "./dist/plugin-sdk/channel-reply-pipeline.d.ts",
|
||||||
|
"default": "./dist/plugin-sdk/channel-reply-pipeline.js"
|
||||||
|
},
|
||||||
"./plugin-sdk/channel-runtime": {
|
"./plugin-sdk/channel-runtime": {
|
||||||
"types": "./dist/plugin-sdk/channel-runtime.d.ts",
|
"types": "./dist/plugin-sdk/channel-runtime.d.ts",
|
||||||
"default": "./dist/plugin-sdk/channel-runtime.js"
|
"default": "./dist/plugin-sdk/channel-runtime.js"
|
||||||
@ -254,6 +262,10 @@
|
|||||||
"types": "./dist/plugin-sdk/channel-lifecycle.d.ts",
|
"types": "./dist/plugin-sdk/channel-lifecycle.d.ts",
|
||||||
"default": "./dist/plugin-sdk/channel-lifecycle.js"
|
"default": "./dist/plugin-sdk/channel-lifecycle.js"
|
||||||
},
|
},
|
||||||
|
"./plugin-sdk/channel-pairing": {
|
||||||
|
"types": "./dist/plugin-sdk/channel-pairing.d.ts",
|
||||||
|
"default": "./dist/plugin-sdk/channel-pairing.js"
|
||||||
|
},
|
||||||
"./plugin-sdk/channel-policy": {
|
"./plugin-sdk/channel-policy": {
|
||||||
"types": "./dist/plugin-sdk/channel-policy.d.ts",
|
"types": "./dist/plugin-sdk/channel-policy.d.ts",
|
||||||
"default": "./dist/plugin-sdk/channel-policy.js"
|
"default": "./dist/plugin-sdk/channel-policy.js"
|
||||||
@ -334,6 +346,10 @@
|
|||||||
"types": "./dist/plugin-sdk/request-url.d.ts",
|
"types": "./dist/plugin-sdk/request-url.d.ts",
|
||||||
"default": "./dist/plugin-sdk/request-url.js"
|
"default": "./dist/plugin-sdk/request-url.js"
|
||||||
},
|
},
|
||||||
|
"./plugin-sdk/webhook-ingress": {
|
||||||
|
"types": "./dist/plugin-sdk/webhook-ingress.d.ts",
|
||||||
|
"default": "./dist/plugin-sdk/webhook-ingress.js"
|
||||||
|
},
|
||||||
"./plugin-sdk/webhook-path": {
|
"./plugin-sdk/webhook-path": {
|
||||||
"types": "./dist/plugin-sdk/webhook-path.d.ts",
|
"types": "./dist/plugin-sdk/webhook-path.d.ts",
|
||||||
"default": "./dist/plugin-sdk/webhook-path.js"
|
"default": "./dist/plugin-sdk/webhook-path.js"
|
||||||
@ -342,6 +358,10 @@
|
|||||||
"types": "./dist/plugin-sdk/runtime-store.d.ts",
|
"types": "./dist/plugin-sdk/runtime-store.d.ts",
|
||||||
"default": "./dist/plugin-sdk/runtime-store.js"
|
"default": "./dist/plugin-sdk/runtime-store.js"
|
||||||
},
|
},
|
||||||
|
"./plugin-sdk/secret-input": {
|
||||||
|
"types": "./dist/plugin-sdk/secret-input.d.ts",
|
||||||
|
"default": "./dist/plugin-sdk/secret-input.js"
|
||||||
|
},
|
||||||
"./plugin-sdk/web-media": {
|
"./plugin-sdk/web-media": {
|
||||||
"types": "./dist/plugin-sdk/web-media.d.ts",
|
"types": "./dist/plugin-sdk/web-media.d.ts",
|
||||||
"default": "./dist/plugin-sdk/web-media.js"
|
"default": "./dist/plugin-sdk/web-media.js"
|
||||||
|
|||||||
@ -9,10 +9,12 @@
|
|||||||
"runtime",
|
"runtime",
|
||||||
"runtime-env",
|
"runtime-env",
|
||||||
"setup",
|
"setup",
|
||||||
|
"channel-setup",
|
||||||
"setup-tools",
|
"setup-tools",
|
||||||
"config-runtime",
|
"config-runtime",
|
||||||
"reply-runtime",
|
"reply-runtime",
|
||||||
"reply-payload",
|
"reply-payload",
|
||||||
|
"channel-reply-pipeline",
|
||||||
"channel-runtime",
|
"channel-runtime",
|
||||||
"interactive-runtime",
|
"interactive-runtime",
|
||||||
"infra-runtime",
|
"infra-runtime",
|
||||||
@ -53,6 +55,7 @@
|
|||||||
"channel-config-helpers",
|
"channel-config-helpers",
|
||||||
"channel-config-schema",
|
"channel-config-schema",
|
||||||
"channel-lifecycle",
|
"channel-lifecycle",
|
||||||
|
"channel-pairing",
|
||||||
"channel-policy",
|
"channel-policy",
|
||||||
"channel-send-result",
|
"channel-send-result",
|
||||||
"group-access",
|
"group-access",
|
||||||
@ -73,8 +76,10 @@
|
|||||||
"reply-history",
|
"reply-history",
|
||||||
"media-understanding",
|
"media-understanding",
|
||||||
"request-url",
|
"request-url",
|
||||||
|
"webhook-ingress",
|
||||||
"webhook-path",
|
"webhook-path",
|
||||||
"runtime-store",
|
"runtime-store",
|
||||||
|
"secret-input",
|
||||||
"web-media",
|
"web-media",
|
||||||
"speech",
|
"speech",
|
||||||
"state-paths",
|
"state-paths",
|
||||||
|
|||||||
@ -3,9 +3,12 @@ import type { OpenClawConfig } from "../config/config.js";
|
|||||||
import type { AgentModelEntryConfig } from "../config/types.agent-defaults.js";
|
import type { AgentModelEntryConfig } from "../config/types.agent-defaults.js";
|
||||||
import type { ModelDefinitionConfig } from "../config/types.models.js";
|
import type { ModelDefinitionConfig } from "../config/types.models.js";
|
||||||
import {
|
import {
|
||||||
|
applyProviderConfigWithDefaultModelPreset,
|
||||||
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithDefaultModel,
|
applyProviderConfigWithDefaultModel,
|
||||||
applyProviderConfigWithDefaultModels,
|
applyProviderConfigWithDefaultModels,
|
||||||
applyProviderConfigWithModelCatalog,
|
applyProviderConfigWithModelCatalog,
|
||||||
|
withAgentModelAliases,
|
||||||
} from "../plugins/provider-onboarding-config.js";
|
} from "../plugins/provider-onboarding-config.js";
|
||||||
|
|
||||||
function makeModel(id: string): ModelDefinitionConfig {
|
function makeModel(id: string): ModelDefinitionConfig {
|
||||||
@ -97,4 +100,76 @@ describe("onboard auth provider config merges", () => {
|
|||||||
|
|
||||||
expect(next.models?.providers?.custom?.models?.map((m) => m.id)).toEqual(["model-z"]);
|
expect(next.models?.providers?.custom?.models?.map((m) => m.id)).toEqual(["model-z"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("preserves explicit aliases when adding provider alias presets", () => {
|
||||||
|
expect(
|
||||||
|
withAgentModelAliases(
|
||||||
|
{
|
||||||
|
"custom/model-a": { alias: "Pinned" },
|
||||||
|
},
|
||||||
|
[{ modelRef: "custom/model-a", alias: "Preset" }, "custom/model-b"],
|
||||||
|
),
|
||||||
|
).toEqual({
|
||||||
|
"custom/model-a": { alias: "Pinned" },
|
||||||
|
"custom/model-b": {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies default-model presets with alias and primary model", () => {
|
||||||
|
const next = applyProviderConfigWithDefaultModelPreset(
|
||||||
|
{
|
||||||
|
agents: {
|
||||||
|
defaults: {
|
||||||
|
models: {
|
||||||
|
"custom/model-z": { alias: "Pinned" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
providerId: "custom",
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://example.com/v1",
|
||||||
|
defaultModel: makeModel("model-z"),
|
||||||
|
aliases: [{ modelRef: "custom/model-z", alias: "Preset" }],
|
||||||
|
primaryModelRef: "custom/model-z",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(next.agents?.defaults?.models?.["custom/model-z"]).toEqual({ alias: "Pinned" });
|
||||||
|
expect(next.agents?.defaults?.model).toEqual({ primary: "custom/model-z" });
|
||||||
|
});
|
||||||
|
|
||||||
|
it("applies catalog presets with alias and merged catalog models", () => {
|
||||||
|
const next = applyProviderConfigWithModelCatalogPreset(
|
||||||
|
{
|
||||||
|
models: {
|
||||||
|
providers: {
|
||||||
|
custom: {
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://example.com/v1",
|
||||||
|
models: [makeModel("model-a")],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
providerId: "custom",
|
||||||
|
api: "openai-completions",
|
||||||
|
baseUrl: "https://example.com/v1",
|
||||||
|
catalogModels: [makeModel("model-a"), makeModel("model-b")],
|
||||||
|
aliases: [{ modelRef: "custom/model-b", alias: "Catalog Alias" }],
|
||||||
|
primaryModelRef: "custom/model-b",
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(next.models?.providers?.custom?.models?.map((model) => model.id)).toEqual([
|
||||||
|
"model-a",
|
||||||
|
"model-b",
|
||||||
|
]);
|
||||||
|
expect(next.agents?.defaults?.models?.["custom/model-b"]).toEqual({
|
||||||
|
alias: "Catalog Alias",
|
||||||
|
});
|
||||||
|
expect(next.agents?.defaults?.model).toEqual({ primary: "custom/model-b" });
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
48
src/plugin-sdk/channel-pairing.test.ts
Normal file
48
src/plugin-sdk/channel-pairing.test.ts
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||||
|
import { createChannelPairingController } from "./channel-pairing.js";
|
||||||
|
|
||||||
|
describe("createChannelPairingController", () => {
|
||||||
|
it("scopes store access and issues pairing challenges through the scoped store", async () => {
|
||||||
|
const readAllowFromStore = vi.fn(async () => ["alice"]);
|
||||||
|
const upsertPairingRequest = vi.fn(async () => ({ code: "123456", created: true }));
|
||||||
|
const replies: string[] = [];
|
||||||
|
const sendPairingReply = vi.fn(async (text: string) => {
|
||||||
|
replies.push(text);
|
||||||
|
});
|
||||||
|
const runtime = {
|
||||||
|
channel: {
|
||||||
|
pairing: {
|
||||||
|
readAllowFromStore,
|
||||||
|
upsertPairingRequest,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} as unknown as PluginRuntime;
|
||||||
|
|
||||||
|
const pairing = createChannelPairingController({
|
||||||
|
core: runtime,
|
||||||
|
channel: "googlechat",
|
||||||
|
accountId: "Primary",
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect(pairing.readAllowFromStore()).resolves.toEqual(["alice"]);
|
||||||
|
await pairing.issueChallenge({
|
||||||
|
senderId: "user-1",
|
||||||
|
senderIdLine: "Your id: user-1",
|
||||||
|
sendPairingReply,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readAllowFromStore).toHaveBeenCalledWith({
|
||||||
|
channel: "googlechat",
|
||||||
|
accountId: "primary",
|
||||||
|
});
|
||||||
|
expect(upsertPairingRequest).toHaveBeenCalledWith({
|
||||||
|
channel: "googlechat",
|
||||||
|
accountId: "primary",
|
||||||
|
id: "user-1",
|
||||||
|
meta: undefined,
|
||||||
|
});
|
||||||
|
expect(sendPairingReply).toHaveBeenCalledTimes(1);
|
||||||
|
expect(replies[0]).toContain("123456");
|
||||||
|
});
|
||||||
|
});
|
||||||
31
src/plugin-sdk/channel-pairing.ts
Normal file
31
src/plugin-sdk/channel-pairing.ts
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
import type { ChannelId } from "../channels/plugins/types.js";
|
||||||
|
import { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
||||||
|
import type { PluginRuntime } from "../plugins/runtime/types.js";
|
||||||
|
import { createScopedPairingAccess } from "./pairing-access.js";
|
||||||
|
|
||||||
|
export { createScopedPairingAccess } from "./pairing-access.js";
|
||||||
|
|
||||||
|
type ScopedPairingAccess = ReturnType<typeof createScopedPairingAccess>;
|
||||||
|
|
||||||
|
export type ChannelPairingController = ScopedPairingAccess & {
|
||||||
|
issueChallenge: (
|
||||||
|
params: Omit<Parameters<typeof issuePairingChallenge>[0], "channel" | "upsertPairingRequest">,
|
||||||
|
) => ReturnType<typeof issuePairingChallenge>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createChannelPairingController(params: {
|
||||||
|
core: PluginRuntime;
|
||||||
|
channel: ChannelId;
|
||||||
|
accountId: string;
|
||||||
|
}): ChannelPairingController {
|
||||||
|
const access = createScopedPairingAccess(params);
|
||||||
|
return {
|
||||||
|
...access,
|
||||||
|
issueChallenge: (challenge) =>
|
||||||
|
issuePairingChallenge({
|
||||||
|
channel: params.channel,
|
||||||
|
upsertPairingRequest: access.upsertPairingRequest,
|
||||||
|
...challenge,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
}
|
||||||
39
src/plugin-sdk/channel-reply-pipeline.test.ts
Normal file
39
src/plugin-sdk/channel-reply-pipeline.test.ts
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import { describe, expect, it, vi } from "vitest";
|
||||||
|
import { createChannelReplyPipeline } from "./channel-reply-pipeline.js";
|
||||||
|
|
||||||
|
describe("createChannelReplyPipeline", () => {
|
||||||
|
it("builds prefix options without forcing typing support", () => {
|
||||||
|
const pipeline = createChannelReplyPipeline({
|
||||||
|
cfg: {},
|
||||||
|
agentId: "main",
|
||||||
|
channel: "telegram",
|
||||||
|
accountId: "default",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(typeof pipeline.onModelSelected).toBe("function");
|
||||||
|
expect(typeof pipeline.responsePrefixContextProvider).toBe("function");
|
||||||
|
expect(pipeline.typingCallbacks).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("builds typing callbacks when typing config is provided", async () => {
|
||||||
|
const start = vi.fn(async () => {});
|
||||||
|
const stop = vi.fn(async () => {});
|
||||||
|
const pipeline = createChannelReplyPipeline({
|
||||||
|
cfg: {},
|
||||||
|
agentId: "main",
|
||||||
|
channel: "discord",
|
||||||
|
accountId: "default",
|
||||||
|
typing: {
|
||||||
|
start,
|
||||||
|
stop,
|
||||||
|
onStartError: () => {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await pipeline.typingCallbacks?.onReplyStart();
|
||||||
|
pipeline.typingCallbacks?.onIdle?.();
|
||||||
|
|
||||||
|
expect(start).toHaveBeenCalled();
|
||||||
|
expect(stop).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
38
src/plugin-sdk/channel-reply-pipeline.ts
Normal file
38
src/plugin-sdk/channel-reply-pipeline.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import {
|
||||||
|
createReplyPrefixContext,
|
||||||
|
createReplyPrefixOptions,
|
||||||
|
type ReplyPrefixContextBundle,
|
||||||
|
type ReplyPrefixOptions,
|
||||||
|
} from "../channels/reply-prefix.js";
|
||||||
|
import {
|
||||||
|
createTypingCallbacks,
|
||||||
|
type CreateTypingCallbacksParams,
|
||||||
|
type TypingCallbacks,
|
||||||
|
} from "../channels/typing.js";
|
||||||
|
|
||||||
|
export type ReplyPrefixContext = ReplyPrefixContextBundle["prefixContext"];
|
||||||
|
export type { ReplyPrefixContextBundle, ReplyPrefixOptions };
|
||||||
|
export type { CreateTypingCallbacksParams, TypingCallbacks };
|
||||||
|
export { createReplyPrefixContext, createReplyPrefixOptions, createTypingCallbacks };
|
||||||
|
|
||||||
|
export type ChannelReplyPipeline = ReplyPrefixOptions & {
|
||||||
|
typingCallbacks?: TypingCallbacks;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function createChannelReplyPipeline(params: {
|
||||||
|
cfg: Parameters<typeof createReplyPrefixOptions>[0]["cfg"];
|
||||||
|
agentId: string;
|
||||||
|
channel?: string;
|
||||||
|
accountId?: string;
|
||||||
|
typing?: CreateTypingCallbacksParams;
|
||||||
|
}): ChannelReplyPipeline {
|
||||||
|
return {
|
||||||
|
...createReplyPrefixOptions({
|
||||||
|
cfg: params.cfg,
|
||||||
|
agentId: params.agentId,
|
||||||
|
channel: params.channel,
|
||||||
|
accountId: params.accountId,
|
||||||
|
}),
|
||||||
|
...(params.typing ? { typingCallbacks: createTypingCallbacks(params.typing) } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
38
src/plugin-sdk/channel-setup.test.ts
Normal file
38
src/plugin-sdk/channel-setup.test.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
|
|
||||||
|
describe("createOptionalChannelSetupSurface", () => {
|
||||||
|
it("returns a matched adapter and wizard for optional plugins", async () => {
|
||||||
|
const setup = createOptionalChannelSetupSurface({
|
||||||
|
channel: "example",
|
||||||
|
label: "Example",
|
||||||
|
npmSpec: "@openclaw/example",
|
||||||
|
docsPath: "/channels/example",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(setup.setupAdapter.resolveAccountId?.({ cfg: {} })).toBe("default");
|
||||||
|
expect(
|
||||||
|
setup.setupAdapter.validateInput?.({
|
||||||
|
cfg: {},
|
||||||
|
accountId: "default",
|
||||||
|
input: {},
|
||||||
|
}),
|
||||||
|
).toContain("@openclaw/example");
|
||||||
|
expect(setup.setupWizard.channel).toBe("example");
|
||||||
|
expect(setup.setupWizard.status.unconfiguredHint).toContain("/channels/example");
|
||||||
|
await expect(
|
||||||
|
setup.setupWizard.finalize?.({
|
||||||
|
cfg: {},
|
||||||
|
accountId: "default",
|
||||||
|
credentialValues: {},
|
||||||
|
runtime: {
|
||||||
|
log: () => {},
|
||||||
|
error: () => {},
|
||||||
|
exit: async () => {},
|
||||||
|
},
|
||||||
|
prompter: {} as never,
|
||||||
|
forceAllowFrom: false,
|
||||||
|
}),
|
||||||
|
).rejects.toThrow("@openclaw/example");
|
||||||
|
});
|
||||||
|
});
|
||||||
42
src/plugin-sdk/channel-setup.ts
Normal file
42
src/plugin-sdk/channel-setup.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import type { ChannelSetupWizard } from "../channels/plugins/setup-wizard.js";
|
||||||
|
import type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
||||||
|
import {
|
||||||
|
createOptionalChannelSetupAdapter,
|
||||||
|
createOptionalChannelSetupWizard,
|
||||||
|
} from "./optional-channel-setup.js";
|
||||||
|
|
||||||
|
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
||||||
|
export type { ChannelSetupDmPolicy, ChannelSetupWizard } from "./setup.js";
|
||||||
|
export {
|
||||||
|
DEFAULT_ACCOUNT_ID,
|
||||||
|
createTopLevelChannelDmPolicy,
|
||||||
|
formatDocsLink,
|
||||||
|
setSetupChannelEnabled,
|
||||||
|
splitSetupEntries,
|
||||||
|
} from "./setup.js";
|
||||||
|
|
||||||
|
type OptionalChannelSetupParams = {
|
||||||
|
channel: string;
|
||||||
|
label: string;
|
||||||
|
npmSpec?: string;
|
||||||
|
docsPath?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type OptionalChannelSetupSurface = {
|
||||||
|
setupAdapter: ChannelSetupAdapter;
|
||||||
|
setupWizard: ChannelSetupWizard;
|
||||||
|
};
|
||||||
|
|
||||||
|
export {
|
||||||
|
createOptionalChannelSetupAdapter,
|
||||||
|
createOptionalChannelSetupWizard,
|
||||||
|
} from "./optional-channel-setup.js";
|
||||||
|
|
||||||
|
export function createOptionalChannelSetupSurface(
|
||||||
|
params: OptionalChannelSetupParams,
|
||||||
|
): OptionalChannelSetupSurface {
|
||||||
|
return {
|
||||||
|
setupAdapter: createOptionalChannelSetupAdapter(params),
|
||||||
|
setupWizard: createOptionalChannelSetupWizard(params),
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -38,7 +38,7 @@ export type {
|
|||||||
} from "../channels/plugins/types.adapters.js";
|
} from "../channels/plugins/types.adapters.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixContext } from "../channels/reply-prefix.js";
|
export { createReplyPrefixContext } from "../channels/reply-prefix.js";
|
||||||
export { createTypingCallbacks } from "../channels/typing.js";
|
export { createChannelReplyPipeline, createTypingCallbacks } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig as ClawdbotConfig, OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig as ClawdbotConfig, OpenClawConfig } from "../config/config.js";
|
||||||
export {
|
export {
|
||||||
resolveAllowlistProviderRuntimeGroupPolicy,
|
resolveAllowlistProviderRuntimeGroupPolicy,
|
||||||
@ -47,13 +47,13 @@ export {
|
|||||||
warnMissingProviderGroupPolicyFallbackOnce,
|
warnMissingProviderGroupPolicyFallbackOnce,
|
||||||
} from "../config/runtime-group-policy.js";
|
} from "../config/runtime-group-policy.js";
|
||||||
export type { DmPolicy, GroupToolPolicyConfig } from "../config/types.js";
|
export type { DmPolicy, GroupToolPolicyConfig } from "../config/types.js";
|
||||||
export type { SecretInput } from "../config/types.secrets.js";
|
export type { SecretInput } from "./secret-input.js";
|
||||||
export {
|
export {
|
||||||
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
} from "../config/types.secrets.js";
|
} from "./secret-input.js";
|
||||||
export { buildSecretInputSchema } from "./secret-input-schema.js";
|
|
||||||
export { createDedupeCache } from "../infra/dedupe.js";
|
export { createDedupeCache } from "../infra/dedupe.js";
|
||||||
export { installRequestBodyLimitGuard, readJsonBodyWithLimit } from "../infra/http-body.js";
|
export { installRequestBodyLimitGuard, readJsonBodyWithLimit } from "../infra/http-body.js";
|
||||||
export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
||||||
@ -70,8 +70,7 @@ export type { WizardPrompter } from "../wizard/prompts.js";
|
|||||||
export { feishuSetupWizard, feishuSetupAdapter } from "../../extensions/feishu/setup-api.js";
|
export { feishuSetupWizard, feishuSetupAdapter } from "../../extensions/feishu/setup-api.js";
|
||||||
export { buildAgentMediaPayload } from "./agent-media-payload.js";
|
export { buildAgentMediaPayload } from "./agent-media-payload.js";
|
||||||
export { readJsonFileWithFallback } from "./json-store.js";
|
export { readJsonFileWithFallback } from "./json-store.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
|
||||||
export { createPersistentDedupe } from "./persistent-dedupe.js";
|
export { createPersistentDedupe } from "./persistent-dedupe.js";
|
||||||
export {
|
export {
|
||||||
buildBaseChannelStatusSummary,
|
buildBaseChannelStatusSummary,
|
||||||
@ -85,9 +84,9 @@ export {
|
|||||||
parseFeishuConversationId,
|
parseFeishuConversationId,
|
||||||
} from "../../extensions/feishu/src/conversation-id.js";
|
} from "../../extensions/feishu/src/conversation-id.js";
|
||||||
export {
|
export {
|
||||||
createFixedWindowRateLimiter,
|
|
||||||
createWebhookAnomalyTracker,
|
createWebhookAnomalyTracker,
|
||||||
|
createFixedWindowRateLimiter,
|
||||||
WEBHOOK_ANOMALY_COUNTER_DEFAULTS,
|
WEBHOOK_ANOMALY_COUNTER_DEFAULTS,
|
||||||
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
||||||
} from "./webhook-memory-guards.js";
|
} from "./webhook-ingress.js";
|
||||||
export { applyBasicWebhookRequestGuards } from "./webhook-request-guards.js";
|
export { applyBasicWebhookRequestGuards } from "./webhook-ingress.js";
|
||||||
|
|||||||
@ -2,10 +2,7 @@
|
|||||||
// Keep this list additive and scoped to symbols used under extensions/googlechat.
|
// Keep this list additive and scoped to symbols used under extensions/googlechat.
|
||||||
|
|
||||||
import { resolveChannelGroupRequireMention } from "./channel-policy.js";
|
import { resolveChannelGroupRequireMention } from "./channel-policy.js";
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
createActionGate,
|
createActionGate,
|
||||||
@ -49,7 +46,7 @@ export type {
|
|||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { getChatChannelMeta } from "../channels/registry.js";
|
export { getChatChannelMeta } from "../channels/registry.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
||||||
export {
|
export {
|
||||||
@ -71,26 +68,23 @@ export { resolveDmGroupAccessWithLists } from "../security/dm-policy-shared.js";
|
|||||||
export { formatDocsLink } from "../terminal/links.js";
|
export { formatDocsLink } from "../terminal/links.js";
|
||||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
export type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "./inbound-envelope.js";
|
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "./inbound-envelope.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
|
||||||
export {
|
export {
|
||||||
evaluateGroupRouteAccessForPolicy,
|
evaluateGroupRouteAccessForPolicy,
|
||||||
resolveSenderScopedGroupPolicy,
|
resolveSenderScopedGroupPolicy,
|
||||||
} from "./group-access.js";
|
} from "./group-access.js";
|
||||||
export { extractToolSend } from "./tool-send.js";
|
export { extractToolSend } from "./tool-send.js";
|
||||||
export { resolveWebhookPath } from "./webhook-path.js";
|
|
||||||
export type { WebhookInFlightLimiter } from "./webhook-request-guards.js";
|
|
||||||
export {
|
export {
|
||||||
beginWebhookRequestPipelineOrReject,
|
beginWebhookRequestPipelineOrReject,
|
||||||
createWebhookInFlightLimiter,
|
createWebhookInFlightLimiter,
|
||||||
readJsonWebhookBodyOrReject,
|
readJsonWebhookBodyOrReject,
|
||||||
} from "./webhook-request-guards.js";
|
|
||||||
export {
|
|
||||||
registerWebhookTargetWithPluginRoute,
|
registerWebhookTargetWithPluginRoute,
|
||||||
resolveWebhookTargets,
|
resolveWebhookPath,
|
||||||
resolveWebhookTargetWithAuthOrReject,
|
resolveWebhookTargetWithAuthOrReject,
|
||||||
|
resolveWebhookTargets,
|
||||||
|
type WebhookInFlightLimiter,
|
||||||
withResolvedWebhookRequestPipeline,
|
withResolvedWebhookRequestPipeline,
|
||||||
} from "./webhook-targets.js";
|
} from "./webhook-ingress.js";
|
||||||
|
|
||||||
type GoogleChatGroupContext = {
|
type GoogleChatGroupContext = {
|
||||||
cfg: import("../config/config.js").OpenClawConfig;
|
cfg: import("../config/config.js").OpenClawConfig;
|
||||||
@ -107,16 +101,12 @@ export function resolveGoogleChatGroupRequireMention(params: GoogleChatGroupCont
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export const googlechatSetupAdapter = createOptionalChannelSetupAdapter({
|
const googlechatSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "googlechat",
|
channel: "googlechat",
|
||||||
label: "Google Chat",
|
label: "Google Chat",
|
||||||
npmSpec: "@openclaw/googlechat",
|
npmSpec: "@openclaw/googlechat",
|
||||||
docsPath: "/channels/googlechat",
|
docsPath: "/channels/googlechat",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const googlechatSetupWizard = createOptionalChannelSetupWizard({
|
export const googlechatSetupAdapter = googlechatSetup.setupAdapter;
|
||||||
channel: "googlechat",
|
export const googlechatSetupWizard = googlechatSetup.setupWizard;
|
||||||
label: "Google Chat",
|
|
||||||
npmSpec: "@openclaw/googlechat",
|
|
||||||
docsPath: "/channels/googlechat",
|
|
||||||
});
|
|
||||||
|
|||||||
@ -23,7 +23,7 @@ export { patchScopedAccountConfig } from "../channels/plugins/setup-helpers.js";
|
|||||||
export type { BaseProbeResult } from "../channels/plugins/types.js";
|
export type { BaseProbeResult } from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { getChatChannelMeta } from "../channels/registry.js";
|
export { getChatChannelMeta } from "../channels/registry.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
||||||
export {
|
export {
|
||||||
@ -69,8 +69,7 @@ export {
|
|||||||
} from "../security/dm-policy-shared.js";
|
} from "../security/dm-policy-shared.js";
|
||||||
export { formatDocsLink } from "../terminal/links.js";
|
export { formatDocsLink } from "../terminal/links.js";
|
||||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
export type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
|
||||||
export { dispatchInboundReplyWithBase } from "./inbound-reply-dispatch.js";
|
export { dispatchInboundReplyWithBase } from "./inbound-reply-dispatch.js";
|
||||||
export { ircSetupAdapter, ircSetupWizard } from "../../extensions/irc/api.js";
|
export { ircSetupAdapter, ircSetupWizard } from "../../extensions/irc/api.js";
|
||||||
export type { OutboundReplyPayload } from "./reply-payload.js";
|
export type { OutboundReplyPayload } from "./reply-payload.js";
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
// Narrow plugin-sdk surface for the bundled matrix plugin.
|
// Narrow plugin-sdk surface for the bundled matrix plugin.
|
||||||
// Keep this list additive and scoped to symbols used under extensions/matrix.
|
// Keep this list additive and scoped to symbols used under extensions/matrix.
|
||||||
|
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
createActionGate,
|
createActionGate,
|
||||||
@ -60,8 +57,8 @@ export type {
|
|||||||
ChannelToolSend,
|
ChannelToolSend,
|
||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export { createTypingCallbacks } from "../channels/typing.js";
|
export { createTypingCallbacks } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export {
|
export {
|
||||||
GROUP_POLICY_BLOCKED_LABEL,
|
GROUP_POLICY_BLOCKED_LABEL,
|
||||||
@ -75,13 +72,13 @@ export type {
|
|||||||
GroupToolPolicyConfig,
|
GroupToolPolicyConfig,
|
||||||
MarkdownTableMode,
|
MarkdownTableMode,
|
||||||
} from "../config/types.js";
|
} from "../config/types.js";
|
||||||
export type { SecretInput } from "../config/types.secrets.js";
|
export type { SecretInput } from "./secret-input.js";
|
||||||
export {
|
export {
|
||||||
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
} from "../config/types.secrets.js";
|
} from "./secret-input.js";
|
||||||
export { buildSecretInputSchema } from "./secret-input-schema.js";
|
|
||||||
export { ToolPolicySchema } from "../config/zod-schema.agent-runtime.js";
|
export { ToolPolicySchema } from "../config/zod-schema.agent-runtime.js";
|
||||||
export { MarkdownConfigSchema } from "../config/zod-schema.core.js";
|
export { MarkdownConfigSchema } from "../config/zod-schema.core.js";
|
||||||
export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
||||||
@ -103,7 +100,7 @@ export {
|
|||||||
evaluateGroupRouteAccessForPolicy,
|
evaluateGroupRouteAccessForPolicy,
|
||||||
resolveSenderScopedGroupPolicy,
|
resolveSenderScopedGroupPolicy,
|
||||||
} from "./group-access.js";
|
} from "./group-access.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { formatResolvedUnresolvedNote } from "./resolution-notes.js";
|
export { formatResolvedUnresolvedNote } from "./resolution-notes.js";
|
||||||
export { runPluginCommandWithTimeout } from "./run-command.js";
|
export { runPluginCommandWithTimeout } from "./run-command.js";
|
||||||
export { dispatchReplyFromConfigWithSettledDispatcher } from "./inbound-reply-dispatch.js";
|
export { dispatchReplyFromConfigWithSettledDispatcher } from "./inbound-reply-dispatch.js";
|
||||||
@ -114,16 +111,12 @@ export {
|
|||||||
collectStatusIssuesFromLastError,
|
collectStatusIssuesFromLastError,
|
||||||
} from "./status-helpers.js";
|
} from "./status-helpers.js";
|
||||||
|
|
||||||
export const matrixSetupWizard = createOptionalChannelSetupWizard({
|
const matrixSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "matrix",
|
channel: "matrix",
|
||||||
label: "Matrix",
|
label: "Matrix",
|
||||||
npmSpec: "@openclaw/matrix",
|
npmSpec: "@openclaw/matrix",
|
||||||
docsPath: "/channels/matrix",
|
docsPath: "/channels/matrix",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const matrixSetupAdapter = createOptionalChannelSetupAdapter({
|
export const matrixSetupWizard = matrixSetup.setupWizard;
|
||||||
channel: "matrix",
|
export const matrixSetupAdapter = matrixSetup.setupAdapter;
|
||||||
label: "Matrix",
|
|
||||||
npmSpec: "@openclaw/matrix",
|
|
||||||
docsPath: "/channels/matrix",
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
// Narrow plugin-sdk surface for the bundled msteams plugin.
|
// Narrow plugin-sdk surface for the bundled msteams plugin.
|
||||||
// Keep this list additive and scoped to symbols used under extensions/msteams.
|
// Keep this list additive and scoped to symbols used under extensions/msteams.
|
||||||
|
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export type { ChunkMode } from "../auto-reply/chunk.js";
|
export type { ChunkMode } from "../auto-reply/chunk.js";
|
||||||
export type { HistoryEntry } from "../auto-reply/reply/history.js";
|
export type { HistoryEntry } from "../auto-reply/reply/history.js";
|
||||||
@ -55,8 +52,8 @@ export type {
|
|||||||
ChannelOutboundAdapter,
|
ChannelOutboundAdapter,
|
||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export { createTypingCallbacks } from "../channels/typing.js";
|
export { createTypingCallbacks } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
||||||
export { resolveToolsBySender } from "../config/group-policy.js";
|
export { resolveToolsBySender } from "../config/group-policy.js";
|
||||||
@ -109,7 +106,7 @@ export { withFileLock } from "./file-lock.js";
|
|||||||
export { dispatchReplyFromConfigWithSettledDispatcher } from "./inbound-reply-dispatch.js";
|
export { dispatchReplyFromConfigWithSettledDispatcher } from "./inbound-reply-dispatch.js";
|
||||||
export { readJsonFileWithFallback, writeJsonFileAtomically } from "./json-store.js";
|
export { readJsonFileWithFallback, writeJsonFileAtomically } from "./json-store.js";
|
||||||
export { loadOutboundMediaFromUrl } from "./outbound-media.js";
|
export { loadOutboundMediaFromUrl } from "./outbound-media.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { resolveInboundSessionEnvelopeContext } from "../channels/session-envelope.js";
|
export { resolveInboundSessionEnvelopeContext } from "../channels/session-envelope.js";
|
||||||
export {
|
export {
|
||||||
buildHostnameAllowlistPolicyFromSuffixAllowlist,
|
buildHostnameAllowlistPolicyFromSuffixAllowlist,
|
||||||
@ -124,16 +121,12 @@ export {
|
|||||||
} from "./status-helpers.js";
|
} from "./status-helpers.js";
|
||||||
export { normalizeStringEntries } from "../shared/string-normalization.js";
|
export { normalizeStringEntries } from "../shared/string-normalization.js";
|
||||||
|
|
||||||
export const msteamsSetupWizard = createOptionalChannelSetupWizard({
|
const msteamsSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "msteams",
|
channel: "msteams",
|
||||||
label: "Microsoft Teams",
|
label: "Microsoft Teams",
|
||||||
npmSpec: "@openclaw/msteams",
|
npmSpec: "@openclaw/msteams",
|
||||||
docsPath: "/channels/msteams",
|
docsPath: "/channels/msteams",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const msteamsSetupAdapter = createOptionalChannelSetupAdapter({
|
export const msteamsSetupWizard = msteamsSetup.setupWizard;
|
||||||
channel: "msteams",
|
export const msteamsSetupAdapter = msteamsSetup.setupAdapter;
|
||||||
label: "Microsoft Teams",
|
|
||||||
npmSpec: "@openclaw/msteams",
|
|
||||||
docsPath: "/channels/msteams",
|
|
||||||
});
|
|
||||||
|
|||||||
@ -32,7 +32,7 @@ export {
|
|||||||
export { createAccountListHelpers } from "../channels/plugins/account-helpers.js";
|
export { createAccountListHelpers } from "../channels/plugins/account-helpers.js";
|
||||||
export type { ChannelGroupContext, ChannelSetupInput } from "../channels/plugins/types.js";
|
export type { ChannelGroupContext, ChannelSetupInput } from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { mapAllowFromEntries } from "./channel-config-helpers.js";
|
export { mapAllowFromEntries } from "./channel-config-helpers.js";
|
||||||
export { evaluateMatchedGroupAccessForPolicy } from "./group-access.js";
|
export { evaluateMatchedGroupAccessForPolicy } from "./group-access.js";
|
||||||
@ -49,13 +49,13 @@ export type {
|
|||||||
GroupPolicy,
|
GroupPolicy,
|
||||||
GroupToolPolicyConfig,
|
GroupToolPolicyConfig,
|
||||||
} from "../config/types.js";
|
} from "../config/types.js";
|
||||||
export type { SecretInput } from "../config/types.secrets.js";
|
export type { SecretInput } from "./secret-input.js";
|
||||||
export {
|
export {
|
||||||
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
} from "../config/types.secrets.js";
|
} from "./secret-input.js";
|
||||||
export { buildSecretInputSchema } from "./secret-input-schema.js";
|
|
||||||
export { ToolPolicySchema } from "../config/zod-schema.agent-runtime.js";
|
export { ToolPolicySchema } from "../config/zod-schema.agent-runtime.js";
|
||||||
export {
|
export {
|
||||||
BlockStreamingCoalesceSchema,
|
BlockStreamingCoalesceSchema,
|
||||||
@ -88,8 +88,7 @@ export {
|
|||||||
listConfiguredAccountIds,
|
listConfiguredAccountIds,
|
||||||
resolveAccountWithDefaultFallback,
|
resolveAccountWithDefaultFallback,
|
||||||
} from "./account-resolution.js";
|
} from "./account-resolution.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
|
||||||
export { createPersistentDedupe } from "./persistent-dedupe.js";
|
export { createPersistentDedupe } from "./persistent-dedupe.js";
|
||||||
export type { OutboundReplyPayload } from "./reply-payload.js";
|
export type { OutboundReplyPayload } from "./reply-payload.js";
|
||||||
export {
|
export {
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
// Narrow plugin-sdk surface for the bundled nostr plugin.
|
// Narrow plugin-sdk surface for the bundled nostr plugin.
|
||||||
// Keep this list additive and scoped to symbols used under extensions/nostr.
|
// Keep this list additive and scoped to symbols used under extensions/nostr.
|
||||||
|
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||||
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
export type { ChannelSetupAdapter } from "../channels/plugins/types.adapters.js";
|
||||||
@ -25,16 +22,12 @@ export {
|
|||||||
export { createFixedWindowRateLimiter } from "./webhook-memory-guards.js";
|
export { createFixedWindowRateLimiter } from "./webhook-memory-guards.js";
|
||||||
export { mapAllowFromEntries } from "./channel-config-helpers.js";
|
export { mapAllowFromEntries } from "./channel-config-helpers.js";
|
||||||
|
|
||||||
export const nostrSetupAdapter = createOptionalChannelSetupAdapter({
|
const nostrSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "nostr",
|
channel: "nostr",
|
||||||
label: "Nostr",
|
label: "Nostr",
|
||||||
npmSpec: "@openclaw/nostr",
|
npmSpec: "@openclaw/nostr",
|
||||||
docsPath: "/channels/nostr",
|
docsPath: "/channels/nostr",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const nostrSetupWizard = createOptionalChannelSetupWizard({
|
export const nostrSetupAdapter = nostrSetup.setupAdapter;
|
||||||
channel: "nostr",
|
export const nostrSetupWizard = nostrSetup.setupWizard;
|
||||||
label: "Nostr",
|
|
||||||
npmSpec: "@openclaw/nostr",
|
|
||||||
docsPath: "/channels/nostr",
|
|
||||||
});
|
|
||||||
|
|||||||
@ -9,8 +9,13 @@ export type {
|
|||||||
export {
|
export {
|
||||||
applyAgentDefaultModelPrimary,
|
applyAgentDefaultModelPrimary,
|
||||||
applyOnboardAuthAgentModelsAndProviders,
|
applyOnboardAuthAgentModelsAndProviders,
|
||||||
|
applyProviderConfigWithDefaultModelPreset,
|
||||||
|
applyProviderConfigWithDefaultModelsPreset,
|
||||||
applyProviderConfigWithDefaultModel,
|
applyProviderConfigWithDefaultModel,
|
||||||
applyProviderConfigWithDefaultModels,
|
applyProviderConfigWithDefaultModels,
|
||||||
|
applyProviderConfigWithModelCatalogPreset,
|
||||||
applyProviderConfigWithModelCatalog,
|
applyProviderConfigWithModelCatalog,
|
||||||
|
withAgentModelAliases,
|
||||||
} from "../plugins/provider-onboarding-config.js";
|
} from "../plugins/provider-onboarding-config.js";
|
||||||
|
export type { AgentModelAliasEntry } from "../plugins/provider-onboarding-config.js";
|
||||||
export { ensureModelAllowlistEntry } from "../plugins/provider-model-allowlist.js";
|
export { ensureModelAllowlistEntry } from "../plugins/provider-model-allowlist.js";
|
||||||
|
|||||||
24
src/plugin-sdk/secret-input.test.ts
Normal file
24
src/plugin-sdk/secret-input.test.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { describe, expect, it } from "vitest";
|
||||||
|
import {
|
||||||
|
buildOptionalSecretInputSchema,
|
||||||
|
buildSecretInputArraySchema,
|
||||||
|
normalizeSecretInputString,
|
||||||
|
} from "./secret-input.js";
|
||||||
|
|
||||||
|
describe("plugin-sdk secret input helpers", () => {
|
||||||
|
it("accepts undefined for optional secret input", () => {
|
||||||
|
expect(buildOptionalSecretInputSchema().safeParse(undefined).success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("accepts arrays of secret inputs", () => {
|
||||||
|
const result = buildSecretInputArraySchema().safeParse([
|
||||||
|
"sk-plain",
|
||||||
|
{ source: "env", provider: "default", id: "OPENAI_API_KEY" },
|
||||||
|
]);
|
||||||
|
expect(result.success).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("normalizes plaintext secret strings", () => {
|
||||||
|
expect(normalizeSecretInputString(" sk-test ")).toBe("sk-test");
|
||||||
|
});
|
||||||
|
});
|
||||||
23
src/plugin-sdk/secret-input.ts
Normal file
23
src/plugin-sdk/secret-input.ts
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { z } from "zod";
|
||||||
|
import {
|
||||||
|
hasConfiguredSecretInput,
|
||||||
|
normalizeResolvedSecretInputString,
|
||||||
|
normalizeSecretInputString,
|
||||||
|
} from "../config/types.secrets.js";
|
||||||
|
import { buildSecretInputSchema } from "./secret-input-schema.js";
|
||||||
|
|
||||||
|
export type { SecretInput } from "../config/types.secrets.js";
|
||||||
|
export {
|
||||||
|
buildSecretInputSchema,
|
||||||
|
hasConfiguredSecretInput,
|
||||||
|
normalizeResolvedSecretInputString,
|
||||||
|
normalizeSecretInputString,
|
||||||
|
};
|
||||||
|
|
||||||
|
export function buildOptionalSecretInputSchema() {
|
||||||
|
return buildSecretInputSchema().optional();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildSecretInputArraySchema() {
|
||||||
|
return z.array(buildSecretInputSchema());
|
||||||
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
import * as bluebubblesSdk from "openclaw/plugin-sdk/bluebubbles";
|
import * as bluebubblesSdk from "openclaw/plugin-sdk/bluebubbles";
|
||||||
|
import * as channelPairingSdk from "openclaw/plugin-sdk/channel-pairing";
|
||||||
|
import * as channelReplyPipelineSdk from "openclaw/plugin-sdk/channel-reply-pipeline";
|
||||||
import * as channelRuntimeSdk from "openclaw/plugin-sdk/channel-runtime";
|
import * as channelRuntimeSdk from "openclaw/plugin-sdk/channel-runtime";
|
||||||
import * as channelSendResultSdk from "openclaw/plugin-sdk/channel-send-result";
|
import * as channelSendResultSdk from "openclaw/plugin-sdk/channel-send-result";
|
||||||
|
import * as channelSetupSdk from "openclaw/plugin-sdk/channel-setup";
|
||||||
import * as coreSdk from "openclaw/plugin-sdk/core";
|
import * as coreSdk from "openclaw/plugin-sdk/core";
|
||||||
import type {
|
import type {
|
||||||
ChannelMessageActionContext as CoreChannelMessageActionContext,
|
ChannelMessageActionContext as CoreChannelMessageActionContext,
|
||||||
@ -18,11 +21,13 @@ import * as replyPayloadSdk from "openclaw/plugin-sdk/reply-payload";
|
|||||||
import * as routingSdk from "openclaw/plugin-sdk/routing";
|
import * as routingSdk from "openclaw/plugin-sdk/routing";
|
||||||
import * as runtimeSdk from "openclaw/plugin-sdk/runtime";
|
import * as runtimeSdk from "openclaw/plugin-sdk/runtime";
|
||||||
import * as sandboxSdk from "openclaw/plugin-sdk/sandbox";
|
import * as sandboxSdk from "openclaw/plugin-sdk/sandbox";
|
||||||
|
import * as secretInputSdk from "openclaw/plugin-sdk/secret-input";
|
||||||
import * as selfHostedProviderSetupSdk from "openclaw/plugin-sdk/self-hosted-provider-setup";
|
import * as selfHostedProviderSetupSdk from "openclaw/plugin-sdk/self-hosted-provider-setup";
|
||||||
import * as setupSdk from "openclaw/plugin-sdk/setup";
|
import * as setupSdk from "openclaw/plugin-sdk/setup";
|
||||||
import * as slackSdk from "openclaw/plugin-sdk/slack";
|
import * as slackSdk from "openclaw/plugin-sdk/slack";
|
||||||
import * as telegramSdk from "openclaw/plugin-sdk/telegram";
|
import * as telegramSdk from "openclaw/plugin-sdk/telegram";
|
||||||
import * as testingSdk from "openclaw/plugin-sdk/testing";
|
import * as testingSdk from "openclaw/plugin-sdk/testing";
|
||||||
|
import * as webhookIngressSdk from "openclaw/plugin-sdk/webhook-ingress";
|
||||||
import * as whatsappSdk from "openclaw/plugin-sdk/whatsapp";
|
import * as whatsappSdk from "openclaw/plugin-sdk/whatsapp";
|
||||||
import * as whatsappActionRuntimeSdk from "openclaw/plugin-sdk/whatsapp-action-runtime";
|
import * as whatsappActionRuntimeSdk from "openclaw/plugin-sdk/whatsapp-action-runtime";
|
||||||
import * as whatsappLoginQrSdk from "openclaw/plugin-sdk/whatsapp-login-qr";
|
import * as whatsappLoginQrSdk from "openclaw/plugin-sdk/whatsapp-login-qr";
|
||||||
@ -111,6 +116,21 @@ describe("plugin-sdk subpath exports", () => {
|
|||||||
expect(typeof channelRuntimeSdk.sendPayloadMediaSequenceOrFallback).toBe("function");
|
expect(typeof channelRuntimeSdk.sendPayloadMediaSequenceOrFallback).toBe("function");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("exports channel setup helpers from the dedicated subpath", () => {
|
||||||
|
expect(typeof channelSetupSdk.createOptionalChannelSetupSurface).toBe("function");
|
||||||
|
expect(typeof channelSetupSdk.createTopLevelChannelDmPolicy).toBe("function");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exports channel pairing helpers from the dedicated subpath", () => {
|
||||||
|
expect(typeof channelPairingSdk.createChannelPairingController).toBe("function");
|
||||||
|
expect(typeof channelPairingSdk.createScopedPairingAccess).toBe("function");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exports channel reply pipeline helpers from the dedicated subpath", () => {
|
||||||
|
expect(typeof channelReplyPipelineSdk.createChannelReplyPipeline).toBe("function");
|
||||||
|
expect(typeof channelReplyPipelineSdk.createTypingCallbacks).toBe("function");
|
||||||
|
});
|
||||||
|
|
||||||
it("exports channel send-result helpers from the dedicated subpath", () => {
|
it("exports channel send-result helpers from the dedicated subpath", () => {
|
||||||
expect(typeof channelSendResultSdk.attachChannelToResult).toBe("function");
|
expect(typeof channelSendResultSdk.attachChannelToResult).toBe("function");
|
||||||
expect(typeof channelSendResultSdk.buildChannelSendResult).toBe("function");
|
expect(typeof channelSendResultSdk.buildChannelSendResult).toBe("function");
|
||||||
@ -162,6 +182,18 @@ describe("plugin-sdk subpath exports", () => {
|
|||||||
expect(typeof sandboxSdk.runPluginCommandWithTimeout).toBe("function");
|
expect(typeof sandboxSdk.runPluginCommandWithTimeout).toBe("function");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("exports secret input helpers from the dedicated subpath", () => {
|
||||||
|
expect(typeof secretInputSdk.buildSecretInputSchema).toBe("function");
|
||||||
|
expect(typeof secretInputSdk.buildOptionalSecretInputSchema).toBe("function");
|
||||||
|
expect(typeof secretInputSdk.normalizeSecretInputString).toBe("function");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("exports webhook ingress helpers from the dedicated subpath", () => {
|
||||||
|
expect(typeof webhookIngressSdk.resolveWebhookPath).toBe("function");
|
||||||
|
expect(typeof webhookIngressSdk.readJsonWebhookBodyOrReject).toBe("function");
|
||||||
|
expect(typeof webhookIngressSdk.withResolvedWebhookRequestPipeline).toBe("function");
|
||||||
|
});
|
||||||
|
|
||||||
it("exports shared core types used by bundled channels", () => {
|
it("exports shared core types used by bundled channels", () => {
|
||||||
expectTypeOf<CoreOpenClawPluginApi>().toMatchTypeOf<OpenClawPluginApi>();
|
expectTypeOf<CoreOpenClawPluginApi>().toMatchTypeOf<OpenClawPluginApi>();
|
||||||
expectTypeOf<CorePluginRuntime>().toMatchTypeOf<PluginRuntime>();
|
expectTypeOf<CorePluginRuntime>().toMatchTypeOf<PluginRuntime>();
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
// Narrow plugin-sdk surface for the bundled tlon plugin.
|
// Narrow plugin-sdk surface for the bundled tlon plugin.
|
||||||
// Keep this list additive and scoped to symbols used under extensions/tlon.
|
// Keep this list additive and scoped to symbols used under extensions/tlon.
|
||||||
|
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||||
@ -18,7 +15,7 @@ export type {
|
|||||||
ChannelSetupInput,
|
ChannelSetupInput,
|
||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { createDedupeCache } from "../infra/dedupe.js";
|
export { createDedupeCache } from "../infra/dedupe.js";
|
||||||
export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
export { fetchWithSsrFGuard } from "../infra/net/fetch-guard.js";
|
||||||
@ -33,16 +30,12 @@ export { formatDocsLink } from "../terminal/links.js";
|
|||||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
export type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
export { createLoggerBackedRuntime } from "./runtime.js";
|
export { createLoggerBackedRuntime } from "./runtime.js";
|
||||||
|
|
||||||
export const tlonSetupAdapter = createOptionalChannelSetupAdapter({
|
const tlonSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "tlon",
|
channel: "tlon",
|
||||||
label: "Tlon",
|
label: "Tlon",
|
||||||
npmSpec: "@openclaw/tlon",
|
npmSpec: "@openclaw/tlon",
|
||||||
docsPath: "/channels/tlon",
|
docsPath: "/channels/tlon",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const tlonSetupWizard = createOptionalChannelSetupWizard({
|
export const tlonSetupAdapter = tlonSetup.setupAdapter;
|
||||||
channel: "tlon",
|
export const tlonSetupWizard = tlonSetup.setupWizard;
|
||||||
label: "Tlon",
|
|
||||||
npmSpec: "@openclaw/tlon",
|
|
||||||
docsPath: "/channels/tlon",
|
|
||||||
});
|
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
// Narrow plugin-sdk surface for the bundled twitch plugin.
|
// Narrow plugin-sdk surface for the bundled twitch plugin.
|
||||||
// Keep this list additive and scoped to symbols used under extensions/twitch.
|
// Keep this list additive and scoped to symbols used under extensions/twitch.
|
||||||
|
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||||
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
export { buildChannelConfigSchema } from "../channels/plugins/config-schema.js";
|
||||||
@ -27,7 +24,7 @@ export type {
|
|||||||
ChannelStatusIssue,
|
ChannelStatusIssue,
|
||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { MarkdownConfigSchema } from "../config/zod-schema.core.js";
|
export { MarkdownConfigSchema } from "../config/zod-schema.core.js";
|
||||||
export type { OutboundDeliveryResult } from "../infra/outbound/deliver.js";
|
export type { OutboundDeliveryResult } from "../infra/outbound/deliver.js";
|
||||||
@ -39,14 +36,11 @@ export type { RuntimeEnv } from "../runtime.js";
|
|||||||
export { formatDocsLink } from "../terminal/links.js";
|
export { formatDocsLink } from "../terminal/links.js";
|
||||||
export type { WizardPrompter } from "../wizard/prompts.js";
|
export type { WizardPrompter } from "../wizard/prompts.js";
|
||||||
|
|
||||||
export const twitchSetupAdapter = createOptionalChannelSetupAdapter({
|
const twitchSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "twitch",
|
channel: "twitch",
|
||||||
label: "Twitch",
|
label: "Twitch",
|
||||||
npmSpec: "@openclaw/twitch",
|
npmSpec: "@openclaw/twitch",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const twitchSetupWizard = createOptionalChannelSetupWizard({
|
export const twitchSetupAdapter = twitchSetup.setupAdapter;
|
||||||
channel: "twitch",
|
export const twitchSetupWizard = twitchSetup.setupWizard;
|
||||||
label: "Twitch",
|
|
||||||
npmSpec: "@openclaw/twitch",
|
|
||||||
});
|
|
||||||
|
|||||||
38
src/plugin-sdk/webhook-ingress.ts
Normal file
38
src/plugin-sdk/webhook-ingress.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
export {
|
||||||
|
createBoundedCounter,
|
||||||
|
createFixedWindowRateLimiter,
|
||||||
|
createWebhookAnomalyTracker,
|
||||||
|
WEBHOOK_ANOMALY_COUNTER_DEFAULTS,
|
||||||
|
WEBHOOK_ANOMALY_STATUS_CODES,
|
||||||
|
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
||||||
|
type BoundedCounter,
|
||||||
|
type FixedWindowRateLimiter,
|
||||||
|
type WebhookAnomalyTracker,
|
||||||
|
} from "./webhook-memory-guards.js";
|
||||||
|
export {
|
||||||
|
applyBasicWebhookRequestGuards,
|
||||||
|
beginWebhookRequestPipelineOrReject,
|
||||||
|
createWebhookInFlightLimiter,
|
||||||
|
isJsonContentType,
|
||||||
|
readJsonWebhookBodyOrReject,
|
||||||
|
readWebhookBodyOrReject,
|
||||||
|
WEBHOOK_BODY_READ_DEFAULTS,
|
||||||
|
WEBHOOK_IN_FLIGHT_DEFAULTS,
|
||||||
|
type WebhookBodyReadProfile,
|
||||||
|
type WebhookInFlightLimiter,
|
||||||
|
} from "./webhook-request-guards.js";
|
||||||
|
export {
|
||||||
|
registerWebhookTarget,
|
||||||
|
registerWebhookTargetWithPluginRoute,
|
||||||
|
resolveSingleWebhookTarget,
|
||||||
|
resolveSingleWebhookTargetAsync,
|
||||||
|
resolveWebhookTargetWithAuthOrReject,
|
||||||
|
resolveWebhookTargetWithAuthOrRejectSync,
|
||||||
|
resolveWebhookTargets,
|
||||||
|
withResolvedWebhookRequestPipeline,
|
||||||
|
type RegisterWebhookPluginRouteOptions,
|
||||||
|
type RegisterWebhookTargetOptions,
|
||||||
|
type RegisteredWebhookTarget,
|
||||||
|
type WebhookTargetMatchResult,
|
||||||
|
} from "./webhook-targets.js";
|
||||||
|
export { normalizeWebhookPath, resolveWebhookPath } from "./webhook-path.js";
|
||||||
@ -34,9 +34,9 @@ export type {
|
|||||||
ChannelStatusIssue,
|
ChannelStatusIssue,
|
||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
|
||||||
export { logTypingFailure } from "../channels/logging.js";
|
export { logTypingFailure } from "../channels/logging.js";
|
||||||
export { createTypingCallbacks } from "../channels/typing.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
|
export { createTypingCallbacks } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export {
|
export {
|
||||||
resolveDefaultGroupPolicy,
|
resolveDefaultGroupPolicy,
|
||||||
@ -44,13 +44,13 @@ export {
|
|||||||
warnMissingProviderGroupPolicyFallbackOnce,
|
warnMissingProviderGroupPolicyFallbackOnce,
|
||||||
} from "../config/runtime-group-policy.js";
|
} from "../config/runtime-group-policy.js";
|
||||||
export type { GroupPolicy, MarkdownTableMode } from "../config/types.js";
|
export type { GroupPolicy, MarkdownTableMode } from "../config/types.js";
|
||||||
export type { SecretInput } from "../config/types.secrets.js";
|
export type { SecretInput } from "./secret-input.js";
|
||||||
export {
|
export {
|
||||||
|
buildSecretInputSchema,
|
||||||
hasConfiguredSecretInput,
|
hasConfiguredSecretInput,
|
||||||
normalizeResolvedSecretInputString,
|
normalizeResolvedSecretInputString,
|
||||||
normalizeSecretInputString,
|
normalizeSecretInputString,
|
||||||
} from "../config/types.secrets.js";
|
} from "./secret-input.js";
|
||||||
export { buildSecretInputSchema } from "./secret-input-schema.js";
|
|
||||||
export { MarkdownConfigSchema } from "../config/zod-schema.core.js";
|
export { MarkdownConfigSchema } from "../config/zod-schema.core.js";
|
||||||
export { waitForAbortSignal } from "../infra/abort-signal.js";
|
export { waitForAbortSignal } from "../infra/abort-signal.js";
|
||||||
export { createDedupeCache } from "../infra/dedupe.js";
|
export { createDedupeCache } from "../infra/dedupe.js";
|
||||||
@ -72,8 +72,7 @@ export { resolveChannelAccountConfigBasePath } from "./config-paths.js";
|
|||||||
export { evaluateSenderGroupAccess } from "./group-access.js";
|
export { evaluateSenderGroupAccess } from "./group-access.js";
|
||||||
export type { SenderGroupAccessDecision } from "./group-access.js";
|
export type { SenderGroupAccessDecision } from "./group-access.js";
|
||||||
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "./inbound-envelope.js";
|
export { resolveInboundRouteEnvelopeBuilderWithRuntime } from "./inbound-envelope.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
|
||||||
export { buildChannelSendResult } from "./channel-send-result.js";
|
export { buildChannelSendResult } from "./channel-send-result.js";
|
||||||
export type { OutboundReplyPayload } from "./reply-payload.js";
|
export type { OutboundReplyPayload } from "./reply-payload.js";
|
||||||
export {
|
export {
|
||||||
@ -90,25 +89,21 @@ export {
|
|||||||
export { chunkTextForOutbound } from "./text-chunking.js";
|
export { chunkTextForOutbound } from "./text-chunking.js";
|
||||||
export { extractToolSend } from "./tool-send.js";
|
export { extractToolSend } from "./tool-send.js";
|
||||||
export {
|
export {
|
||||||
|
applyBasicWebhookRequestGuards,
|
||||||
createFixedWindowRateLimiter,
|
createFixedWindowRateLimiter,
|
||||||
createWebhookAnomalyTracker,
|
createWebhookAnomalyTracker,
|
||||||
|
readJsonWebhookBodyOrReject,
|
||||||
|
registerWebhookTarget,
|
||||||
|
registerWebhookTargetWithPluginRoute,
|
||||||
|
resolveSingleWebhookTarget,
|
||||||
|
resolveWebhookPath,
|
||||||
|
resolveWebhookTargetWithAuthOrRejectSync,
|
||||||
|
resolveWebhookTargets,
|
||||||
WEBHOOK_ANOMALY_COUNTER_DEFAULTS,
|
WEBHOOK_ANOMALY_COUNTER_DEFAULTS,
|
||||||
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
WEBHOOK_RATE_LIMIT_DEFAULTS,
|
||||||
} from "./webhook-memory-guards.js";
|
withResolvedWebhookRequestPipeline,
|
||||||
export { resolveWebhookPath } from "./webhook-path.js";
|
} from "./webhook-ingress.js";
|
||||||
export {
|
|
||||||
applyBasicWebhookRequestGuards,
|
|
||||||
readJsonWebhookBodyOrReject,
|
|
||||||
} from "./webhook-request-guards.js";
|
|
||||||
export type {
|
export type {
|
||||||
RegisterWebhookPluginRouteOptions,
|
RegisterWebhookPluginRouteOptions,
|
||||||
RegisterWebhookTargetOptions,
|
RegisterWebhookTargetOptions,
|
||||||
} from "./webhook-targets.js";
|
} from "./webhook-ingress.js";
|
||||||
export {
|
|
||||||
registerWebhookTarget,
|
|
||||||
registerWebhookTargetWithPluginRoute,
|
|
||||||
resolveWebhookTargetWithAuthOrRejectSync,
|
|
||||||
resolveSingleWebhookTarget,
|
|
||||||
resolveWebhookTargets,
|
|
||||||
withResolvedWebhookRequestPipeline,
|
|
||||||
} from "./webhook-targets.js";
|
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
// Narrow plugin-sdk surface for the bundled zalouser plugin.
|
// Narrow plugin-sdk surface for the bundled zalouser plugin.
|
||||||
// Keep this list additive and scoped to symbols used under extensions/zalouser.
|
// Keep this list additive and scoped to symbols used under extensions/zalouser.
|
||||||
|
|
||||||
import {
|
import { createOptionalChannelSetupSurface } from "./channel-setup.js";
|
||||||
createOptionalChannelSetupAdapter,
|
|
||||||
createOptionalChannelSetupWizard,
|
|
||||||
} from "./optional-channel-setup.js";
|
|
||||||
|
|
||||||
export type { ReplyPayload } from "../auto-reply/types.js";
|
export type { ReplyPayload } from "../auto-reply/types.js";
|
||||||
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
|
export { mergeAllowlist, summarizeMapping } from "../channels/allowlists/resolve-utils.js";
|
||||||
@ -36,8 +33,8 @@ export type {
|
|||||||
ChannelStatusIssue,
|
ChannelStatusIssue,
|
||||||
} from "../channels/plugins/types.js";
|
} from "../channels/plugins/types.js";
|
||||||
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
export type { ChannelPlugin } from "../channels/plugins/types.plugin.js";
|
||||||
export { createReplyPrefixOptions } from "../channels/reply-prefix.js";
|
export { createChannelReplyPipeline, createReplyPrefixOptions } from "./channel-reply-pipeline.js";
|
||||||
export { createTypingCallbacks } from "../channels/typing.js";
|
export { createTypingCallbacks } from "./channel-reply-pipeline.js";
|
||||||
export type { OpenClawConfig } from "../config/config.js";
|
export type { OpenClawConfig } from "../config/config.js";
|
||||||
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
export { isDangerousNameMatchingEnabled } from "../config/dangerous-name-matching.js";
|
||||||
export {
|
export {
|
||||||
@ -63,8 +60,7 @@ export {
|
|||||||
resolveSenderScopedGroupPolicy,
|
resolveSenderScopedGroupPolicy,
|
||||||
} from "./group-access.js";
|
} from "./group-access.js";
|
||||||
export { loadOutboundMediaFromUrl } from "./outbound-media.js";
|
export { loadOutboundMediaFromUrl } from "./outbound-media.js";
|
||||||
export { createScopedPairingAccess } from "./pairing-access.js";
|
export { createChannelPairingController, createScopedPairingAccess } from "./channel-pairing.js";
|
||||||
export { issuePairingChallenge } from "../pairing/pairing-challenge.js";
|
|
||||||
export { buildChannelSendResult } from "./channel-send-result.js";
|
export { buildChannelSendResult } from "./channel-send-result.js";
|
||||||
export type { OutboundReplyPayload } from "./reply-payload.js";
|
export type { OutboundReplyPayload } from "./reply-payload.js";
|
||||||
export {
|
export {
|
||||||
@ -79,16 +75,12 @@ export { formatResolvedUnresolvedNote } from "./resolution-notes.js";
|
|||||||
export { buildBaseAccountStatusSnapshot } from "./status-helpers.js";
|
export { buildBaseAccountStatusSnapshot } from "./status-helpers.js";
|
||||||
export { chunkTextForOutbound } from "./text-chunking.js";
|
export { chunkTextForOutbound } from "./text-chunking.js";
|
||||||
|
|
||||||
export const zalouserSetupAdapter = createOptionalChannelSetupAdapter({
|
const zalouserSetup = createOptionalChannelSetupSurface({
|
||||||
channel: "zalouser",
|
channel: "zalouser",
|
||||||
label: "Zalo Personal",
|
label: "Zalo Personal",
|
||||||
npmSpec: "@openclaw/zalouser",
|
npmSpec: "@openclaw/zalouser",
|
||||||
docsPath: "/channels/zalouser",
|
docsPath: "/channels/zalouser",
|
||||||
});
|
});
|
||||||
|
|
||||||
export const zalouserSetupWizard = createOptionalChannelSetupWizard({
|
export const zalouserSetupAdapter = zalouserSetup.setupAdapter;
|
||||||
channel: "zalouser",
|
export const zalouserSetupWizard = zalouserSetup.setupWizard;
|
||||||
label: "Zalo Personal",
|
|
||||||
npmSpec: "@openclaw/zalouser",
|
|
||||||
docsPath: "/channels/zalouser",
|
|
||||||
});
|
|
||||||
|
|||||||
@ -18,6 +18,38 @@ function extractAgentDefaultModelFallbacks(model: unknown): string[] | undefined
|
|||||||
return Array.isArray(fallbacks) ? fallbacks.map((v) => String(v)) : undefined;
|
return Array.isArray(fallbacks) ? fallbacks.map((v) => String(v)) : undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type AgentModelAliasEntry =
|
||||||
|
| string
|
||||||
|
| {
|
||||||
|
modelRef: string;
|
||||||
|
alias?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function normalizeAgentModelAliasEntry(entry: AgentModelAliasEntry): {
|
||||||
|
modelRef: string;
|
||||||
|
alias?: string;
|
||||||
|
} {
|
||||||
|
if (typeof entry === "string") {
|
||||||
|
return { modelRef: entry };
|
||||||
|
}
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function withAgentModelAliases(
|
||||||
|
existing: Record<string, AgentModelEntryConfig> | undefined,
|
||||||
|
aliases: readonly AgentModelAliasEntry[],
|
||||||
|
): Record<string, AgentModelEntryConfig> {
|
||||||
|
const next = { ...existing };
|
||||||
|
for (const entry of aliases) {
|
||||||
|
const normalized = normalizeAgentModelAliasEntry(entry);
|
||||||
|
next[normalized.modelRef] = {
|
||||||
|
...next[normalized.modelRef],
|
||||||
|
...(normalized.alias ? { alias: next[normalized.modelRef]?.alias ?? normalized.alias } : {}),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
export function applyOnboardAuthAgentModelsAndProviders(
|
export function applyOnboardAuthAgentModelsAndProviders(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
params: {
|
params: {
|
||||||
@ -117,6 +149,56 @@ export function applyProviderConfigWithDefaultModel(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function applyProviderConfigWithDefaultModelPreset(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
params: {
|
||||||
|
providerId: string;
|
||||||
|
api: ModelApi;
|
||||||
|
baseUrl: string;
|
||||||
|
defaultModel: ModelDefinitionConfig;
|
||||||
|
defaultModelId?: string;
|
||||||
|
aliases?: readonly AgentModelAliasEntry[];
|
||||||
|
primaryModelRef?: string;
|
||||||
|
},
|
||||||
|
): OpenClawConfig {
|
||||||
|
const next = applyProviderConfigWithDefaultModel(cfg, {
|
||||||
|
agentModels: withAgentModelAliases(cfg.agents?.defaults?.models, params.aliases ?? []),
|
||||||
|
providerId: params.providerId,
|
||||||
|
api: params.api,
|
||||||
|
baseUrl: params.baseUrl,
|
||||||
|
defaultModel: params.defaultModel,
|
||||||
|
defaultModelId: params.defaultModelId,
|
||||||
|
});
|
||||||
|
return params.primaryModelRef
|
||||||
|
? applyAgentDefaultModelPrimary(next, params.primaryModelRef)
|
||||||
|
: next;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyProviderConfigWithDefaultModelsPreset(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
params: {
|
||||||
|
providerId: string;
|
||||||
|
api: ModelApi;
|
||||||
|
baseUrl: string;
|
||||||
|
defaultModels: ModelDefinitionConfig[];
|
||||||
|
defaultModelId?: string;
|
||||||
|
aliases?: readonly AgentModelAliasEntry[];
|
||||||
|
primaryModelRef?: string;
|
||||||
|
},
|
||||||
|
): OpenClawConfig {
|
||||||
|
const next = applyProviderConfigWithDefaultModels(cfg, {
|
||||||
|
agentModels: withAgentModelAliases(cfg.agents?.defaults?.models, params.aliases ?? []),
|
||||||
|
providerId: params.providerId,
|
||||||
|
api: params.api,
|
||||||
|
baseUrl: params.baseUrl,
|
||||||
|
defaultModels: params.defaultModels,
|
||||||
|
defaultModelId: params.defaultModelId,
|
||||||
|
});
|
||||||
|
return params.primaryModelRef
|
||||||
|
? applyAgentDefaultModelPrimary(next, params.primaryModelRef)
|
||||||
|
: next;
|
||||||
|
}
|
||||||
|
|
||||||
export function applyProviderConfigWithModelCatalog(
|
export function applyProviderConfigWithModelCatalog(
|
||||||
cfg: OpenClawConfig,
|
cfg: OpenClawConfig,
|
||||||
params: {
|
params: {
|
||||||
@ -149,6 +231,29 @@ export function applyProviderConfigWithModelCatalog(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function applyProviderConfigWithModelCatalogPreset(
|
||||||
|
cfg: OpenClawConfig,
|
||||||
|
params: {
|
||||||
|
providerId: string;
|
||||||
|
api: ModelApi;
|
||||||
|
baseUrl: string;
|
||||||
|
catalogModels: ModelDefinitionConfig[];
|
||||||
|
aliases?: readonly AgentModelAliasEntry[];
|
||||||
|
primaryModelRef?: string;
|
||||||
|
},
|
||||||
|
): OpenClawConfig {
|
||||||
|
const next = applyProviderConfigWithModelCatalog(cfg, {
|
||||||
|
agentModels: withAgentModelAliases(cfg.agents?.defaults?.models, params.aliases ?? []),
|
||||||
|
providerId: params.providerId,
|
||||||
|
api: params.api,
|
||||||
|
baseUrl: params.baseUrl,
|
||||||
|
catalogModels: params.catalogModels,
|
||||||
|
});
|
||||||
|
return params.primaryModelRef
|
||||||
|
? applyAgentDefaultModelPrimary(next, params.primaryModelRef)
|
||||||
|
: next;
|
||||||
|
}
|
||||||
|
|
||||||
type ProviderModelMergeState = {
|
type ProviderModelMergeState = {
|
||||||
providers: Record<string, ModelProviderConfig>;
|
providers: Record<string, ModelProviderConfig>;
|
||||||
existingProvider?: ModelProviderConfig;
|
existingProvider?: ModelProviderConfig;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user