Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
019ea07
init attempt on guardrail interface
Reapor-Yurnero Feb 1, 2026
1ae9c11
fix some typing errors
Reapor-Yurnero Feb 1, 2026
4a6da7a
fix bug that would hang on pre request violation indefinitely
Reapor-Yurnero Feb 1, 2026
84055e5
fix web browser not seeing blocked message bug
Reapor-Yurnero Feb 1, 2026
6b0d748
fix an error from the previous fix
Reapor-Yurnero Feb 1, 2026
6d7f989
add some doc
Reapor-Yurnero Feb 1, 2026
85ab3a2
refactor: migrate guardrails to plugin hook system
Scrattlebeard Feb 1, 2026
5c74c85
Add LlamaGuard and gpt-oss-safeguard plugins. Remove guardrails confi…
Scrattlebeard Feb 1, 2026
7ff2716
refactor: add createGuardrailPlugin factory for unified guardrail API
Scrattlebeard Feb 1, 2026
965dbc0
feat: add command-safety-guard and security-audit plugins
Scrattlebeard Feb 1, 2026
fd6b621
Plugins: fix guardrail hook sequencing and short circuiting
Reapor-Yurnero Feb 2, 2026
e2fd8a1
change plugin naming to follow conventions
Reapor-Yurnero Feb 2, 2026
efc7065
remove redundant config enabled key
Reapor-Yurnero Feb 2, 2026
f646657
revert some unnecesary validation after moving to plugins
Reapor-Yurnero Feb 2, 2026
d1e1e31
remove redundant config.enable schema
Reapor-Yurnero Feb 2, 2026
6b5719b
Guardrails: GPT-OSS safeguard defaults and append mode
Reapor-Yurnero Feb 2, 2026
ce2a526
remove llama guard for the moment
Reapor-Yurnero Feb 2, 2026
211dde8
Guardrails: skip hooks for internal runs
Reapor-Yurnero Feb 2, 2026
c2bdd7d
polish the doc
Reapor-Yurnero Feb 2, 2026
1bb5876
Guardrails: add priority and attribution
Reapor-Yurnero Feb 2, 2026
a646c9a
Enhance command-safety-guard and security-audit plugins with UI hints…
Scrattlebeard Feb 2, 2026
70edfa0
Merge branch 'feat/guardrail_interface' into bugfix/command-safety-an…
Scrattlebeard Feb 2, 2026
87c6051
Fix implementations to use the correct tool names.
Scrattlebeard Feb 2, 2026
664fdcc
Merge pull request #5 from grayswansecurity/bugfix/fix-tool-names-in-…
Scrattlebeard Feb 2, 2026
a8f0f7c
Merge upstream/main
Reapor-Yurnero Feb 2, 2026
d020951
fix pnpm lint & pnpm build errors
Reapor-Yurnero Feb 2, 2026
43f4fc2
Merge grayswansecurity/openclaw#2
Reapor-Yurnero Feb 2, 2026
6b7c542
add readme for cygnal and gpt-oss-safeguard extensions
Reapor-Yurnero Feb 2, 2026
0e9293b
update doc about restart option
Reapor-Yurnero Feb 2, 2026
3b1e194
fix a typo introduced in command-safety-guard
Reapor-Yurnero Feb 2, 2026
e37120d
Add OpenClaw-specific API link
nwinter Feb 3, 2026
020918e
Update pnpm-lock.yaml for command-safety-guard extension
nwinter Feb 3, 2026
8dc07d2
Format extension files and escape pipe in fork-bomb pattern
nwinter Feb 3, 2026
de84696
Update test to match hook contract requiring toolCallId and messages
nwinter Feb 3, 2026
ed99104
Fix tests: use lowercase tool names and updated DEFAULT_POLICY content
nwinter Feb 3, 2026
aae4098
Skip path tests on Windows (plugin only supports Unix paths)
nwinter Feb 3, 2026
df0ffd9
address greptile comments
Reapor-Yurnero Feb 3, 2026
87e03a9
address false positves in security-audit extension for redirection
Reapor-Yurnero Feb 3, 2026
0b6d963
fix formatting issue in previous commit
Reapor-Yurnero Feb 3, 2026
495f859
address dropped tool return metadata on block
Reapor-Yurnero Feb 3, 2026
d4bea63
address more comments
Reapor-Yurnero Feb 3, 2026
51fcebe
fix type error
Reapor-Yurnero Feb 3, 2026
f1aac5f
Merge upstream/main
Reapor-Yurnero Feb 9, 2026
0a3e77d
Merge upstream/main
Reapor-Yurnero Feb 12, 2026
1141b52
Merge remote-tracking branch 'upstream/main' into feat/guardrail_inte…
Reapor-Yurnero Feb 14, 2026
8c94a4a
Merge remote-tracking branch 'upstream/main' into feat/guardrail_inte…
Reapor-Yurnero Feb 14, 2026
a5c1013
test(memory): stabilize qmd-manager wait
Reapor-Yurnero Feb 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Guardrails: skip hooks for internal runs
  • Loading branch information
