fix telegram polling and message action scopes · openclaw/openclaw@5239b20
2026-05-17
·
via Recent Commits to openclaw:main
| Original file line number | Diff line number | Diff line change |
|---|
@@ -668,6 +668,39 @@ describe("handleTelegramAction", () => {
|
668 | 668 | ]); |
669 | 669 | }); |
670 | 670 | |
| 671 | +it("forwards gateway client scopes into Telegram send target resolution", async () => { |
| 672 | +await handleTelegramAction( |
| 673 | +{ |
| 674 | +action: "sendMessage", |
| 675 | +to: "@testchannel", |
| 676 | +content: "Hello from CLI", |
| 677 | +}, |
| 678 | +telegramConfig(), |
| 679 | +{ gatewayClientScopes: ["operator.write"] }, |
| 680 | +); |
| 681 | +const call = mockCall(sendMessageTelegram, 0, "gateway-scoped send"); |
| 682 | +expect(requireRecord(call[2], "gateway-scoped send options").gatewayClientScopes).toEqual([ |
| 683 | +"operator.write", |
| 684 | +]); |
| 685 | +}); |
| 686 | + |
| 687 | +it("forwards gateway client scopes into Telegram poll target resolution", async () => { |
| 688 | +await handleTelegramAction( |
| 689 | +{ |
| 690 | +action: "poll", |
| 691 | +to: "@testchannel", |
| 692 | +question: "Ready?", |
| 693 | +answers: ["Yes", "No"], |
| 694 | +}, |
| 695 | +telegramConfig(), |
| 696 | +{ gatewayClientScopes: ["operator.write"] }, |
| 697 | +); |
| 698 | +const call = mockCall(sendPollTelegram, 0, "gateway-scoped poll"); |
| 699 | +expect(requireRecord(call[2], "gateway-scoped poll options").gatewayClientScopes).toEqual([ |
| 700 | +"operator.write", |
| 701 | +]); |
| 702 | +}); |
| 703 | + |
671 | 704 | it.each([ |
672 | 705 | { |
673 | 706 | name: "react", |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -241,6 +241,7 @@ export async function handleTelegramAction(
|
241 | 241 | mediaReadFile?: (filePath: string) => Promise<Buffer>; |
242 | 242 | sessionKey?: string | null; |
243 | 243 | inboundEventKind?: string; |
| 244 | +gatewayClientScopes?: readonly string[]; |
244 | 245 | }, |
245 | 246 | ): Promise<AgentToolResult<unknown>> { |
246 | 247 | const { action, accountId } = { |
@@ -404,6 +405,7 @@ export async function handleTelegramAction(
|
404 | 405 | mediaUrl: mediaUrl || undefined, |
405 | 406 | mediaLocalRoots: options?.mediaLocalRoots, |
406 | 407 | mediaReadFile: options?.mediaReadFile, |
| 408 | +gatewayClientScopes: options?.gatewayClientScopes, |
407 | 409 | buttons, |
408 | 410 | replyToMessageId: replyToMessageId ?? undefined, |
409 | 411 | messageThreadId: messageThreadId ?? undefined, |
@@ -491,6 +493,7 @@ export async function handleTelegramAction(
|
491 | 493 | messageThreadId: messageThreadId ?? undefined, |
492 | 494 | isAnonymous: isAnonymous ?? undefined, |
493 | 495 | silent: silent ?? undefined, |
| 496 | +gatewayClientScopes: options?.gatewayClientScopes, |
494 | 497 | }, |
495 | 498 | ); |
496 | 499 | notifyVisibleOutboundSuccess(to, messageThreadId); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -63,7 +63,9 @@ describe("telegramMessageActions", () => {
|
63 | 63 | {}, |
64 | 64 | { |
65 | 65 | mediaLocalRoots: [], |
| 66 | +mediaReadFile: undefined, |
66 | 67 | sessionKey: "telegram-session", |
| 68 | +gatewayClientScopes: undefined, |
67 | 69 | }, |
68 | 70 | ); |
69 | 71 | }); |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -183,9 +183,11 @@ export const telegramMessageActions: ChannelMessageActionAdapter = {
|
183 | 183 | cfg, |
184 | 184 | accountId, |
185 | 185 | mediaLocalRoots, |
| 186 | + mediaReadFile, |
186 | 187 | sessionKey, |
187 | 188 | inboundEventKind, |
188 | 189 | toolContext, |
| 190 | + gatewayClientScopes, |
189 | 191 | }) => { |
190 | 192 | const telegramAction = resolveTelegramMessageActionName(action); |
191 | 193 | if (!telegramAction) { |
@@ -203,7 +205,7 @@ export const telegramMessageActions: ChannelMessageActionAdapter = {
|
203 | 205 | : {}), |
204 | 206 | }, |
205 | 207 | cfg, |
206 | | -{ mediaLocalRoots, sessionKey, inboundEventKind }, |
| 208 | +{ mediaLocalRoots, mediaReadFile, sessionKey, inboundEventKind, gatewayClientScopes }, |
207 | 209 | ); |
208 | 210 | }, |
209 | 211 | }; |
| Original file line number | Diff line number | Diff line change |
|---|
@@ -585,9 +585,10 @@ describe("TelegramPollingSession", () => {
|
585 | 585 | token: "tok", |
586 | 586 | }), |
587 | 587 | ); |
588 | | -expect( |
589 | | -mockObjectArg(createTelegramBotMock, "createTelegramBot").updateOffset, |
590 | | -).toBeUndefined(); |
| 588 | +expect(mockObjectArg(createTelegramBotMock, "createTelegramBot").updateOffset).toEqual({ |
| 589 | +lastUpdateId: null, |
| 590 | +onUpdateId: expect.any(Function), |
| 591 | +}); |
591 | 592 | expect(init).toHaveBeenCalledBefore(handleUpdate); |
592 | 593 | expect(handleUpdate).toHaveBeenCalledWith({ update_id: 42, message: { text: "hello" } }); |
593 | 594 | } finally { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -279,12 +279,10 @@ export class TelegramPollingSession {
|
279 | 279 | const fetchAbortController = new AbortController(); |
280 | 280 | this.#activeFetchAbort = fetchAbortController; |
281 | 281 | const telegramTransport = this.#transportState.acquireForNextCycle(); |
282 | | -const updateOffset = this.opts.isolatedIngress?.enabled |
283 | | - ? undefined |
284 | | - : { |
285 | | -lastUpdateId: this.opts.getLastUpdateId(), |
286 | | -onUpdateId: this.opts.persistUpdateId, |
287 | | -}; |
| 282 | +const updateOffset = { |
| 283 | +lastUpdateId: this.opts.getLastUpdateId(), |
| 284 | +onUpdateId: this.opts.persistUpdateId, |
| 285 | +}; |
288 | 286 | try { |
289 | 287 | return createTelegramBot({ |
290 | 288 | token: this.opts.token, |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -10,7 +10,6 @@ import type {
|
10 | 10 | TelegramIngressWorkerMessage, |
11 | 11 | TelegramIngressWorkerOptions, |
12 | 12 | } from "./telegram-ingress-worker.js"; |
13 | | -import { writeTelegramUpdateOffset } from "./update-offset-store.js"; |
14 | 13 | |
15 | 14 | const options = workerData as TelegramIngressWorkerOptions; |
16 | 15 | const pollLimit = 100; |
@@ -131,11 +130,6 @@ async function main(): Promise<void> {
|
131 | 130 | }); |
132 | 131 | if (lastUpdateId === null || updateId > lastUpdateId) { |
133 | 132 | lastUpdateId = updateId; |
134 | | -await writeTelegramUpdateOffset({ |
135 | | -accountId: options.accountId, |
136 | | -botToken: options.token, |
137 | | - updateId, |
138 | | -}); |
139 | 133 | } |
140 | 134 | post({ type: "spooled", updateId, queued: result.length }); |
141 | 135 | } |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -695,6 +695,7 @@ export type ChannelMessageActionContext = {
|
695 | 695 | }; |
696 | 696 | toolContext?: ChannelThreadingToolContext; |
697 | 697 | dryRun?: boolean; |
| 698 | +gatewayClientScopes?: readonly string[]; |
698 | 699 | }; |
699 | 700 | |
700 | 701 | export type ChannelToolSend = { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -1325,17 +1325,21 @@ describe("gateway send mirroring", () => {
|
1325 | 1325 | "send-test-message-action-media-roots", |
1326 | 1326 | ); |
1327 | 1327 | |
1328 | | -const { respond } = await runMessageActionRequest({ |
1329 | | -channel: "telegram", |
1330 | | -action: "sendAttachment", |
1331 | | -params: { chatId: "123", mediaUrl: `${TEST_AGENT_WORKSPACE}/render.png` }, |
1332 | | -agentId: "work", |
1333 | | -idempotencyKey: "idem-message-action-media-roots", |
1334 | | -}); |
| 1328 | +const { respond } = await runMessageActionRequest( |
| 1329 | +{ |
| 1330 | +channel: "telegram", |
| 1331 | +action: "sendAttachment", |
| 1332 | +params: { chatId: "123", mediaUrl: `${TEST_AGENT_WORKSPACE}/render.png` }, |
| 1333 | +agentId: "work", |
| 1334 | +idempotencyKey: "idem-message-action-media-roots", |
| 1335 | +}, |
| 1336 | +{ connect: { scopes: ["operator.write"] } }, |
| 1337 | +); |
1335 | 1338 | |
1336 | 1339 | expect(firstRespondCall(respond)[0]).toBe(true); |
1337 | 1340 | const actionCall = lastDispatchChannelMessageActionCall(); |
1338 | 1341 | expect(actionCall?.mediaLocalRoots).toContain(TEST_AGENT_WORKSPACE); |
| 1342 | +expect(actionCall?.gatewayClientScopes).toEqual(["operator.write"]); |
1339 | 1343 | }); |
1340 | 1344 | |
1341 | 1345 | it("forces senderIsOwner=false for narrowly-scoped callers but honors it for full operators", async () => { |
|
| Original file line number | Diff line number | Diff line change |
|---|
@@ -373,6 +373,7 @@ export const sendHandlers: GatewayRequestHandlers = {
|
373 | 373 | ), |
374 | 374 | toolContext: request.toolContext, |
375 | 375 | dryRun: false, |
| 376 | +gatewayClientScopes: client?.connect?.scopes ?? [], |
376 | 377 | }); |
377 | 378 | if (!handled) { |
378 | 379 | const error = errorShape( |
|
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。