feat(hooks): add message_received and message_sent hooks to chat completions endpoint
Trigger plugin hooks for API requests through /v1/chat/completions:
- message_received: fires before agent processing with prompt content,
user field, model, sessionKey, and source metadata
- message_sent: fires after response generation (non-streaming only)
This enables plugins to react to API traffic, e.g., logging voice
shortcut interactions to Discord for history/context.
The hooks use the existing plugin hook system (not internal hooks),
so any plugin can register handlers via api.on('message_received', ...)
Note: Streaming responses do not yet fire message_sent; this could be
added in a follow-up by accumulating deltas and firing at lifecycle end.
This commit is contained in:
parent
da71eaebd2
commit
7f34d730db
@ -5,6 +5,7 @@ import { buildHistoryContextFromEntries, type HistoryEntry } from "../auto-reply
|
|||||||
import { createDefaultDeps } from "../cli/deps.js";
|
import { createDefaultDeps } from "../cli/deps.js";
|
||||||
import { agentCommand } from "../commands/agent.js";
|
import { agentCommand } from "../commands/agent.js";
|
||||||
import { emitAgentEvent, onAgentEvent } from "../infra/agent-events.js";
|
import { emitAgentEvent, onAgentEvent } from "../infra/agent-events.js";
|
||||||
|
import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
|
||||||
import { defaultRuntime } from "../runtime.js";
|
import { defaultRuntime } from "../runtime.js";
|
||||||
import { authorizeGatewayConnect, type ResolvedGatewayAuth } from "./auth.js";
|
import { authorizeGatewayConnect, type ResolvedGatewayAuth } from "./auth.js";
|
||||||
import {
|
import {
|
||||||
@ -200,6 +201,35 @@ export async function handleOpenAiHttpRequest(
|
|||||||
const runId = `chatcmpl_${randomUUID()}`;
|
const runId = `chatcmpl_${randomUUID()}`;
|
||||||
const deps = createDefaultDeps();
|
const deps = createDefaultDeps();
|
||||||
|
|
||||||
|
// Trigger message_received hook for API requests (enables voice logging, etc.)
|
||||||
|
const hookRunner = getGlobalHookRunner();
|
||||||
|
if (hookRunner?.hasHooks("message_received")) {
|
||||||
|
void hookRunner
|
||||||
|
.runMessageReceived(
|
||||||
|
{
|
||||||
|
from: user ?? "api",
|
||||||
|
content: prompt.message,
|
||||||
|
timestamp: Date.now(),
|
||||||
|
metadata: {
|
||||||
|
apiUser: user,
|
||||||
|
model,
|
||||||
|
sessionKey,
|
||||||
|
source: "chat_completions",
|
||||||
|
runId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelId: "api",
|
||||||
|
accountId: undefined,
|
||||||
|
conversationId: sessionKey,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.catch((err) => {
|
||||||
|
// Fire-and-forget, just log errors
|
||||||
|
console.error(`[openai-http] message_received hook failed: ${String(err)}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (!stream) {
|
if (!stream) {
|
||||||
try {
|
try {
|
||||||
const result = await agentCommand(
|
const result = await agentCommand(
|
||||||
@ -225,6 +255,24 @@ export async function handleOpenAiHttpRequest(
|
|||||||
.join("\n\n")
|
.join("\n\n")
|
||||||
: "No response from OpenClaw.";
|
: "No response from OpenClaw.";
|
||||||
|
|
||||||
|
// Trigger message_sent hook for API responses (non-streaming only for now)
|
||||||
|
if (hookRunner?.hasHooks("message_sent")) {
|
||||||
|
void hookRunner
|
||||||
|
.runMessageSent(
|
||||||
|
{
|
||||||
|
to: user ?? "api",
|
||||||
|
content,
|
||||||
|
success: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelId: "api",
|
||||||
|
accountId: undefined,
|
||||||
|
conversationId: sessionKey,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.catch(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
sendJson(res, 200, {
|
sendJson(res, 200, {
|
||||||
id: runId,
|
id: runId,
|
||||||
object: "chat.completion",
|
object: "chat.completion",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user