|
9 | 9 | // - The owner can turn a connector off for one Bot: `bot.connectors = { composio: false }`. Absent |
10 | 10 | // means on, so every Bot, old or new, has the connected connector. |
11 | 11 | // - A friend's Bot (`remote`) never gets them. A run Bot (`ephemeral`) gets a connector |
12 | | -// only when its `stepTools` name it (`github` covers `mcp__github__*`). A Session whose |
| 12 | +// only when its `stepTools` name it (`github` covers `mcp__github__*`), and never when a |
| 13 | +// friend's Bot is the one that started the run (#1555). A Session whose |
13 | 14 | // Bot or parent chain cannot be resolved fails closed. Sessions that belong to no Bot |
14 | 15 | // (the DSH Agent, plain DSH sessions) are not touched: they are the owner's own, and no |
15 | 16 | // friend can reach them. |
@@ -69,8 +70,17 @@ export function install(rt) { |
69 | 70 | return caps |
70 | 71 | } |
71 | 72 | const capOff = (bot, id) => capsOf(bot).find(cap => turnedOff(cap, id)) |
| 73 | + // #1555: `run_workflow`/`define_workflow` have no `visibleTo`, so a friend's Bot can call them and a run |
| 74 | + // Bot can name it as the one that started the run (`createdBy`). A remote Bot has no switch table of ours |
| 75 | + // to intersect with, so it reads as "every connector switched off": the node's `tools` cannot hand the run |
| 76 | + // Bot a connector. A record with no `createdBy` (the owner, the board, an older run) keeps the answer it |
| 77 | + // had, and a `createdBy` that names a Bot we do not have leaves it as it was too. |
| 78 | + const remoteCaller = (bot) => { |
| 79 | + const id = bot?.createdBy |
| 80 | + return (typeof id === 'string' && id !== '' ? rt.botOf(id) : undefined)?.remote !== undefined |
| 81 | + } |
72 | 82 | const allowed = (bot, id) => bot.remote === undefined && !turnedOff(bot, id) |
73 | | - && (bot.ephemeral === undefined || (stepGrants(bot, id) && capOff(bot, id) === undefined)) |
| 83 | + && (bot.ephemeral === undefined || (stepGrants(bot, id) && capOff(bot, id) === undefined && !remoteCaller(bot))) |
74 | 84 |
|
75 | 85 | // The Bot an Agent works for: its own chat, a group Session and an earlier part resolve through |
76 | 86 | // selfOf; a sub-agent Session is followed up to its parent. The answer has three shapes, and only |
@@ -144,6 +154,9 @@ export function install(rt) { |
144 | 154 | if (allowed(bot, id)) return undefined |
145 | 155 | if (bot.remote !== undefined) return `The ${id} connector is not available to a friend's Bot.` |
146 | 156 | if (bot.ephemeral !== undefined) { |
| 157 | + // #1555: the caller is the reason, not the step list — a friend's Bot started this run, and a remote |
| 158 | + // Bot has no switch table of ours to intersect with, so it reads as every connector switched off. |
| 159 | + if (remoteCaller(bot)) return `The ${id} connector is not available to a run started by a friend's Bot.` |
147 | 160 | // #1544: the step did name it — a Bot's switch is what refuses it, and naming it again in the |
148 | 161 | // graph cannot turn it back on. |
149 | 162 | const cap = capOff(bot, id) |
|
0 commit comments