Add smart ACK provider for WeChat MP replies
Replace fixed ackText with a rule-based AckProvider that picks response templates by message type and intent (translate, summary, rewrite, poster, ppt, mindmap, code, search, schedule). Pure sync, zero I/O, auto-falls back to config.ackText on any error. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
+49
-67
@@ -42,16 +42,6 @@ export type AdminSummary = {
|
||||
};
|
||||
};
|
||||
|
||||
export type LlmKey = {
|
||||
id: string;
|
||||
name: string;
|
||||
provider: string;
|
||||
model?: string;
|
||||
models?: string[];
|
||||
isSelected: boolean;
|
||||
createdAt?: string;
|
||||
};
|
||||
|
||||
export type LedgerEntry = {
|
||||
id: string;
|
||||
userId: string;
|
||||
@@ -160,6 +150,33 @@ export type WechatDeliveryLog = {
|
||||
digestType: string | null;
|
||||
};
|
||||
|
||||
export type WechatWebNotification = {
|
||||
id: string;
|
||||
userId: string;
|
||||
username: string;
|
||||
displayName: string;
|
||||
channel: string;
|
||||
notificationType: string;
|
||||
title: string;
|
||||
body: string;
|
||||
status: string;
|
||||
readAt: number | null;
|
||||
createdAt: number;
|
||||
updatedAt: number;
|
||||
};
|
||||
|
||||
export type CreateWechatNotificationPayload = {
|
||||
userId?: string;
|
||||
userIds?: string[];
|
||||
audience?: 'all';
|
||||
allUsers?: boolean;
|
||||
title: string;
|
||||
body: string;
|
||||
notificationType?: string;
|
||||
channel?: 'web' | 'wechat';
|
||||
channels?: Array<'web' | 'wechat'>;
|
||||
};
|
||||
|
||||
// ─── Summary ──────────────────────────────────────────────────────────────────
|
||||
|
||||
export async function fetchAdminSummary() {
|
||||
@@ -269,6 +286,28 @@ export async function fetchWechatDeliveries(params: { status?: string; limit?: n
|
||||
return adminFetch<{ deliveries: WechatDeliveryLog[] }>(`/admin-api/wechat/deliveries?${q}`);
|
||||
}
|
||||
|
||||
export async function fetchWechatWebNotifications(params: { status?: string; limit?: number } = {}) {
|
||||
const q = new URLSearchParams();
|
||||
if (params.status) q.set('status', params.status);
|
||||
if (params.limit) q.set('limit', String(params.limit));
|
||||
return adminFetch<{ notifications: WechatWebNotification[] }>(
|
||||
`/admin-api/wechat/web-notifications?${q}`,
|
||||
);
|
||||
}
|
||||
|
||||
export async function createWechatWebNotification(body: CreateWechatNotificationPayload) {
|
||||
return adminFetch<{
|
||||
ok: boolean;
|
||||
created: number;
|
||||
wechatSent: number;
|
||||
wechatFailures: Array<{ userId: string; message: string }>;
|
||||
targets: number;
|
||||
}>('/admin-api/wechat/web-notifications', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
export async function clearWechatRoute(userId: string) {
|
||||
return adminFetch<{ ok: boolean; deleted: number; openidMasked: string }>(
|
||||
`/admin-api/wechat/users/${userId}/route/clear`,
|
||||
@@ -285,60 +324,3 @@ export async function resumeWechatDigest(id: string) {
|
||||
method: 'POST',
|
||||
});
|
||||
}
|
||||
|
||||
// ─── LLM Providers ───────────────────────────────────────────────────────────
|
||||
|
||||
export async function fetchLlmKeys() {
|
||||
return adminFetch<{ keys: LlmKey[] }>('/admin-api/llm-providers/keys');
|
||||
}
|
||||
|
||||
export async function createLlmKey(body: {
|
||||
name: string;
|
||||
provider: string;
|
||||
apiKey: string;
|
||||
model?: string;
|
||||
models?: string;
|
||||
baseUrl?: string;
|
||||
}) {
|
||||
return adminFetch<{ key: LlmKey }>('/admin-api/llm-providers/keys', {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
}
|
||||
|
||||
export async function patchLlmKey(keyId: string, patch: { name?: string; apiKey?: string; model?: string }) {
|
||||
return adminFetch<{ key: LlmKey }>(`/admin-api/llm-providers/keys/${keyId}`, {
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(patch),
|
||||
});
|
||||
}
|
||||
|
||||
export async function selectLlmKey(keyId: string) {
|
||||
return adminFetch(`/admin-api/llm-providers/keys/${keyId}/select`, { method: 'POST' });
|
||||
}
|
||||
|
||||
export async function deleteLlmKey(keyId: string) {
|
||||
return adminFetch(`/admin-api/llm-providers/keys/${keyId}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
export async function testLlmKey(keyId: string) {
|
||||
return adminFetch<{ ok: boolean; model?: string; error?: string }>(
|
||||
`/admin-api/llm-providers/keys/${keyId}/test`,
|
||||
{ method: 'POST' },
|
||||
);
|
||||
}
|
||||
|
||||
export async function fetchLlmGlobal() {
|
||||
return adminFetch<{ settings: { model: string | null } }>('/admin-api/llm-providers/global');
|
||||
}
|
||||
|
||||
export async function putLlmGlobal(model: string) {
|
||||
return adminFetch('/admin-api/llm-providers/global', {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify({ model }),
|
||||
});
|
||||
}
|
||||
|
||||
export async function syncLlmProviders() {
|
||||
return adminFetch<{ synced: number }>('/admin-api/llm-providers/sync', { method: 'POST' });
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user