fix: document tools invoke + honor main session key (#1575) (thanks @vignesh07)
This commit is contained in:
@@ -5,6 +5,7 @@ Docs: https://docs.clawd.bot
|
|||||||
## 2026.1.23 (Unreleased)
|
## 2026.1.23 (Unreleased)
|
||||||
|
|
||||||
### Changes
|
### Changes
|
||||||
|
- Gateway: add /tools/invoke HTTP endpoint for direct tool calls and document it. (#1575) Thanks @vignesh07.
|
||||||
- Agents: keep system prompt time zone-only and move current time to `session_status` for better cache hits.
|
- Agents: keep system prompt time zone-only and move current time to `session_status` for better cache hits.
|
||||||
- Agents: remove redundant bash tool alias from tool registration/display. (#1571) Thanks @Takhoffman.
|
- Agents: remove redundant bash tool alias from tool registration/display. (#1571) Thanks @Takhoffman.
|
||||||
- Browser: add node-host proxy auto-routing for remote gateways (configurable per gateway/node).
|
- Browser: add node-host proxy auto-routing for remote gateways (configurable per gateway/node).
|
||||||
|
|||||||
@@ -916,6 +916,7 @@
|
|||||||
"gateway/configuration-examples",
|
"gateway/configuration-examples",
|
||||||
"gateway/authentication",
|
"gateway/authentication",
|
||||||
"gateway/openai-http-api",
|
"gateway/openai-http-api",
|
||||||
|
"gateway/tools-invoke-http-api",
|
||||||
"gateway/cli-backends",
|
"gateway/cli-backends",
|
||||||
"gateway/local-models",
|
"gateway/local-models",
|
||||||
"gateway/background-process",
|
"gateway/background-process",
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ pnpm gateway:watch
|
|||||||
- The same port also serves HTTP (control UI, hooks, A2UI). Single-port multiplex.
|
- The same port also serves HTTP (control UI, hooks, A2UI). Single-port multiplex.
|
||||||
- OpenAI Chat Completions (HTTP): [`/v1/chat/completions`](/gateway/openai-http-api).
|
- OpenAI Chat Completions (HTTP): [`/v1/chat/completions`](/gateway/openai-http-api).
|
||||||
- OpenResponses (HTTP): [`/v1/responses`](/gateway/openresponses-http-api).
|
- OpenResponses (HTTP): [`/v1/responses`](/gateway/openresponses-http-api).
|
||||||
|
- Tools Invoke (HTTP): [`/tools/invoke`](/gateway/tools-invoke-http-api).
|
||||||
- Starts a Canvas file server by default on `canvasHost.port` (default `18793`), serving `http://<gateway-host>:18793/__clawdbot__/canvas/` from `~/clawd/canvas`. Disable with `canvasHost.enabled=false` or `CLAWDBOT_SKIP_CANVAS_HOST=1`.
|
- Starts a Canvas file server by default on `canvasHost.port` (default `18793`), serving `http://<gateway-host>:18793/__clawdbot__/canvas/` from `~/clawd/canvas`. Disable with `canvasHost.enabled=false` or `CLAWDBOT_SKIP_CANVAS_HOST=1`.
|
||||||
- Logs to stdout; use launchd/systemd to keep it alive and rotate logs.
|
- Logs to stdout; use launchd/systemd to keep it alive and rotate logs.
|
||||||
- Pass `--verbose` to mirror debug logging (handshakes, req/res, events) from the log file into stdio when troubleshooting.
|
- Pass `--verbose` to mirror debug logging (handshakes, req/res, events) from the log file into stdio when troubleshooting.
|
||||||
|
|||||||
79
docs/gateway/tools-invoke-http-api.md
Normal file
79
docs/gateway/tools-invoke-http-api.md
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
---
|
||||||
|
summary: "Invoke a single tool directly via the Gateway HTTP endpoint"
|
||||||
|
read_when:
|
||||||
|
- Calling tools without running a full agent turn
|
||||||
|
- Building automations that need tool policy enforcement
|
||||||
|
---
|
||||||
|
# Tools Invoke (HTTP)
|
||||||
|
|
||||||
|
Clawdbot’s Gateway exposes a simple HTTP endpoint for invoking a single tool directly. It is always enabled, but gated by Gateway auth and tool policy.
|
||||||
|
|
||||||
|
- `POST /tools/invoke`
|
||||||
|
- Same port as the Gateway (WS + HTTP multiplex): `http://<gateway-host>:<port>/tools/invoke`
|
||||||
|
|
||||||
|
Default max payload size is 2 MB.
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
Uses the Gateway auth configuration. Send a bearer token:
|
||||||
|
|
||||||
|
- `Authorization: Bearer <token>`
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- When `gateway.auth.mode="token"`, use `gateway.auth.token` (or `CLAWDBOT_GATEWAY_TOKEN`).
|
||||||
|
- When `gateway.auth.mode="password"`, use `gateway.auth.password` (or `CLAWDBOT_GATEWAY_PASSWORD`).
|
||||||
|
|
||||||
|
## Request body
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"tool": "sessions_list",
|
||||||
|
"action": "json",
|
||||||
|
"args": {},
|
||||||
|
"sessionKey": "main",
|
||||||
|
"dryRun": false
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Fields:
|
||||||
|
- `tool` (string, required): tool name to invoke.
|
||||||
|
- `action` (string, optional): mapped into args if the tool schema supports `action` and the args payload omitted it.
|
||||||
|
- `args` (object, optional): tool-specific arguments.
|
||||||
|
- `sessionKey` (string, optional): target session key. If omitted or `"main"`, the Gateway uses the configured main session key (honors `session.mainKey` and default agent, or `global` in global scope).
|
||||||
|
- `dryRun` (boolean, optional): reserved for future use; currently ignored.
|
||||||
|
|
||||||
|
## Policy + routing behavior
|
||||||
|
|
||||||
|
Tool availability is filtered through the same policy chain used by Gateway agents:
|
||||||
|
- `tools.profile` / `tools.byProvider.profile`
|
||||||
|
- `tools.allow` / `tools.byProvider.allow`
|
||||||
|
- `agents.<id>.tools.allow` / `agents.<id>.tools.byProvider.allow`
|
||||||
|
- group policies (if the session key maps to a group or channel)
|
||||||
|
- subagent policy (when invoking with a subagent session key)
|
||||||
|
|
||||||
|
If a tool is not allowed by policy, the endpoint returns **404**.
|
||||||
|
|
||||||
|
To help group policies resolve context, you can optionally set:
|
||||||
|
- `x-clawdbot-message-channel: <channel>` (example: `slack`, `telegram`)
|
||||||
|
- `x-clawdbot-account-id: <accountId>` (when multiple accounts exist)
|
||||||
|
|
||||||
|
## Responses
|
||||||
|
|
||||||
|
- `200` → `{ ok: true, result }`
|
||||||
|
- `400` → `{ ok: false, error: { type, message } }` (invalid request or tool error)
|
||||||
|
- `401` → unauthorized
|
||||||
|
- `404` → tool not available (not found or not allowlisted)
|
||||||
|
- `405` → method not allowed
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -sS http://127.0.0.1:18789/tools/invoke \
|
||||||
|
-H 'Authorization: Bearer YOUR_TOKEN' \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d '{
|
||||||
|
"tool": "sessions_list",
|
||||||
|
"action": "json",
|
||||||
|
"args": {}
|
||||||
|
}'
|
||||||
|
```
|
||||||
@@ -1,15 +1,12 @@
|
|||||||
import { describe, expect, it } from "vitest";
|
import { describe, expect, it } from "vitest";
|
||||||
|
|
||||||
import { installGatewayTestHooks, getFreePort } from "./test-helpers.server.js";
|
import { installGatewayTestHooks, getFreePort, startGatewayServer } from "./test-helpers.server.js";
|
||||||
import { startGatewayServer } from "./server.js";
|
|
||||||
import { testState } from "./test-helpers.mocks.js";
|
import { testState } from "./test-helpers.mocks.js";
|
||||||
|
|
||||||
installGatewayTestHooks({ scope: "suite" });
|
installGatewayTestHooks({ scope: "suite" });
|
||||||
|
|
||||||
describe("POST /tools/invoke", () => {
|
describe("POST /tools/invoke", () => {
|
||||||
it("invokes a tool and returns {ok:true,result}", async () => {
|
it("invokes a tool and returns {ok:true,result}", async () => {
|
||||||
testState.gatewayAuth = { mode: "none" } as any;
|
|
||||||
|
|
||||||
// Allow the sessions_list tool for main agent.
|
// Allow the sessions_list tool for main agent.
|
||||||
testState.agentsConfig = {
|
testState.agentsConfig = {
|
||||||
list: [
|
list: [
|
||||||
@@ -41,8 +38,7 @@ describe("POST /tools/invoke", () => {
|
|||||||
await server.close();
|
await server.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects unauthorized when auth mode is token and header is missing", async () => {
|
it("accepts password auth when bearer token matches", async () => {
|
||||||
testState.gatewayAuth = { mode: "token", token: "t" } as any;
|
|
||||||
testState.agentsConfig = {
|
testState.agentsConfig = {
|
||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
@@ -55,7 +51,42 @@ describe("POST /tools/invoke", () => {
|
|||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
const port = await getFreePort();
|
const port = await getFreePort();
|
||||||
const server = await startGatewayServer(port, { bind: "loopback" });
|
const server = await startGatewayServer(port, {
|
||||||
|
bind: "loopback",
|
||||||
|
auth: { mode: "password", password: "secret" },
|
||||||
|
});
|
||||||
|
|
||||||
|
const res = await fetch(`http://127.0.0.1:${port}/tools/invoke`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: {
|
||||||
|
"content-type": "application/json",
|
||||||
|
authorization: "Bearer secret",
|
||||||
|
},
|
||||||
|
body: JSON.stringify({ tool: "sessions_list", action: "json", args: {}, sessionKey: "main" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toBe(200);
|
||||||
|
|
||||||
|
await server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("rejects unauthorized when auth mode is token and header is missing", async () => {
|
||||||
|
testState.agentsConfig = {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
id: "main",
|
||||||
|
tools: {
|
||||||
|
allow: ["sessions_list"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const port = await getFreePort();
|
||||||
|
const server = await startGatewayServer(port, {
|
||||||
|
bind: "loopback",
|
||||||
|
auth: { mode: "token", token: "t" },
|
||||||
|
});
|
||||||
|
|
||||||
const res = await fetch(`http://127.0.0.1:${port}/tools/invoke`, {
|
const res = await fetch(`http://127.0.0.1:${port}/tools/invoke`, {
|
||||||
method: "POST",
|
method: "POST",
|
||||||
@@ -69,7 +100,6 @@ describe("POST /tools/invoke", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("returns 404 when tool is not allowlisted", async () => {
|
it("returns 404 when tool is not allowlisted", async () => {
|
||||||
testState.gatewayAuth = { mode: "none" } as any;
|
|
||||||
testState.agentsConfig = {
|
testState.agentsConfig = {
|
||||||
list: [
|
list: [
|
||||||
{
|
{
|
||||||
@@ -94,4 +124,77 @@ describe("POST /tools/invoke", () => {
|
|||||||
|
|
||||||
await server.close();
|
await server.close();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("respects tools.profile allowlist", async () => {
|
||||||
|
testState.agentsConfig = {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
id: "main",
|
||||||
|
tools: {
|
||||||
|
allow: ["sessions_list"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
const { writeConfigFile } = await import("../config/config.js");
|
||||||
|
await writeConfigFile({
|
||||||
|
tools: { profile: "minimal" },
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
const port = await getFreePort();
|
||||||
|
const server = await startGatewayServer(port, { bind: "loopback" });
|
||||||
|
|
||||||
|
const res = await fetch(`http://127.0.0.1:${port}/tools/invoke`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
body: JSON.stringify({ tool: "sessions_list", action: "json", args: {}, sessionKey: "main" }),
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(res.status).toBe(404);
|
||||||
|
|
||||||
|
await server.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("uses the configured main session key when sessionKey is missing or main", async () => {
|
||||||
|
testState.agentsConfig = {
|
||||||
|
list: [
|
||||||
|
{
|
||||||
|
id: "main",
|
||||||
|
tools: {
|
||||||
|
deny: ["sessions_list"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "ops",
|
||||||
|
default: true,
|
||||||
|
tools: {
|
||||||
|
allow: ["sessions_list"],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any;
|
||||||
|
testState.sessionConfig = { mainKey: "primary" };
|
||||||
|
|
||||||
|
const port = await getFreePort();
|
||||||
|
const server = await startGatewayServer(port, { bind: "loopback" });
|
||||||
|
|
||||||
|
const payload = { tool: "sessions_list", action: "json", args: {} };
|
||||||
|
|
||||||
|
const resDefault = await fetch(`http://127.0.0.1:${port}/tools/invoke`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
body: JSON.stringify(payload),
|
||||||
|
});
|
||||||
|
expect(resDefault.status).toBe(200);
|
||||||
|
|
||||||
|
const resMain = await fetch(`http://127.0.0.1:${port}/tools/invoke`, {
|
||||||
|
method: "POST",
|
||||||
|
headers: { "content-type": "application/json" },
|
||||||
|
body: JSON.stringify({ ...payload, sessionKey: "main" }),
|
||||||
|
});
|
||||||
|
expect(resMain.status).toBe(200);
|
||||||
|
|
||||||
|
await server.close();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,13 +1,25 @@
|
|||||||
import type { IncomingMessage, ServerResponse } from "node:http";
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
||||||
|
|
||||||
import { loadConfig } from "../config/config.js";
|
|
||||||
import { resolveAgentIdFromSessionKey } from "../agents/agent-scope.js";
|
|
||||||
import { createClawdbotTools } from "../agents/clawdbot-tools.js";
|
import { createClawdbotTools } from "../agents/clawdbot-tools.js";
|
||||||
import {
|
import {
|
||||||
|
filterToolsByPolicy,
|
||||||
resolveEffectiveToolPolicy,
|
resolveEffectiveToolPolicy,
|
||||||
resolveGroupToolPolicy,
|
resolveGroupToolPolicy,
|
||||||
isToolAllowedByPolicies,
|
resolveSubagentToolPolicy,
|
||||||
} from "../agents/pi-tools.policy.js";
|
} from "../agents/pi-tools.policy.js";
|
||||||
|
import {
|
||||||
|
buildPluginToolGroups,
|
||||||
|
collectExplicitAllowlist,
|
||||||
|
expandPolicyWithPluginGroups,
|
||||||
|
normalizeToolName,
|
||||||
|
resolveToolProfilePolicy,
|
||||||
|
stripPluginOnlyAllowlist,
|
||||||
|
} from "../agents/tool-policy.js";
|
||||||
|
import { loadConfig } from "../config/config.js";
|
||||||
|
import { resolveMainSessionKey } from "../config/sessions.js";
|
||||||
|
import { logWarn } from "../logger.js";
|
||||||
|
import { getPluginToolMeta } from "../plugins/tools.js";
|
||||||
|
import { isSubagentSessionKey } from "../routing/session-key.js";
|
||||||
import { normalizeMessageChannel } from "../utils/message-channel.js";
|
import { normalizeMessageChannel } from "../utils/message-channel.js";
|
||||||
|
|
||||||
import { authorizeGatewayConnect, type ResolvedGatewayAuth } from "./auth.js";
|
import { authorizeGatewayConnect, type ResolvedGatewayAuth } from "./auth.js";
|
||||||
@@ -71,7 +83,7 @@ export async function handleToolsInvokeHttpRequest(
|
|||||||
const token = getBearerToken(req);
|
const token = getBearerToken(req);
|
||||||
const authResult = await authorizeGatewayConnect({
|
const authResult = await authorizeGatewayConnect({
|
||||||
auth: opts.auth,
|
auth: opts.auth,
|
||||||
connectAuth: token ? { token } : null,
|
connectAuth: token ? { token, password: token } : null,
|
||||||
req,
|
req,
|
||||||
});
|
});
|
||||||
if (!authResult.ok) {
|
if (!authResult.ok) {
|
||||||
@@ -98,9 +110,10 @@ export async function handleToolsInvokeHttpRequest(
|
|||||||
: {}
|
: {}
|
||||||
) as Record<string, unknown>;
|
) as Record<string, unknown>;
|
||||||
|
|
||||||
const sessionKey = resolveSessionKeyFromBody(body) ?? "main";
|
|
||||||
const cfg = loadConfig();
|
const cfg = loadConfig();
|
||||||
const agentId = resolveAgentIdFromSessionKey(sessionKey);
|
const rawSessionKey = resolveSessionKeyFromBody(body);
|
||||||
|
const sessionKey =
|
||||||
|
!rawSessionKey || rawSessionKey === "main" ? resolveMainSessionKey(cfg) : rawSessionKey;
|
||||||
|
|
||||||
// Resolve message channel/account hints (optional headers) for policy inheritance.
|
// Resolve message channel/account hints (optional headers) for policy inheritance.
|
||||||
const messageChannel = normalizeMessageChannel(
|
const messageChannel = normalizeMessageChannel(
|
||||||
@@ -108,34 +121,113 @@ export async function handleToolsInvokeHttpRequest(
|
|||||||
);
|
);
|
||||||
const accountId = getHeader(req, "x-clawdbot-account-id")?.trim() || undefined;
|
const accountId = getHeader(req, "x-clawdbot-account-id")?.trim() || undefined;
|
||||||
|
|
||||||
// Build tool list (core + plugin tools).
|
const {
|
||||||
const allTools = createClawdbotTools({
|
agentId,
|
||||||
agentSessionKey: sessionKey,
|
globalPolicy,
|
||||||
agentChannel: messageChannel ?? undefined,
|
globalProviderPolicy,
|
||||||
agentAccountId: accountId,
|
agentPolicy,
|
||||||
config: cfg,
|
agentProviderPolicy,
|
||||||
});
|
profile,
|
||||||
|
providerProfile,
|
||||||
const policy = resolveEffectiveToolPolicy({ config: cfg, sessionKey });
|
} = resolveEffectiveToolPolicy({ config: cfg, sessionKey });
|
||||||
|
const profilePolicy = resolveToolProfilePolicy(profile);
|
||||||
|
const providerProfilePolicy = resolveToolProfilePolicy(providerProfile);
|
||||||
const groupPolicy = resolveGroupToolPolicy({
|
const groupPolicy = resolveGroupToolPolicy({
|
||||||
config: cfg,
|
config: cfg,
|
||||||
sessionKey,
|
sessionKey,
|
||||||
messageProvider: messageChannel ?? undefined,
|
messageProvider: messageChannel ?? undefined,
|
||||||
accountId: accountId ?? null,
|
accountId: accountId ?? null,
|
||||||
});
|
});
|
||||||
|
const subagentPolicy = isSubagentSessionKey(sessionKey)
|
||||||
|
? resolveSubagentToolPolicy(cfg)
|
||||||
|
: undefined;
|
||||||
|
|
||||||
const allowed = (name: string) =>
|
// Build tool list (core + plugin tools).
|
||||||
isToolAllowedByPolicies(name, [
|
const allTools = createClawdbotTools({
|
||||||
policy.globalPolicy,
|
agentSessionKey: sessionKey,
|
||||||
policy.agentPolicy,
|
agentChannel: messageChannel ?? undefined,
|
||||||
policy.globalProviderPolicy,
|
agentAccountId: accountId,
|
||||||
policy.agentProviderPolicy,
|
config: cfg,
|
||||||
|
pluginToolAllowlist: collectExplicitAllowlist([
|
||||||
|
profilePolicy,
|
||||||
|
providerProfilePolicy,
|
||||||
|
globalPolicy,
|
||||||
|
globalProviderPolicy,
|
||||||
|
agentPolicy,
|
||||||
|
agentProviderPolicy,
|
||||||
groupPolicy,
|
groupPolicy,
|
||||||
]);
|
subagentPolicy,
|
||||||
|
]),
|
||||||
|
});
|
||||||
|
|
||||||
const tools = (allTools as any[]).filter((t) => allowed(t.name));
|
const coreToolNames = new Set(
|
||||||
|
allTools
|
||||||
|
.filter((tool) => !getPluginToolMeta(tool as any))
|
||||||
|
.map((tool) => normalizeToolName(tool.name))
|
||||||
|
.filter(Boolean),
|
||||||
|
);
|
||||||
|
const pluginGroups = buildPluginToolGroups({
|
||||||
|
tools: allTools,
|
||||||
|
toolMeta: (tool) => getPluginToolMeta(tool as any),
|
||||||
|
});
|
||||||
|
const resolvePolicy = (policy: typeof profilePolicy, label: string) => {
|
||||||
|
const resolved = stripPluginOnlyAllowlist(policy, pluginGroups, coreToolNames);
|
||||||
|
if (resolved.unknownAllowlist.length > 0) {
|
||||||
|
const entries = resolved.unknownAllowlist.join(", ");
|
||||||
|
const suffix = resolved.strippedAllowlist
|
||||||
|
? "Ignoring allowlist so core tools remain available."
|
||||||
|
: "These entries won't match any tool unless the plugin is enabled.";
|
||||||
|
logWarn(`tools: ${label} allowlist contains unknown entries (${entries}). ${suffix}`);
|
||||||
|
}
|
||||||
|
return expandPolicyWithPluginGroups(resolved.policy, pluginGroups);
|
||||||
|
};
|
||||||
|
const profilePolicyExpanded = resolvePolicy(
|
||||||
|
profilePolicy,
|
||||||
|
profile ? `tools.profile (${profile})` : "tools.profile",
|
||||||
|
);
|
||||||
|
const providerProfileExpanded = resolvePolicy(
|
||||||
|
providerProfilePolicy,
|
||||||
|
providerProfile ? `tools.byProvider.profile (${providerProfile})` : "tools.byProvider.profile",
|
||||||
|
);
|
||||||
|
const globalPolicyExpanded = resolvePolicy(globalPolicy, "tools.allow");
|
||||||
|
const globalProviderExpanded = resolvePolicy(globalProviderPolicy, "tools.byProvider.allow");
|
||||||
|
const agentPolicyExpanded = resolvePolicy(
|
||||||
|
agentPolicy,
|
||||||
|
agentId ? `agents.${agentId}.tools.allow` : "agent tools.allow",
|
||||||
|
);
|
||||||
|
const agentProviderExpanded = resolvePolicy(
|
||||||
|
agentProviderPolicy,
|
||||||
|
agentId ? `agents.${agentId}.tools.byProvider.allow` : "agent tools.byProvider.allow",
|
||||||
|
);
|
||||||
|
const groupPolicyExpanded = resolvePolicy(groupPolicy, "group tools.allow");
|
||||||
|
const subagentPolicyExpanded = expandPolicyWithPluginGroups(subagentPolicy, pluginGroups);
|
||||||
|
|
||||||
const tool = tools.find((t) => t.name === toolName);
|
const toolsFiltered = profilePolicyExpanded
|
||||||
|
? filterToolsByPolicy(allTools, profilePolicyExpanded)
|
||||||
|
: allTools;
|
||||||
|
const providerProfileFiltered = providerProfileExpanded
|
||||||
|
? filterToolsByPolicy(toolsFiltered, providerProfileExpanded)
|
||||||
|
: toolsFiltered;
|
||||||
|
const globalFiltered = globalPolicyExpanded
|
||||||
|
? filterToolsByPolicy(providerProfileFiltered, globalPolicyExpanded)
|
||||||
|
: providerProfileFiltered;
|
||||||
|
const globalProviderFiltered = globalProviderExpanded
|
||||||
|
? filterToolsByPolicy(globalFiltered, globalProviderExpanded)
|
||||||
|
: globalFiltered;
|
||||||
|
const agentFiltered = agentPolicyExpanded
|
||||||
|
? filterToolsByPolicy(globalProviderFiltered, agentPolicyExpanded)
|
||||||
|
: globalProviderFiltered;
|
||||||
|
const agentProviderFiltered = agentProviderExpanded
|
||||||
|
? filterToolsByPolicy(agentFiltered, agentProviderExpanded)
|
||||||
|
: agentFiltered;
|
||||||
|
const groupFiltered = groupPolicyExpanded
|
||||||
|
? filterToolsByPolicy(agentProviderFiltered, groupPolicyExpanded)
|
||||||
|
: agentProviderFiltered;
|
||||||
|
const subagentFiltered = subagentPolicyExpanded
|
||||||
|
? filterToolsByPolicy(groupFiltered, subagentPolicyExpanded)
|
||||||
|
: groupFiltered;
|
||||||
|
|
||||||
|
const tool = subagentFiltered.find((t) => t.name === toolName);
|
||||||
if (!tool) {
|
if (!tool) {
|
||||||
sendJson(res, 404, {
|
sendJson(res, 404, {
|
||||||
ok: false,
|
ok: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user