docs: document approval reaction reply contracts

This commit is contained in:
Peter Steinberger
2026-06-04 22:32:37 -04:00
parent 14690904f0
commit 1e6fb5089b
2 changed files with 15 additions and 0 deletions

View File

@@ -67,6 +67,7 @@ export type ApprovalReactionTargetRecord<TRoute = unknown> = {
expiresAtMs?: number;
};
/** Resolved approval target and decision produced from a reaction event. */
export type ApprovalReactionTargetResolution<TRoute = unknown> =
ApprovalReactionDecisionResolution & {
approvalId: string;
@@ -74,11 +75,13 @@ export type ApprovalReactionTargetResolution<TRoute = unknown> =
route?: TRoute;
};
/** Reply payload enriched with reaction decision metadata. */
export type ApprovalReactionPromptPayload = ReplyPayload & {
allowedDecisions: readonly ExecApprovalReplyDecision[];
reactionBindings: readonly ApprovalReactionDecisionBinding[];
};
/** Pair of reaction-enabled and manual-fallback approval prompt payloads. */
export type ApprovalReactionPendingContent = {
reactionPayload: ApprovalReactionPromptPayload;
manualFallbackPayload: ReplyPayload;
@@ -339,6 +342,7 @@ function buildMetadataPayload(params: {
);
}
/** Build an approval prompt payload with reaction bindings for a prepared view. */
export function buildApprovalPendingPromptPayload(params: {
request: ApprovalRequest;
view: PendingApprovalView;
@@ -363,6 +367,7 @@ export function buildApprovalPendingPromptPayload(params: {
};
}
/** Build an approval prompt payload with reaction bindings directly from a request. */
export function buildApprovalReactionPromptPayloadForRequest(params: {
request: ApprovalRequest;
nowMs: number;
@@ -378,6 +383,7 @@ function replaceApprovalIdPlaceholder(text: string | undefined, approvalId: stri
return (text ?? "").replace(/\/approve\s+<id>/g, `/approve ${approvalId}`);
}
/** Build reaction and manual-fallback pending approval content for a prepared view. */
export function buildApprovalReactionPendingContent(params: {
request: ApprovalRequest;
view: PendingApprovalView;
@@ -418,6 +424,7 @@ export function buildApprovalReactionPendingContent(params: {
return { reactionPayload, manualFallbackPayload };
}
/** Build reaction and manual-fallback pending approval content directly from a request. */
export function buildApprovalReactionPendingContentForRequest(params: {
request: ApprovalRequest;
nowMs: number;
@@ -429,6 +436,7 @@ export function buildApprovalReactionPendingContentForRequest(params: {
});
}
/** Create an approval target store backed by memory with optional persistent storage. */
export function createApprovalReactionTargetStore<TTarget>(params: {
namespace: string;
maxEntries: number;

View File

@@ -9,6 +9,7 @@ import { hasReplyPayloadContent } from "../interactive/payload.js";
export type { MediaPayload, MediaPayloadInput } from "../channels/plugins/media-payload.js";
export { buildMediaPayload } from "../channels/plugins/media-payload.js";
/** Plugin-facing reply payload without core-only trusted local media internals. */
export type ReplyPayload = Omit<InternalReplyPayload, "trustedLocalMedia">;
export type { ReplyPayloadTtsSupplement } from "../auto-reply/reply-payload.js";
export {
@@ -19,6 +20,7 @@ export {
markReplyPayloadAsTtsSupplement,
} from "../auto-reply/reply-payload.js";
/** Normalized outbound reply payload accepted by channel send helpers. */
export type OutboundReplyPayload = {
/** Plain text reply body. */
text?: string;
@@ -40,6 +42,7 @@ export type OutboundReplyPayload = {
replyToId?: string;
};
/** Minimal payload shape used to identify reasoning/thinking replies. */
export type ReasoningReplyPayload = {
/** Reply text that may carry hidden reasoning markers. */
text?: string;
@@ -47,6 +50,7 @@ export type ReasoningReplyPayload = {
isReasoning?: boolean;
};
/** Derived sendability facts for text/media outbound payload delivery. */
export type SendableOutboundReplyParts = {
/** Raw text selected for delivery before trimming. */
text: string;
@@ -81,6 +85,7 @@ function trimLeadingMarkdownQuoteMarkers(text: string): string {
return candidate;
}
/** Detect reasoning replies from explicit flags or common reasoning text prefixes. */
export function isReasoningReplyPayload(payload: ReasoningReplyPayload): boolean {
if (payload.isReasoning === true) {
return true;
@@ -445,6 +450,7 @@ export async function sendMediaWithLeadingCaption(params: {
return true;
}
/** Deliver media with leading caption when possible, otherwise fall back to chunked text. */
export async function deliverTextOrMediaReply(params: {
payload: OutboundReplyPayload;
text: string;
@@ -486,6 +492,7 @@ export async function deliverTextOrMediaReply(params: {
return sentText ? "text" : "empty";
}
/** Send text with attachment links appended for channels without native media upload. */
export async function deliverFormattedTextWithAttachments(params: {
payload: OutboundReplyPayload;
send: (params: { text: string; replyToId?: string }) => Promise<void>;