mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-05-01 06:36:23 +08:00
fix: support explicit active-memory chat types (openclaw#66285)
Verified: - pnpm install --frozen-lockfile - pnpm test extensions/active-memory/config.test.ts extensions/active-memory/index.test.ts - pnpm exec oxfmt --check --threads=1 CHANGELOG.md extensions/active-memory/index.ts extensions/active-memory/index.test.ts extensions/active-memory/config.test.ts extensions/active-memory/openclaw.plugin.json - git diff --check Co-authored-by: Lidang-Jiang <119769478+Lidang-Jiang@users.noreply.github.com> Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
@@ -11,6 +11,7 @@ Docs: https://docs.openclaw.ai
|
||||
|
||||
### Fixes
|
||||
|
||||
- Active Memory: allow `allowedChatTypes` to include explicit portal/webchat sessions and classify `agent:...:explicit:...` session keys before opaque session ids can shadow the chat type. Fixes #65775. (#66285) Thanks @Lidang-Jiang.
|
||||
- fix(device-pairing): validate callerScopes against resolved token scopes on repair [AI]. (#72925) Thanks @pgondhi987.
|
||||
- Active Memory docs: document the `cacheTtlMs` 1000-120000 ms range and 15000 ms default so setup snippets do not lead users past the schema limit. Fixes #65708. (#65737) Thanks @WuKongAI-CMU.
|
||||
- fix(agents): canonicalize provider aliases in byProvider tool policy lookup [AI]. (#72917) Thanks @pgondhi987.
|
||||
|
||||
@@ -36,6 +36,20 @@ describe("active-memory manifest config schema", () => {
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("accepts explicit in allowedChatTypes", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
cacheKey: "active-memory.manifest.allowed-chat-types.explicit",
|
||||
value: {
|
||||
enabled: true,
|
||||
agents: ["main"],
|
||||
allowedChatTypes: ["direct", "explicit"],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(true);
|
||||
});
|
||||
|
||||
it("rejects timeoutMs values above the runtime ceiling", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
@@ -49,4 +63,18 @@ describe("active-memory manifest config schema", () => {
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
});
|
||||
|
||||
it("rejects unknown allowedChatTypes values", () => {
|
||||
const result = validateJsonSchemaValue({
|
||||
schema: manifest.configSchema,
|
||||
cacheKey: "active-memory.manifest.allowed-chat-types.invalid",
|
||||
value: {
|
||||
enabled: true,
|
||||
agents: ["main"],
|
||||
allowedChatTypes: ["direct", "portal"],
|
||||
},
|
||||
});
|
||||
|
||||
expect(result.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -548,6 +548,54 @@ describe("active-memory plugin", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("runs for explicit sessions when explicit chat types are explicitly allowed", async () => {
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
allowedChatTypes: ["explicit"],
|
||||
};
|
||||
await plugin.register(api as unknown as OpenClawPluginApi);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what should i work on next?", messages: [] },
|
||||
{
|
||||
agentId: "main",
|
||||
trigger: "user",
|
||||
sessionKey: "agent:main:explicit:portal-123",
|
||||
messageProvider: "webchat",
|
||||
channelId: "webchat",
|
||||
},
|
||||
);
|
||||
|
||||
expect(runEmbeddedPiAgent).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual({
|
||||
prependContext: expect.stringContaining("<active_memory_plugin>"),
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps explicit session classification when the opaque session id contains chat-type tokens", async () => {
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
allowedChatTypes: ["explicit"],
|
||||
};
|
||||
await plugin.register(api as unknown as OpenClawPluginApi);
|
||||
|
||||
const result = await hooks.before_prompt_build(
|
||||
{ prompt: "what should i work on next?", messages: [] },
|
||||
{
|
||||
agentId: "main",
|
||||
trigger: "user",
|
||||
sessionKey: "agent:main:explicit:portal-123:group:shadow",
|
||||
messageProvider: "webchat",
|
||||
channelId: "webchat",
|
||||
},
|
||||
);
|
||||
|
||||
expect(runEmbeddedPiAgent).toHaveBeenCalledTimes(1);
|
||||
expect(result).toEqual({
|
||||
prependContext: expect.stringContaining("<active_memory_plugin>"),
|
||||
});
|
||||
});
|
||||
|
||||
it("skips group sessions whose conversation id is not in allowedChatIds", async () => {
|
||||
api.pluginConfig = {
|
||||
agents: ["main"],
|
||||
|
||||
@@ -68,7 +68,7 @@ type ActiveRecallPluginConfig = {
|
||||
model?: string;
|
||||
modelFallback?: string;
|
||||
modelFallbackPolicy?: "default-remote" | "resolved-only";
|
||||
allowedChatTypes?: Array<"direct" | "group" | "channel">;
|
||||
allowedChatTypes?: Array<"direct" | "group" | "channel" | "explicit">;
|
||||
allowedChatIds?: string[];
|
||||
deniedChatIds?: string[];
|
||||
thinking?: ActiveMemoryThinkingLevel;
|
||||
@@ -105,7 +105,7 @@ type ResolvedActiveRecallPluginConfig = {
|
||||
model?: string;
|
||||
modelFallback?: string;
|
||||
modelFallbackPolicy: "default-remote" | "resolved-only";
|
||||
allowedChatTypes: Array<"direct" | "group" | "channel">;
|
||||
allowedChatTypes: Array<"direct" | "group" | "channel" | "explicit">;
|
||||
allowedChatIds: string[];
|
||||
deniedChatIds: string[];
|
||||
thinking: ActiveMemoryThinkingLevel;
|
||||
@@ -176,7 +176,7 @@ type CachedActiveRecallResult = {
|
||||
result: ActiveRecallResult;
|
||||
};
|
||||
|
||||
type ActiveMemoryChatType = "direct" | "group" | "channel";
|
||||
type ActiveMemoryChatType = "direct" | "group" | "channel" | "explicit";
|
||||
|
||||
type ActiveMemoryToggleStore = {
|
||||
sessions?: Record<string, { disabled?: boolean; updatedAt?: number }>;
|
||||
@@ -643,7 +643,7 @@ function normalizePluginConfig(pluginConfig: unknown): ResolvedActiveRecallPlugi
|
||||
const allowedChatTypes = Array.isArray(raw.allowedChatTypes)
|
||||
? raw.allowedChatTypes.filter(
|
||||
(value): value is ActiveMemoryChatType =>
|
||||
value === "direct" || value === "group" || value === "channel",
|
||||
value === "direct" || value === "group" || value === "channel" || value === "explicit",
|
||||
)
|
||||
: [];
|
||||
return {
|
||||
@@ -913,6 +913,9 @@ function resolveChatType(ctx: {
|
||||
}): ActiveMemoryChatType | undefined {
|
||||
const sessionKey = ctx.sessionKey?.trim().toLowerCase();
|
||||
if (sessionKey) {
|
||||
if (sessionKey.startsWith("agent:") && sessionKey.split(":")[2] === "explicit") {
|
||||
return "explicit";
|
||||
}
|
||||
if (sessionKey.includes(":group:")) {
|
||||
return "group";
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["direct", "group", "channel"]
|
||||
"enum": ["direct", "group", "channel", "explicit"]
|
||||
}
|
||||
},
|
||||
"allowedChatIds": {
|
||||
@@ -101,7 +101,7 @@
|
||||
},
|
||||
"allowedChatTypes": {
|
||||
"label": "Allowed Chat Types",
|
||||
"help": "Choose which session types may run Active Memory. Defaults to direct-message style sessions only."
|
||||
"help": "Choose which session types may run Active Memory. Defaults to direct-message style sessions only, but explicit portal/webchat sessions can also be enabled."
|
||||
},
|
||||
"allowedChatIds": {
|
||||
"label": "Allowed Chat IDs",
|
||||
|
||||
Reference in New Issue
Block a user