Compare commits
1 Commits
main
...
codex/fix-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3a2525be5f |
@ -74,7 +74,11 @@ import { subscribeEmbeddedPiSession } from "../../pi-embedded-subscribe.js";
|
||||
import { createPreparedEmbeddedPiSettingsManager } from "../../pi-project-settings.js";
|
||||
import { applyPiAutoCompactionGuard } from "../../pi-settings.js";
|
||||
import { toClientToolDefinitions } from "../../pi-tool-definition-adapter.js";
|
||||
import { createOpenClawCodingTools, resolveToolLoopDetectionConfig } from "../../pi-tools.js";
|
||||
import {
|
||||
applyOpenClawToolPolicies,
|
||||
createOpenClawCodingTools,
|
||||
resolveToolLoopDetectionConfig,
|
||||
} from "../../pi-tools.js";
|
||||
import { resolveSandboxContext } from "../../sandbox.js";
|
||||
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
||||
import { isXaiProvider } from "../../schema/clean-for-xai.js";
|
||||
@ -1559,10 +1563,30 @@ export async function runEmbeddedAttempt(
|
||||
],
|
||||
})
|
||||
: undefined;
|
||||
const effectiveTools =
|
||||
const effectiveToolsUnfiltered =
|
||||
bundleMcpRuntime && bundleMcpRuntime.tools.length > 0
|
||||
? [...tools, ...bundleMcpRuntime.tools]
|
||||
: tools;
|
||||
const effectiveTools = applyOpenClawToolPolicies({
|
||||
tools: effectiveToolsUnfiltered,
|
||||
config: params.config,
|
||||
sessionKey: sandboxSessionKey,
|
||||
agentId: sessionAgentId,
|
||||
modelProvider: params.model.provider,
|
||||
modelId: params.modelId,
|
||||
messageProvider: params.messageChannel ?? params.messageProvider,
|
||||
groupId: params.groupId,
|
||||
groupChannel: params.groupChannel,
|
||||
groupSpace: params.groupSpace,
|
||||
agentAccountId: params.agentAccountId,
|
||||
senderId: params.senderId,
|
||||
senderName: params.senderName,
|
||||
senderUsername: params.senderUsername,
|
||||
senderE164: params.senderE164,
|
||||
senderIsOwner: params.senderIsOwner,
|
||||
spawnedBy: params.spawnedBy,
|
||||
sandbox,
|
||||
});
|
||||
const allowedToolNames = collectAllowedToolNames({
|
||||
tools: effectiveTools,
|
||||
clientTools,
|
||||
|
||||
@ -3,6 +3,7 @@ import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/config.js";
|
||||
import { applyOpenClawToolPolicies } from "./pi-tools.js";
|
||||
import {
|
||||
filterToolsByPolicy,
|
||||
isToolAllowedByPolicyName,
|
||||
@ -35,6 +36,26 @@ describe("pi-tools.policy", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("applyOpenClawToolPolicies", () => {
|
||||
it("removes owner-only tools for non-owner senders", () => {
|
||||
const tools = [createStubTool("read"), { ...createStubTool("bundle_probe"), ownerOnly: true }];
|
||||
const filtered = applyOpenClawToolPolicies({ tools, senderIsOwner: false });
|
||||
expect(filtered.map((tool) => tool.name)).toEqual(["read"]);
|
||||
});
|
||||
|
||||
it("applies allow/deny policy to non-plugin tools", () => {
|
||||
const cfg = {
|
||||
tools: {
|
||||
allow: ["read"],
|
||||
deny: ["bundle_probe"],
|
||||
},
|
||||
} as unknown as OpenClawConfig;
|
||||
const tools = [createStubTool("read"), createStubTool("bundle_probe")];
|
||||
const filtered = applyOpenClawToolPolicies({ tools, config: cfg });
|
||||
expect(filtered.map((tool) => tool.name)).toEqual(["read"]);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resolveSubagentToolPolicy depth awareness", () => {
|
||||
const baseCfg = {
|
||||
agents: { defaults: { subagents: { maxSpawnDepth: 2 } } },
|
||||
|
||||
@ -195,6 +195,105 @@ export const __testing = {
|
||||
applyModelProviderToolPolicy,
|
||||
} as const;
|
||||
|
||||
export function applyOpenClawToolPolicies(params: {
|
||||
tools: AnyAgentTool[];
|
||||
config?: OpenClawConfig;
|
||||
sessionKey?: string;
|
||||
agentId?: string;
|
||||
modelProvider?: string;
|
||||
modelId?: string;
|
||||
messageProvider?: string;
|
||||
groupId?: string | null;
|
||||
groupChannel?: string | null;
|
||||
groupSpace?: string | null;
|
||||
agentAccountId?: string;
|
||||
senderId?: string | null;
|
||||
senderName?: string | null;
|
||||
senderUsername?: string | null;
|
||||
senderE164?: string | null;
|
||||
senderIsOwner?: boolean;
|
||||
spawnedBy?: string | null;
|
||||
sandbox?: SandboxContext | null;
|
||||
}): AnyAgentTool[] {
|
||||
const sandbox = params.sandbox?.enabled ? params.sandbox : undefined;
|
||||
const {
|
||||
agentId,
|
||||
globalPolicy,
|
||||
globalProviderPolicy,
|
||||
agentPolicy,
|
||||
agentProviderPolicy,
|
||||
profile,
|
||||
providerProfile,
|
||||
profileAlsoAllow,
|
||||
providerProfileAlsoAllow,
|
||||
} = resolveEffectiveToolPolicy({
|
||||
config: params.config,
|
||||
sessionKey: params.sessionKey,
|
||||
agentId: params.agentId,
|
||||
modelProvider: params.modelProvider,
|
||||
modelId: params.modelId,
|
||||
});
|
||||
const groupPolicy = resolveGroupToolPolicy({
|
||||
config: params.config,
|
||||
sessionKey: params.sessionKey,
|
||||
spawnedBy: params.spawnedBy,
|
||||
messageProvider: params.messageProvider,
|
||||
groupId: params.groupId,
|
||||
groupChannel: params.groupChannel,
|
||||
groupSpace: params.groupSpace,
|
||||
accountId: params.agentAccountId,
|
||||
senderId: params.senderId,
|
||||
senderName: params.senderName,
|
||||
senderUsername: params.senderUsername,
|
||||
senderE164: params.senderE164,
|
||||
});
|
||||
const profilePolicyWithAlsoAllow = mergeAlsoAllowPolicy(
|
||||
resolveToolProfilePolicy(profile),
|
||||
profileAlsoAllow,
|
||||
);
|
||||
const providerProfilePolicyWithAlsoAllow = mergeAlsoAllowPolicy(
|
||||
resolveToolProfilePolicy(providerProfile),
|
||||
providerProfileAlsoAllow,
|
||||
);
|
||||
const subagentPolicy =
|
||||
isSubagentSessionKey(params.sessionKey) && params.sessionKey
|
||||
? resolveSubagentToolPolicyForSession(params.config, params.sessionKey)
|
||||
: undefined;
|
||||
const toolsForMessageProvider = applyMessageProviderToolPolicy(
|
||||
params.tools,
|
||||
params.messageProvider,
|
||||
);
|
||||
const toolsForModelProvider = applyModelProviderToolPolicy(toolsForMessageProvider, {
|
||||
modelProvider: params.modelProvider,
|
||||
modelId: params.modelId,
|
||||
});
|
||||
const toolsByAuthorization = applyOwnerOnlyToolPolicy(
|
||||
toolsForModelProvider,
|
||||
params.senderIsOwner === true,
|
||||
);
|
||||
return applyToolPolicyPipeline({
|
||||
tools: toolsByAuthorization,
|
||||
toolMeta: (tool) => getPluginToolMeta(tool),
|
||||
warn: logWarn,
|
||||
steps: [
|
||||
...buildDefaultToolPolicyPipelineSteps({
|
||||
profilePolicy: profilePolicyWithAlsoAllow,
|
||||
profile,
|
||||
providerProfilePolicy: providerProfilePolicyWithAlsoAllow,
|
||||
providerProfile,
|
||||
globalPolicy,
|
||||
globalProviderPolicy,
|
||||
agentPolicy,
|
||||
agentProviderPolicy,
|
||||
groupPolicy,
|
||||
agentId,
|
||||
}),
|
||||
{ policy: sandbox?.tools, label: "sandbox tools.allow" },
|
||||
{ policy: subagentPolicy, label: "subagent tools.allow" },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export function createOpenClawCodingTools(options?: {
|
||||
agentId?: string;
|
||||
exec?: ExecToolDefaults & ProcessToolDefaults;
|
||||
@ -562,37 +661,25 @@ export function createOpenClawCodingTools(options?: {
|
||||
return [tool];
|
||||
})
|
||||
: tools;
|
||||
const toolsForMessageProvider = applyMessageProviderToolPolicy(
|
||||
toolsForMemoryFlush,
|
||||
options?.messageProvider,
|
||||
);
|
||||
const toolsForModelProvider = applyModelProviderToolPolicy(toolsForMessageProvider, {
|
||||
const subagentFiltered = applyOpenClawToolPolicies({
|
||||
tools: toolsForMemoryFlush,
|
||||
config: options?.config,
|
||||
sessionKey: options?.sessionKey,
|
||||
agentId: options?.agentId,
|
||||
modelProvider: options?.modelProvider,
|
||||
modelId: options?.modelId,
|
||||
});
|
||||
// Security: treat unknown/undefined as unauthorized (opt-in, not opt-out)
|
||||
const senderIsOwner = options?.senderIsOwner === true;
|
||||
const toolsByAuthorization = applyOwnerOnlyToolPolicy(toolsForModelProvider, senderIsOwner);
|
||||
const subagentFiltered = applyToolPolicyPipeline({
|
||||
tools: toolsByAuthorization,
|
||||
toolMeta: (tool) => getPluginToolMeta(tool),
|
||||
warn: logWarn,
|
||||
steps: [
|
||||
...buildDefaultToolPolicyPipelineSteps({
|
||||
profilePolicy: profilePolicyWithAlsoAllow,
|
||||
profile,
|
||||
providerProfilePolicy: providerProfilePolicyWithAlsoAllow,
|
||||
providerProfile,
|
||||
globalPolicy,
|
||||
globalProviderPolicy,
|
||||
agentPolicy,
|
||||
agentProviderPolicy,
|
||||
groupPolicy,
|
||||
agentId,
|
||||
}),
|
||||
{ policy: sandbox?.tools, label: "sandbox tools.allow" },
|
||||
{ policy: subagentPolicy, label: "subagent tools.allow" },
|
||||
],
|
||||
messageProvider: options?.messageProvider,
|
||||
groupId: options?.groupId,
|
||||
groupChannel: options?.groupChannel,
|
||||
groupSpace: options?.groupSpace,
|
||||
agentAccountId: options?.agentAccountId,
|
||||
senderId: options?.senderId,
|
||||
senderName: options?.senderName,
|
||||
senderUsername: options?.senderUsername,
|
||||
senderE164: options?.senderE164,
|
||||
senderIsOwner: options?.senderIsOwner,
|
||||
spawnedBy: options?.spawnedBy,
|
||||
sandbox,
|
||||
});
|
||||
// Always normalize tool JSON Schemas before handing them to pi-agent/pi-ai.
|
||||
// Without this, some providers (notably OpenAI) will reject root-level union schemas.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user