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 { createPreparedEmbeddedPiSettingsManager } from "../../pi-project-settings.js";
|
||||||
import { applyPiAutoCompactionGuard } from "../../pi-settings.js";
|
import { applyPiAutoCompactionGuard } from "../../pi-settings.js";
|
||||||
import { toClientToolDefinitions } from "../../pi-tool-definition-adapter.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 { resolveSandboxContext } from "../../sandbox.js";
|
||||||
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
import { resolveSandboxRuntimeStatus } from "../../sandbox/runtime-status.js";
|
||||||
import { isXaiProvider } from "../../schema/clean-for-xai.js";
|
import { isXaiProvider } from "../../schema/clean-for-xai.js";
|
||||||
@ -1559,10 +1563,30 @@ export async function runEmbeddedAttempt(
|
|||||||
],
|
],
|
||||||
})
|
})
|
||||||
: undefined;
|
: undefined;
|
||||||
const effectiveTools =
|
const effectiveToolsUnfiltered =
|
||||||
bundleMcpRuntime && bundleMcpRuntime.tools.length > 0
|
bundleMcpRuntime && bundleMcpRuntime.tools.length > 0
|
||||||
? [...tools, ...bundleMcpRuntime.tools]
|
? [...tools, ...bundleMcpRuntime.tools]
|
||||||
: 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({
|
const allowedToolNames = collectAllowedToolNames({
|
||||||
tools: effectiveTools,
|
tools: effectiveTools,
|
||||||
clientTools,
|
clientTools,
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import os from "node:os";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
import type { OpenClawConfig } from "../config/config.js";
|
import type { OpenClawConfig } from "../config/config.js";
|
||||||
|
import { applyOpenClawToolPolicies } from "./pi-tools.js";
|
||||||
import {
|
import {
|
||||||
filterToolsByPolicy,
|
filterToolsByPolicy,
|
||||||
isToolAllowedByPolicyName,
|
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", () => {
|
describe("resolveSubagentToolPolicy depth awareness", () => {
|
||||||
const baseCfg = {
|
const baseCfg = {
|
||||||
agents: { defaults: { subagents: { maxSpawnDepth: 2 } } },
|
agents: { defaults: { subagents: { maxSpawnDepth: 2 } } },
|
||||||
|
|||||||
@ -195,6 +195,105 @@ export const __testing = {
|
|||||||
applyModelProviderToolPolicy,
|
applyModelProviderToolPolicy,
|
||||||
} as const;
|
} 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?: {
|
export function createOpenClawCodingTools(options?: {
|
||||||
agentId?: string;
|
agentId?: string;
|
||||||
exec?: ExecToolDefaults & ProcessToolDefaults;
|
exec?: ExecToolDefaults & ProcessToolDefaults;
|
||||||
@ -562,37 +661,25 @@ export function createOpenClawCodingTools(options?: {
|
|||||||
return [tool];
|
return [tool];
|
||||||
})
|
})
|
||||||
: tools;
|
: tools;
|
||||||
const toolsForMessageProvider = applyMessageProviderToolPolicy(
|
const subagentFiltered = applyOpenClawToolPolicies({
|
||||||
toolsForMemoryFlush,
|
tools: toolsForMemoryFlush,
|
||||||
options?.messageProvider,
|
config: options?.config,
|
||||||
);
|
sessionKey: options?.sessionKey,
|
||||||
const toolsForModelProvider = applyModelProviderToolPolicy(toolsForMessageProvider, {
|
agentId: options?.agentId,
|
||||||
modelProvider: options?.modelProvider,
|
modelProvider: options?.modelProvider,
|
||||||
modelId: options?.modelId,
|
modelId: options?.modelId,
|
||||||
});
|
messageProvider: options?.messageProvider,
|
||||||
// Security: treat unknown/undefined as unauthorized (opt-in, not opt-out)
|
groupId: options?.groupId,
|
||||||
const senderIsOwner = options?.senderIsOwner === true;
|
groupChannel: options?.groupChannel,
|
||||||
const toolsByAuthorization = applyOwnerOnlyToolPolicy(toolsForModelProvider, senderIsOwner);
|
groupSpace: options?.groupSpace,
|
||||||
const subagentFiltered = applyToolPolicyPipeline({
|
agentAccountId: options?.agentAccountId,
|
||||||
tools: toolsByAuthorization,
|
senderId: options?.senderId,
|
||||||
toolMeta: (tool) => getPluginToolMeta(tool),
|
senderName: options?.senderName,
|
||||||
warn: logWarn,
|
senderUsername: options?.senderUsername,
|
||||||
steps: [
|
senderE164: options?.senderE164,
|
||||||
...buildDefaultToolPolicyPipelineSteps({
|
senderIsOwner: options?.senderIsOwner,
|
||||||
profilePolicy: profilePolicyWithAlsoAllow,
|
spawnedBy: options?.spawnedBy,
|
||||||
profile,
|
sandbox,
|
||||||
providerProfilePolicy: providerProfilePolicyWithAlsoAllow,
|
|
||||||
providerProfile,
|
|
||||||
globalPolicy,
|
|
||||||
globalProviderPolicy,
|
|
||||||
agentPolicy,
|
|
||||||
agentProviderPolicy,
|
|
||||||
groupPolicy,
|
|
||||||
agentId,
|
|
||||||
}),
|
|
||||||
{ policy: sandbox?.tools, label: "sandbox tools.allow" },
|
|
||||||
{ policy: subagentPolicy, label: "subagent tools.allow" },
|
|
||||||
],
|
|
||||||
});
|
});
|
||||||
// Always normalize tool JSON Schemas before handing them to pi-agent/pi-ai.
|
// 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.
|
// Without this, some providers (notably OpenAI) will reject root-level union schemas.
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user