mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 06:30:42 +00:00
fix(tools): allow no-tool llm-task runs
This commit is contained in:
@@ -118,6 +118,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Active Memory: preserve the target agent context when building embedded recall plugin tools so `memory_search` and `memory_get` stay available for explicit recall sessions. Fixes #76343. Thanks @Countermarch.
|
||||
- Plugins/externalization: repair missing configured plugin installs from npm by default, reserve ClawHub downloads for explicit `clawhubSpec` metadata, and cover agent-runtime/env-selected plugin repair. Thanks @vincentkoc.
|
||||
- Plugins/install: allow official catalog-matched npm channel plugins such as Feishu to pass the trusted install scanner path while keeping spoofed package names blocked. Thanks @vincentkoc.
|
||||
- Tools/llm-task: keep JSON-only embedded model runs from tripping inherited tool allowlists when tools are intentionally disabled, while preserving runtime `toolsAllow` failures. Fixes #74019. Thanks @amknight.
|
||||
- Tools/profiles: make `tools.profile: "full"` grant all tools including optional plugin tools such as browser, so the full profile no longer silently drops plugin-provided tools that require an explicit allowlist entry. Fixes #76507. Thanks @amknight.
|
||||
- Feishu: keep timeout env parsing separate from the HTTP client wrapper so package security scans no longer report a false env-harvesting hit during install. Thanks @vincentkoc.
|
||||
- Upgrade/config: validate configured web-search providers and statically suppressed model/provider pairs against the active plugin set at config load, so stale plugin state fails loud before runtime fallback.
|
||||
|
||||
@@ -697,7 +697,7 @@ function collectAttemptExplicitToolAllowlistSources(params: {
|
||||
{ label: "group tools.allow", allow: groupPolicy?.allow },
|
||||
{ label: "sandbox tools.allow", allow: params.sandboxToolPolicy?.allow },
|
||||
{ label: "subagent tools.allow", allow: subagentPolicy?.allow },
|
||||
{ label: "runtime toolsAllow", allow: params.toolsAllow },
|
||||
{ label: "runtime toolsAllow", allow: params.toolsAllow, enforceWhenToolsDisabled: true },
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,9 @@ describe("tool allowlist guard", () => {
|
||||
|
||||
it("fails closed for runtime toolsAllow when tools are disabled", () => {
|
||||
const error = buildEmptyExplicitToolAllowlistError({
|
||||
sources: [{ label: "runtime toolsAllow", entries: ["query_db"] }],
|
||||
sources: [
|
||||
{ label: "runtime toolsAllow", entries: ["query_db"], enforceWhenToolsDisabled: true },
|
||||
],
|
||||
callableToolNames: [],
|
||||
toolsEnabled: true,
|
||||
disableTools: true,
|
||||
@@ -29,6 +31,17 @@ describe("tool allowlist guard", () => {
|
||||
expect(error?.message).toContain("tools are disabled for this run");
|
||||
});
|
||||
|
||||
it("allows inherited config allowlists when a run intentionally disables tools", () => {
|
||||
expect(
|
||||
buildEmptyExplicitToolAllowlistError({
|
||||
sources: [{ label: "tools.allow", entries: ["lobster", "llm-task"] }],
|
||||
callableToolNames: [],
|
||||
toolsEnabled: true,
|
||||
disableTools: true,
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("fails closed when the selected model cannot use requested tools", () => {
|
||||
const error = buildEmptyExplicitToolAllowlistError({
|
||||
sources: [{ label: "agents.db.tools.allow", entries: ["query_db"] }],
|
||||
@@ -63,13 +76,21 @@ describe("tool allowlist guard", () => {
|
||||
it("keeps source labels for config and runtime allowlists", () => {
|
||||
const sources = collectExplicitToolAllowlistSources([
|
||||
{ label: "tools.allow", allow: [" read ", ""] },
|
||||
{ label: "runtime toolsAllow", allow: ["query_db"] },
|
||||
{
|
||||
label: "runtime toolsAllow",
|
||||
allow: ["query_db"],
|
||||
enforceWhenToolsDisabled: true,
|
||||
},
|
||||
{ label: "tools.byProvider.allow" },
|
||||
]);
|
||||
|
||||
expect(sources).toEqual([
|
||||
{ label: "tools.allow", entries: ["read"] },
|
||||
{ label: "runtime toolsAllow", entries: ["query_db"] },
|
||||
{
|
||||
label: "runtime toolsAllow",
|
||||
entries: ["query_db"],
|
||||
enforceWhenToolsDisabled: true,
|
||||
},
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -3,14 +3,24 @@ import { normalizeToolName } from "./tool-policy.js";
|
||||
type ExplicitToolAllowlistSource = {
|
||||
label: string;
|
||||
entries: string[];
|
||||
enforceWhenToolsDisabled?: boolean;
|
||||
};
|
||||
|
||||
export function collectExplicitToolAllowlistSources(
|
||||
sources: Array<{ label: string; allow?: string[] }>,
|
||||
sources: Array<{ label: string; allow?: string[]; enforceWhenToolsDisabled?: boolean }>,
|
||||
): ExplicitToolAllowlistSource[] {
|
||||
return sources.flatMap((source) => {
|
||||
const entries = (source.allow ?? []).map((entry) => entry.trim()).filter(Boolean);
|
||||
return entries.length ? [{ label: source.label, entries }] : [];
|
||||
if (entries.length === 0) {
|
||||
return [];
|
||||
}
|
||||
return [
|
||||
{
|
||||
label: source.label,
|
||||
entries,
|
||||
...(source.enforceWhenToolsDisabled === true ? { enforceWhenToolsDisabled: true } : {}),
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
|
||||
@@ -20,11 +30,15 @@ export function buildEmptyExplicitToolAllowlistError(params: {
|
||||
toolsEnabled: boolean;
|
||||
disableTools?: boolean;
|
||||
}): Error | null {
|
||||
const sources =
|
||||
params.disableTools === true
|
||||
? params.sources.filter((source) => source.enforceWhenToolsDisabled === true)
|
||||
: params.sources;
|
||||
const callableToolNames = params.callableToolNames.map(normalizeToolName).filter(Boolean);
|
||||
if (params.sources.length === 0 || callableToolNames.length > 0) {
|
||||
if (sources.length === 0 || callableToolNames.length > 0) {
|
||||
return null;
|
||||
}
|
||||
const requested = params.sources
|
||||
const requested = sources
|
||||
.map((source) => `${source.label}: ${source.entries.map(normalizeToolName).join(", ")}`)
|
||||
.join("; ");
|
||||
const reason =
|
||||
|
||||
Reference in New Issue
Block a user