Twilio signs webhook requests using the URL without the port component,
even when the publicUrl config includes a non-standard port. Add a fallback
that strips the port from the verification URL when initial validation fails,
matching the behavior of Twilio's official helper library.
Closes#6334
Address Greptile review: externally-initiated outbound-api calls were
stored with hardcoded direction: "inbound". Now createWebhookCall accepts
a direction parameter so the CallRecord accurately reflects the event's
actual direction. Also skip inboundGreeting for outbound calls and add a
test asserting inbound direction is preserved.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fixes#30900 — Calls initiated directly via the Twilio REST API
(Direction=outbound-api) were rejected as "unknown call" because
processEvent only auto-registered calls with direction=inbound.
External outbound-api calls now get registered in the CallManager
so the media stream is accepted. Inbound policy checks still only
apply to true inbound calls.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Bun runs can trigger multiple embedded agent invocations in a single cron
turn (e.g. retries/fallbacks), making assertions against call[0] flaky.
Assert against the last invocation instead.
Address Greptile review: when sessionKey is undefined the fallback
matched any enabled cron job, which could silently suppress the guard
note due to jobs from unrelated sessions. Return false instead so the
note always appears when session scoping is not possible.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Before appending the "I did not schedule a reminder" guard note, check the
cron store for enabled jobs matching the current session key. This prevents
false positives when the agent references an existing cron created in a
prior turn (e.g. "I'll ping you when it's done" while a monitoring cron is
already running).
The check only fires on the rare path where the text matches commitment
patterns AND no cron was added in the current turn, so the added I/O is
negligible.
Closes#32228
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Stickers, voice notes, and captionless photos from the bot also lack
text and caption fields, so the previous check incorrectly classified
them as system messages and suppressed implicitMention.
Switch to checking for Telegram's forum_topic_* / general_forum_topic_*
service-message fields which only appear on actual service messages.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Address Greptile review feedback: bot media messages (photo/video) use
caption instead of text, so they would be incorrectly classified as
system messages. Add !caption guard to the system message check.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When a Telegram Forum topic is created by the bot, Telegram generates a
system message with from.id=botId and empty text. Every subsequent user
message in that topic has reply_to_message pointing to this system
message, causing the implicitMention check to fire and bypassing
requireMention for every single message.
Add a guard that recognises system messages (is_bot=true with no text)
and excludes them from implicit mention detection, so that only genuine
replies to bot messages trigger the bypass.
Closes#32256
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix(plugins): expose ephemeral sessionId in tool contexts for per-conversation isolation
The plugin tool context (`OpenClawPluginToolContext`) and tool hook
context (`PluginHookToolContext`) only provided `sessionKey`, which
is a durable channel identifier that survives /new and /reset.
Plugins like mem0 that need per-conversation isolation (e.g. mapping
Mem0 `run_id`) had no way to distinguish between conversations,
causing session-scoped memories to persist unbounded across resets.
Add `sessionId` (ephemeral UUID regenerated on /new and /reset) to:
- `OpenClawPluginToolContext` (factory context for plugin tools)
- `PluginHookToolContext` (before_tool_call / after_tool_call hooks)
- Internal `HookContext` for tool call wrappers
Thread the value from the run attempt through createOpenClawCodingTools
→ createOpenClawTools → resolvePluginTools and through the tool hook
wrapper.
Closes#31253
Made-with: Cursor
* fix(agents): propagate embedded sessionId through tool hook context
* test(hooks): cover sessionId in embedded tool hook contexts
* docs(changelog): add sessionId hook context follow-up note
* test(hooks): avoid toolCallId collision in after_tool_call e2e
---------
Co-authored-by: SidQin-cyber <sidqin0410@gmail.com>