mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-18 06:57:28 +00:00
feat(hooks): add trigger and channelId to plugin hook agent context (#28623)
* feat(hooks): add trigger and channelId to plugin hook agent context Adds `trigger` and `channelId` fields to `PluginHookAgentContext` so plugins can determine what initiated the agent run and which channel it originated from, without session-key parsing or Redis bridging. trigger values: "user", "heartbeat", "cron", "memory" channelId values: "telegram", "discord", "whatsapp", etc. Both fields are threaded through run.ts and attempt.ts hookCtx so all hook phases receive them (before_model_resolve, before_prompt_build, before_agent_start, llm_input, llm_output, agent_end). channelId falls back from messageChannel to messageProvider when the former is not set. followup-runner passes originatingChannel so queued followup runs also carry channel context. * docs(changelog): note hook context parity fix for #28623 --------- Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
This commit is contained in:
@@ -45,6 +45,7 @@ Docs: https://docs.openclaw.ai
|
||||
- CLI/Config validation and routing hardening: dedupe `openclaw config validate` failures to a single authoritative report, expose allowed-values metadata/hints across core Zod and plugin AJV validation (including `--json` fields), sanitize terminal-rendered validation text, and make command-path parsing root-option-aware across preaction/route/lazy registration (including routed `config get/unset` with split root options). Thanks @gumadeiras.
|
||||
- Models/config env propagation: apply `config.env.vars` before implicit provider discovery in models bootstrap so config-scoped credentials are visible to implicit provider resolution paths. (#32295) Thanks @hsiaoa.
|
||||
- Hooks/runtime stability: keep the internal hook handler registry on a `globalThis` singleton so hook registration/dispatch remains consistent when bundling emits duplicate module copies. (#32292) Thanks @Drickon.
|
||||
- Hooks/plugin context parity: ensure `llm_input` hooks in embedded attempts receive the same `trigger` and `channelId`-aware `hookCtx` used by the other hook phases, preserving channel/trigger-scoped plugin behavior. (#28623) Thanks @davidrudduck and @vincentkoc.
|
||||
- Restart sentinel formatting: avoid duplicate `Reason:` lines when restart message text already matches `stats.reason`, keeping restart notifications concise for users and downstream parsers. (#32083) Thanks @velamints2.
|
||||
- Voice-call/Twilio signature verification: retry signature validation across deterministic URL port variants (with/without port) to handle mixed Twilio signing behavior behind reverse proxies and non-standard ports. (#25140) Thanks @drvoss.
|
||||
- Hooks/webhook ACK compatibility: return `200` (instead of `202`) for successful `/hooks/agent` requests so providers that require `200` (for example Forward Email) accept dispatched agent hook deliveries. (#28204) Thanks @Glucksberg.
|
||||
|
||||
@@ -263,6 +263,8 @@ export async function runEmbeddedPiAgent(
|
||||
sessionId: params.sessionId,
|
||||
workspaceDir: resolvedWorkspace,
|
||||
messageProvider: params.messageProvider ?? undefined,
|
||||
trigger: params.trigger,
|
||||
channelId: params.messageChannel ?? params.messageProvider ?? undefined,
|
||||
};
|
||||
if (hookRunner?.hasHooks("before_model_resolve")) {
|
||||
try {
|
||||
@@ -715,6 +717,7 @@ export async function runEmbeddedPiAgent(
|
||||
const attempt = await runEmbeddedAttempt({
|
||||
sessionId: params.sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
trigger: params.trigger,
|
||||
messageChannel: params.messageChannel,
|
||||
messageProvider: params.messageProvider,
|
||||
agentAccountId: params.agentAccountId,
|
||||
|
||||
@@ -1356,6 +1356,8 @@ export async function runEmbeddedAttempt(
|
||||
sessionId: params.sessionId,
|
||||
workspaceDir: params.workspaceDir,
|
||||
messageProvider: params.messageProvider ?? undefined,
|
||||
trigger: params.trigger,
|
||||
channelId: params.messageChannel ?? params.messageProvider ?? undefined,
|
||||
};
|
||||
const hookResult = await resolvePromptBuildHookResult({
|
||||
prompt: params.prompt,
|
||||
|
||||
@@ -26,6 +26,8 @@ export type RunEmbeddedPiAgentParams = {
|
||||
messageChannel?: string;
|
||||
messageProvider?: string;
|
||||
agentAccountId?: string;
|
||||
/** What initiated this agent run: "user", "heartbeat", "cron", or "memory". */
|
||||
trigger?: string;
|
||||
/** Delivery target (e.g. telegram:group:123:topic:456) for topic/thread routing. */
|
||||
messageTo?: string;
|
||||
/** Thread/topic identifier for routing replies to the originating thread. */
|
||||
|
||||
@@ -295,6 +295,7 @@ export async function runAgentTurnWithFallback(params: {
|
||||
});
|
||||
return runEmbeddedPiAgent({
|
||||
...embeddedContext,
|
||||
trigger: params.isHeartbeat ? "heartbeat" : "user",
|
||||
groupId: resolveGroupSessionKey(params.sessionCtx)?.id,
|
||||
groupChannel:
|
||||
params.sessionCtx.GroupChannel?.trim() ?? params.sessionCtx.GroupSubject?.trim(),
|
||||
|
||||
@@ -487,6 +487,7 @@ export async function runMemoryFlushIfNeeded(params: {
|
||||
...embeddedContext,
|
||||
...senderContext,
|
||||
...runBaseParams,
|
||||
trigger: "memory",
|
||||
prompt: resolveMemoryFlushPromptForRun({
|
||||
prompt: memoryFlushSettings.prompt,
|
||||
cfg: params.cfg,
|
||||
|
||||
@@ -157,6 +157,8 @@ export function createFollowupRunner(params: {
|
||||
sessionId: queued.run.sessionId,
|
||||
sessionKey: queued.run.sessionKey,
|
||||
agentId: queued.run.agentId,
|
||||
trigger: "user",
|
||||
messageChannel: queued.originatingChannel ?? undefined,
|
||||
messageProvider: queued.run.messageProvider,
|
||||
agentAccountId: queued.run.agentAccountId,
|
||||
messageTo: queued.originatingTo,
|
||||
|
||||
@@ -279,6 +279,7 @@ function runAgentAttempt(params: {
|
||||
sessionId: params.sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
agentId: params.sessionAgentId,
|
||||
trigger: "user",
|
||||
messageChannel: params.messageChannel,
|
||||
agentAccountId: params.runContext.accountId,
|
||||
messageTo: params.opts.replyTo ?? params.opts.to,
|
||||
|
||||
@@ -490,6 +490,7 @@ export async function runCronIsolatedAgentTurn(params: {
|
||||
sessionId: cronSession.sessionEntry.sessionId,
|
||||
sessionKey: agentSessionKey,
|
||||
agentId,
|
||||
trigger: "cron",
|
||||
messageChannel,
|
||||
agentAccountId: resolvedDelivery.accountId,
|
||||
sessionFile,
|
||||
|
||||
@@ -340,6 +340,10 @@ export type PluginHookAgentContext = {
|
||||
sessionId?: string;
|
||||
workspaceDir?: string;
|
||||
messageProvider?: string;
|
||||
/** What initiated this agent run: "user", "heartbeat", "cron", or "memory". */
|
||||
trigger?: string;
|
||||
/** Channel identifier (e.g. "telegram", "discord", "whatsapp"). */
|
||||
channelId?: string;
|
||||
};
|
||||
|
||||
// before_model_resolve hook
|
||||
|
||||
Reference in New Issue
Block a user