mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-04 08:30:25 +00:00
plugin-sdk: split command status surface
This commit is contained in:
committed by
Peter Steinberger
parent
691e2aa856
commit
aa15de8fdc
@@ -2,9 +2,13 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const loadConfigMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../config/config.js", () => ({
|
||||
loadConfig: loadConfigMock,
|
||||
}));
|
||||
vi.mock("../config/config.js", async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import("../config/config.js")>();
|
||||
return {
|
||||
...actual,
|
||||
loadConfig: loadConfigMock,
|
||||
};
|
||||
});
|
||||
|
||||
describe("agents/context eager warmup", () => {
|
||||
const originalArgv = process.argv.slice();
|
||||
@@ -27,4 +31,28 @@ describe("agents/context eager warmup", () => {
|
||||
|
||||
expect(loadConfigMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not eager-load config when onboard imports command-auth through plugin-sdk", async () => {
|
||||
process.argv = ["node", "openclaw", "onboard"];
|
||||
|
||||
await import("../plugin-sdk/command-auth.js");
|
||||
|
||||
expect(loadConfigMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not eager-load config when pairing approve imports command-auth through plugin-sdk", async () => {
|
||||
process.argv = ["node", "openclaw", "pairing", "approve", "feishu", "BAH8YVB3"];
|
||||
|
||||
await import("../plugin-sdk/command-auth.js");
|
||||
|
||||
expect(loadConfigMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not eager-load config when channels login imports command-auth through plugin-sdk", async () => {
|
||||
process.argv = ["node", "openclaw", "channels", "login", "--channel", "openclaw-weixin"];
|
||||
|
||||
await import("../plugin-sdk/command-auth.js");
|
||||
|
||||
expect(loadConfigMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -15,15 +15,12 @@ import {
|
||||
resolveReasoningDefault,
|
||||
resolveThinkingDefault,
|
||||
} from "../../agents/model-selection.js";
|
||||
import { resolveSessionParentSessionKey } from "../../channels/plugins/session-conversation.js";
|
||||
import type { OpenClawConfig } from "../../config/config.js";
|
||||
import type { SessionEntry } from "../../config/sessions/types.js";
|
||||
import { applyModelOverrideToSessionEntry } from "../../sessions/model-overrides.js";
|
||||
import {
|
||||
normalizeLowercaseStringOrEmpty,
|
||||
normalizeOptionalString,
|
||||
} from "../../shared/string-coerce.js";
|
||||
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
|
||||
import type { ThinkLevel } from "./directives.js";
|
||||
import { resolveStoredModelOverride } from "./stored-model-override.js";
|
||||
|
||||
export type ModelDirectiveSelection = {
|
||||
provider: string;
|
||||
@@ -142,61 +139,6 @@ function boundedLevenshteinDistance(a: string, b: string, maxDistance: number):
|
||||
return dist;
|
||||
}
|
||||
|
||||
export type StoredModelOverride = {
|
||||
provider?: string;
|
||||
model: string;
|
||||
source: "session" | "parent";
|
||||
};
|
||||
|
||||
function resolveParentSessionKeyCandidate(params: {
|
||||
sessionKey?: string;
|
||||
parentSessionKey?: string;
|
||||
}): string | null {
|
||||
const explicit = normalizeOptionalString(params.parentSessionKey);
|
||||
if (explicit && explicit !== params.sessionKey) {
|
||||
return explicit;
|
||||
}
|
||||
const derived = resolveSessionParentSessionKey(params.sessionKey);
|
||||
if (derived && derived !== params.sessionKey) {
|
||||
return derived;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resolveStoredModelOverride(params: {
|
||||
sessionEntry?: SessionEntry;
|
||||
sessionStore?: Record<string, SessionEntry>;
|
||||
sessionKey?: string;
|
||||
parentSessionKey?: string;
|
||||
defaultProvider: string;
|
||||
}): StoredModelOverride | null {
|
||||
const direct = resolvePersistedOverrideModelRef({
|
||||
defaultProvider: params.defaultProvider,
|
||||
overrideProvider: params.sessionEntry?.providerOverride,
|
||||
overrideModel: params.sessionEntry?.modelOverride,
|
||||
});
|
||||
if (direct) {
|
||||
return { ...direct, source: "session" };
|
||||
}
|
||||
const parentKey = resolveParentSessionKeyCandidate({
|
||||
sessionKey: params.sessionKey,
|
||||
parentSessionKey: params.parentSessionKey,
|
||||
});
|
||||
if (!parentKey || !params.sessionStore) {
|
||||
return null;
|
||||
}
|
||||
const parentEntry = params.sessionStore[parentKey];
|
||||
const parentOverride = resolvePersistedOverrideModelRef({
|
||||
defaultProvider: params.defaultProvider,
|
||||
overrideProvider: parentEntry?.providerOverride,
|
||||
overrideModel: parentEntry?.modelOverride,
|
||||
});
|
||||
if (!parentOverride) {
|
||||
return null;
|
||||
}
|
||||
return { ...parentOverride, source: "parent" };
|
||||
}
|
||||
|
||||
function scoreFuzzyMatch(params: {
|
||||
provider: string;
|
||||
model: string;
|
||||
|
||||
59
src/auto-reply/reply/stored-model-override.ts
Normal file
59
src/auto-reply/reply/stored-model-override.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
import { resolvePersistedOverrideModelRef } from "../../agents/model-selection.js";
|
||||
import { resolveSessionParentSessionKey } from "../../channels/plugins/session-conversation.js";
|
||||
import type { SessionEntry } from "../../config/sessions/types.js";
|
||||
import { normalizeOptionalString } from "../../shared/string-coerce.js";
|
||||
|
||||
export type StoredModelOverride = {
|
||||
provider?: string;
|
||||
model: string;
|
||||
source: "session" | "parent";
|
||||
};
|
||||
|
||||
function resolveParentSessionKeyCandidate(params: {
|
||||
sessionKey?: string;
|
||||
parentSessionKey?: string;
|
||||
}): string | null {
|
||||
const explicit = normalizeOptionalString(params.parentSessionKey);
|
||||
if (explicit && explicit !== params.sessionKey) {
|
||||
return explicit;
|
||||
}
|
||||
const derived = resolveSessionParentSessionKey(params.sessionKey);
|
||||
if (derived && derived !== params.sessionKey) {
|
||||
return derived;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
export function resolveStoredModelOverride(params: {
|
||||
sessionEntry?: SessionEntry;
|
||||
sessionStore?: Record<string, SessionEntry>;
|
||||
sessionKey?: string;
|
||||
parentSessionKey?: string;
|
||||
defaultProvider: string;
|
||||
}): StoredModelOverride | null {
|
||||
const direct = resolvePersistedOverrideModelRef({
|
||||
defaultProvider: params.defaultProvider,
|
||||
overrideProvider: params.sessionEntry?.providerOverride,
|
||||
overrideModel: params.sessionEntry?.modelOverride,
|
||||
});
|
||||
if (direct) {
|
||||
return { ...direct, source: "session" };
|
||||
}
|
||||
const parentKey = resolveParentSessionKeyCandidate({
|
||||
sessionKey: params.sessionKey,
|
||||
parentSessionKey: params.parentSessionKey,
|
||||
});
|
||||
if (!parentKey || !params.sessionStore) {
|
||||
return null;
|
||||
}
|
||||
const parentEntry = params.sessionStore[parentKey];
|
||||
const parentOverride = resolvePersistedOverrideModelRef({
|
||||
defaultProvider: params.defaultProvider,
|
||||
overrideProvider: parentEntry?.providerOverride,
|
||||
overrideModel: parentEntry?.modelOverride,
|
||||
});
|
||||
if (!parentOverride) {
|
||||
return null;
|
||||
}
|
||||
return { ...parentOverride, source: "parent" };
|
||||
}
|
||||
@@ -78,13 +78,8 @@ export {
|
||||
resolveModelsCommandReply,
|
||||
} from "../auto-reply/reply/commands-models.js";
|
||||
export type { ModelsProviderData } from "../auto-reply/reply/commands-models.js";
|
||||
export { resolveStoredModelOverride } from "../auto-reply/reply/model-selection.js";
|
||||
export type { StoredModelOverride } from "../auto-reply/reply/model-selection.js";
|
||||
export {
|
||||
buildCommandsMessage,
|
||||
buildCommandsMessagePaginated,
|
||||
buildHelpMessage,
|
||||
} from "../auto-reply/status.js";
|
||||
export { resolveStoredModelOverride } from "../auto-reply/reply/stored-model-override.js";
|
||||
export type { StoredModelOverride } from "../auto-reply/reply/stored-model-override.js";
|
||||
|
||||
export type ResolveSenderCommandAuthorizationParams = {
|
||||
cfg: OpenClawConfig;
|
||||
|
||||
5
src/plugin-sdk/command-status.ts
Normal file
5
src/plugin-sdk/command-status.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export {
|
||||
buildCommandsMessage,
|
||||
buildCommandsMessagePaginated,
|
||||
buildHelpMessage,
|
||||
} from "../auto-reply/status.js";
|
||||
@@ -20,7 +20,7 @@ export {
|
||||
buildModelsProviderData,
|
||||
type ModelsProviderData,
|
||||
} from "../auto-reply/reply/commands-models.js";
|
||||
export { resolveStoredModelOverride } from "../auto-reply/reply/model-selection.js";
|
||||
export { resolveStoredModelOverride } from "../auto-reply/reply/stored-model-override.js";
|
||||
export {
|
||||
deleteAccountFromConfigSection,
|
||||
setAccountEnabledInConfigSection,
|
||||
|
||||
@@ -706,6 +706,14 @@ describe("plugin-sdk subpath exports", () => {
|
||||
"shouldComputeCommandAuthorized",
|
||||
"shouldHandleTextCommands",
|
||||
]);
|
||||
expectSourceContract("command-auth", {
|
||||
omits: ["buildCommandsMessage", "buildCommandsMessagePaginated", "buildHelpMessage"],
|
||||
});
|
||||
expectSourceMentions("command-status", [
|
||||
"buildCommandsMessage",
|
||||
"buildCommandsMessagePaginated",
|
||||
"buildHelpMessage",
|
||||
]);
|
||||
expectSourceOmitsSnippet("command-auth", "../../extensions/");
|
||||
expectSourceOmitsSnippet("matrix-runtime-heavy", "../../extensions/");
|
||||
expectSourceMentions("channel-send-result", [
|
||||
|
||||
Reference in New Issue
Block a user