fix(nostr): replace non-existent handleInboundMessage API with dispatchReplyFromConfig
Fixes #4547 The Nostr plugin was calling runtime.channel.reply.handleInboundMessage(), which doesn't exist in the PluginRuntime API. This caused DM processing to fail with 'handleInboundMessage is not a function'. Changed to use the correct message dispatch pattern: 1. Build proper MsgContext with finalizeInboundContext() 2. Create reply dispatcher with createReplyDispatcherWithTyping() 3. Dispatch replies with dispatchReplyFromConfig() This matches the pattern used by other channel extensions like Matrix and Discord. The fix ensures: - DMs are properly routed through the agent pipeline - Session state is recorded correctly - Reply text is formatted with markdown table conversion - Human delay and typing indicators work as expected
This commit is contained in:
parent
da71eaebd2
commit
35576d1481
@ -221,18 +221,105 @@ export const nostrPlugin: ChannelPlugin<ResolvedNostrAccount> = {
|
||||
onMessage: async (senderPubkey, text, reply) => {
|
||||
ctx.log?.debug(`[${account.accountId}] DM from ${senderPubkey}: ${text.slice(0, 50)}...`);
|
||||
|
||||
// Forward to OpenClaw's message pipeline
|
||||
await runtime.channel.reply.handleInboundMessage({
|
||||
// Load current config for routing
|
||||
const cfg = runtime.config.loadConfig();
|
||||
|
||||
// Resolve agent route for this message
|
||||
const route = runtime.channel.routing.resolveAgentRoute({
|
||||
cfg,
|
||||
channel: "nostr",
|
||||
accountId: account.accountId,
|
||||
senderId: senderPubkey,
|
||||
chatType: "direct",
|
||||
chatId: senderPubkey, // For DMs, chatId is the sender's pubkey
|
||||
text,
|
||||
reply: async (responseText: string) => {
|
||||
await reply(responseText);
|
||||
senderId: senderPubkey,
|
||||
});
|
||||
|
||||
// Build session key for this conversation
|
||||
const sessionKey = `nostr:${account.accountId}:direct:${senderPubkey}`;
|
||||
|
||||
// Format the nostr prefix for sender
|
||||
const from = `nostr:${senderPubkey}`;
|
||||
const to = `nostr:${account.publicKey}`;
|
||||
|
||||
// Build the message context
|
||||
const msgContext = runtime.channel.reply.finalizeInboundContext({
|
||||
Body: text,
|
||||
RawBody: text,
|
||||
CommandBody: text,
|
||||
From: from,
|
||||
To: to,
|
||||
SessionKey: sessionKey,
|
||||
AccountId: account.accountId,
|
||||
ChatType: "direct" as const,
|
||||
ConversationLabel: `Nostr DM`,
|
||||
SenderName: senderPubkey.slice(0, 8),
|
||||
SenderId: senderPubkey,
|
||||
Provider: "nostr" as const,
|
||||
Surface: "nostr" as const,
|
||||
Timestamp: Date.now(),
|
||||
CommandAuthorized: true,
|
||||
CommandSource: "text" as const,
|
||||
OriginatingChannel: "nostr" as const,
|
||||
OriginatingTo: to,
|
||||
});
|
||||
|
||||
// Record the inbound session
|
||||
const storePath = runtime.channel.session.resolveStorePath(cfg.session?.store, {
|
||||
agentId: route.agentId,
|
||||
});
|
||||
|
||||
await runtime.channel.session.recordInboundSession({
|
||||
storePath,
|
||||
sessionKey,
|
||||
ctx: msgContext,
|
||||
updateLastRoute: {
|
||||
sessionKey: route.mainSessionKey,
|
||||
channel: "nostr",
|
||||
to: from,
|
||||
accountId: account.accountId,
|
||||
},
|
||||
onRecordError: (err) => {
|
||||
ctx.log?.debug(`[${account.accountId}] Failed updating session meta: ${String(err)}`);
|
||||
},
|
||||
});
|
||||
|
||||
// Create reply dispatcher with typing
|
||||
const tableMode = runtime.channel.text.resolveMarkdownTableMode({
|
||||
cfg,
|
||||
channel: "nostr",
|
||||
accountId: account.accountId,
|
||||
});
|
||||
|
||||
const { dispatcher, replyOptions, markDispatchIdle } =
|
||||
runtime.channel.reply.createReplyDispatcherWithTyping({
|
||||
responsePrefix: null,
|
||||
responsePrefixContextProvider: null,
|
||||
humanDelay: runtime.channel.reply.resolveHumanDelayConfig(cfg, route.agentId),
|
||||
deliver: async (payload) => {
|
||||
const replyText = payload.text ?? "";
|
||||
const convertedText = runtime.channel.text.convertMarkdownTables(replyText, tableMode);
|
||||
await reply(convertedText);
|
||||
},
|
||||
onError: (err, info) => {
|
||||
ctx.log?.error(`[${account.accountId}] Nostr ${info.kind} reply failed: ${String(err)}`);
|
||||
},
|
||||
});
|
||||
|
||||
// Dispatch the reply
|
||||
const { queuedFinal, counts } = await runtime.channel.reply.dispatchReplyFromConfig({
|
||||
ctx: msgContext,
|
||||
cfg,
|
||||
dispatcher,
|
||||
replyOptions,
|
||||
});
|
||||
|
||||
markDispatchIdle();
|
||||
|
||||
if (queuedFinal) {
|
||||
const finalCount = counts.final;
|
||||
ctx.log?.debug(
|
||||
`[${account.accountId}] Delivered ${finalCount} reply${finalCount === 1 ? "" : "ies"} to ${senderPubkey.slice(0, 8)}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
onError: (error, context) => {
|
||||
ctx.log?.error(`[${account.accountId}] Nostr error (${context}): ${error.message}`);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user