mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-01 16:10:22 +00:00
feat: add configurable context visibility
This commit is contained in:
95
src/security/context-visibility.test.ts
Normal file
95
src/security/context-visibility.test.ts
Normal file
@@ -0,0 +1,95 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import {
|
||||
evaluateSupplementalContextVisibility,
|
||||
filterSupplementalContextItems,
|
||||
shouldIncludeSupplementalContext,
|
||||
} from "./context-visibility.js";
|
||||
|
||||
describe("evaluateSupplementalContextVisibility", () => {
|
||||
it("reports why all mode keeps context", () => {
|
||||
expect(
|
||||
evaluateSupplementalContextVisibility({
|
||||
mode: "all",
|
||||
kind: "history",
|
||||
senderAllowed: false,
|
||||
}),
|
||||
).toEqual({
|
||||
include: true,
|
||||
reason: "mode_all",
|
||||
});
|
||||
});
|
||||
|
||||
it("reports quote override decisions", () => {
|
||||
expect(
|
||||
evaluateSupplementalContextVisibility({
|
||||
mode: "allowlist_quote",
|
||||
kind: "quote",
|
||||
senderAllowed: false,
|
||||
}),
|
||||
).toEqual({
|
||||
include: true,
|
||||
reason: "quote_override",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("shouldIncludeSupplementalContext", () => {
|
||||
it("keeps all context in all mode", () => {
|
||||
expect(
|
||||
shouldIncludeSupplementalContext({
|
||||
mode: "all",
|
||||
kind: "history",
|
||||
senderAllowed: false,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("enforces allowlist mode for non-allowlisted senders", () => {
|
||||
expect(
|
||||
shouldIncludeSupplementalContext({
|
||||
mode: "allowlist",
|
||||
kind: "thread",
|
||||
senderAllowed: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it("keeps explicit quotes in allowlist_quote mode", () => {
|
||||
expect(
|
||||
shouldIncludeSupplementalContext({
|
||||
mode: "allowlist_quote",
|
||||
kind: "quote",
|
||||
senderAllowed: false,
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("still drops non-quote context in allowlist_quote mode", () => {
|
||||
expect(
|
||||
shouldIncludeSupplementalContext({
|
||||
mode: "allowlist_quote",
|
||||
kind: "history",
|
||||
senderAllowed: false,
|
||||
}),
|
||||
).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("filterSupplementalContextItems", () => {
|
||||
it("filters blocked items and reports omission count", () => {
|
||||
const result = filterSupplementalContextItems({
|
||||
items: [
|
||||
{ id: "allowed", senderAllowed: true },
|
||||
{ id: "blocked", senderAllowed: false },
|
||||
],
|
||||
mode: "allowlist",
|
||||
kind: "thread",
|
||||
isSenderAllowed: (item) => item.senderAllowed,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
items: [{ id: "allowed", senderAllowed: true }],
|
||||
omitted: 1,
|
||||
});
|
||||
});
|
||||
});
|
||||
58
src/security/context-visibility.ts
Normal file
58
src/security/context-visibility.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { ContextVisibilityMode } from "../config/types.base.js";
|
||||
|
||||
export type ContextVisibilityKind = "history" | "thread" | "quote" | "forwarded";
|
||||
|
||||
export type ContextVisibilityDecisionReason =
|
||||
| "mode_all"
|
||||
| "sender_allowed"
|
||||
| "quote_override"
|
||||
| "blocked";
|
||||
|
||||
export type ContextVisibilityDecision = {
|
||||
include: boolean;
|
||||
reason: ContextVisibilityDecisionReason;
|
||||
};
|
||||
|
||||
export function evaluateSupplementalContextVisibility(params: {
|
||||
mode: ContextVisibilityMode;
|
||||
kind: ContextVisibilityKind;
|
||||
senderAllowed: boolean;
|
||||
}): ContextVisibilityDecision {
|
||||
if (params.mode === "all") {
|
||||
return { include: true, reason: "mode_all" };
|
||||
}
|
||||
if (params.senderAllowed) {
|
||||
return { include: true, reason: "sender_allowed" };
|
||||
}
|
||||
if (params.mode === "allowlist_quote" && params.kind === "quote") {
|
||||
return { include: true, reason: "quote_override" };
|
||||
}
|
||||
return { include: false, reason: "blocked" };
|
||||
}
|
||||
|
||||
export function shouldIncludeSupplementalContext(params: {
|
||||
mode: ContextVisibilityMode;
|
||||
kind: ContextVisibilityKind;
|
||||
senderAllowed: boolean;
|
||||
}): boolean {
|
||||
return evaluateSupplementalContextVisibility(params).include;
|
||||
}
|
||||
|
||||
export function filterSupplementalContextItems<T>(params: {
|
||||
items: readonly T[];
|
||||
mode: ContextVisibilityMode;
|
||||
kind: ContextVisibilityKind;
|
||||
isSenderAllowed: (item: T) => boolean;
|
||||
}): { items: T[]; omitted: number } {
|
||||
const items = params.items.filter((item) =>
|
||||
shouldIncludeSupplementalContext({
|
||||
mode: params.mode,
|
||||
kind: params.kind,
|
||||
senderAllowed: params.isSenderAllowed(item),
|
||||
}),
|
||||
);
|
||||
return {
|
||||
items,
|
||||
omitted: params.items.length - items.length,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user