Reapor-Yurnero committed Feb 2, 2026
commit 211dde8515c05d3ee9b4fc595ae7ce018f163546
4 changes: 2 additions & 2 deletions extensions/gpt-oss-safeguard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ import {
type OpenClawPluginApi,
cleanupTempDir,
collectText,
createGuardrailRunId,
createGuardrailPlugin,
createGuardrailTempDir,
extractMessagesContent,
generateSessionId,
loadRunEmbeddedPiAgent,
} from "openclaw/plugin-sdk";

Expand Down Expand Up @@ -185,7 +185,7 @@ async function callSafeguard(params: {
let tmpDir: string | null = null;
try {
tmpDir = await createGuardrailTempDir("safeguard");
const sessionId = generateSessionId("safeguard");
const sessionId = createGuardrailRunId("gpt-oss-safeguard");
const sessionFile = path.join(tmpDir, "session.json");

const runEmbeddedPiAgent = await loadRunEmbeddedPiAgent();
Expand Down
5 changes: 4 additions & 1 deletion src/agents/pi-embedded-runner/run/attempt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
import { buildTtsSystemPromptHint } from "../../../tts/tts.js";
import { isTimeoutError } from "../../failover-error.js";
import { getGlobalHookRunner } from "../../../plugins/hook-runner-global.js";
import { isGuardrailRunId } from "../../../plugins/guardrails-utils.js";
import { MAX_IMAGE_BYTES } from "../../../media/constants.js";
import type { ToolHookContext } from "../../pi-tool-definition-adapter.js";

Expand Down Expand Up @@ -734,7 +735,9 @@ export async function runEmbeddedAttempt(
}

// Get hook runner once for both before_agent_start and agent_end hooks
const hookRunner = getGlobalHookRunner();
const skipGuardrailHooks =
isGuardrailRunId(params.sessionId) || isGuardrailRunId(params.runId);
const hookRunner = skipGuardrailHooks ? null : getGlobalHookRunner();

let promptError: unknown = null;
try {
Expand Down
2 changes: 2 additions & 0 deletions src/plugin-sdk/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,13 +133,15 @@ export {
buildToolCallSummary,
cleanupTempDir,
collectText,
createGuardrailRunId,
createGuardrailPlugin,
createGuardrailTempDir,
extractMessagesContent,
extractTextFromContent,
extractToolResultText,
generateSessionId,
isStageEnabled,
isGuardrailRunId,
loadRunEmbeddedPiAgent,
resolveBlockMode,
resolveStageConfig,
Expand Down
15 changes: 15 additions & 0 deletions src/plugins/guardrails-utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import { describe, expect, it } from "vitest";
import {
appendWarningToToolResult,
buildToolCallSummary,
createGuardrailRunId,
extractMessagesContent,
extractTextFromContent,
extractToolResultText,
generateSessionId,
isGuardrailRunId,
isStageEnabled,
replaceToolResultWithWarning,
resolveBlockMode,
Expand Down Expand Up @@ -154,6 +156,19 @@ describe("replaceToolResultWithWarning", () => {
});
});

describe("guardrail run id helpers", () => {
it("creates guardrail run ids with the expected prefix", () => {
const runId = createGuardrailRunId("gpt-oss-safeguard");
expect(runId.startsWith("guardrail:")).toBe(true);
expect(isGuardrailRunId(runId)).toBe(true);
});

it("returns false for non-guardrail ids", () => {
expect(isGuardrailRunId("session-123")).toBe(false);
expect(isGuardrailRunId(undefined)).toBe(false);
});
});

describe("buildToolCallSummary", () => {
it("builds JSON summary of tool call", () => {
const summary = buildToolCallSummary("readFile", "call-123", { path: "/test.txt" });
Expand Down
20 changes: 20 additions & 0 deletions src/plugins/guardrails-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,26 @@ export function generateSessionId(prefix: string): string {
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}

const GUARDRAIL_RUN_ID_PREFIX = "guardrail:";

/**
* Generate a unique run/session ID for guardrail-internal model calls.
*/
export function createGuardrailRunId(guardrailId: string): string {
const safeId = guardrailId.trim() || "unknown";
return `${GUARDRAIL_RUN_ID_PREFIX}${generateSessionId(safeId)}`;
}

/**
* Check if a run/session ID belongs to a guardrail-internal call.
*/
export function isGuardrailRunId(id?: string | null): boolean {
if (!id) {
return false;
}
return id.startsWith(GUARDRAIL_RUN_ID_PREFIX);
}

// ============================================================================
// JSON Utilities
// ============================================================================
Expand Down