Files
mai-bot/dashboard/src/lib/memory-progress-client.ts
DrSmoothl 9e48cd2848 feat: add TuningTab component for tuning task management and utility functions for memory operations
- Implemented TuningTab component to handle tuning objectives, intensity, sample size, and evaluation settings.
- Added UI elements for creating tuning tasks and displaying current configurations and recent tasks.
- Introduced utility functions for normalizing and formatting memory operation data, including feedback actions and delete operations.
2026-05-01 20:14:37 +08:00

100 lines
3.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { unifiedWsClient, type WsEventEnvelope } from './unified-ws'
export type MemoryProgressTopic = 'import_progress' | 'delete_progress' | 'feedback_progress'
export interface MemoryProgressEvent {
topic: MemoryProgressTopic
event: string
data: Record<string, unknown>
}
type ProgressListener = (event: MemoryProgressEvent) => void
const DOMAIN = 'memory'
const KNOWN_TOPICS: MemoryProgressTopic[] = ['import_progress', 'delete_progress', 'feedback_progress']
/**
* 长期记忆控制台的统一 WebSocket 桥接客户端。
*
* 负责:
* 1. 订阅 `memory` 域下的若干 topic导入/删除/反馈进度)。
* 2. 把后端推送的事件分发给所有已注册的监听器。
* 3. 即使后端尚未广播也保持安全:监听器为空时不抛错,订阅幂等。
*
* 与 `pluginProgressClient` 保持一致的形状,便于复用。
*/
class MemoryProgressClient {
private initialized = false
private listeners: Set<ProgressListener> = new Set()
private activeTopics: Set<MemoryProgressTopic> = new Set()
private initialize(): void {
if (this.initialized) {
return
}
unifiedWsClient.addEventListener((message: WsEventEnvelope) => {
if (message.domain !== DOMAIN) {
return
}
const topic = (message.topic ?? '') as MemoryProgressTopic
if (!KNOWN_TOPICS.includes(topic)) {
return
}
const payload: MemoryProgressEvent = {
topic,
event: message.event,
data: message.data ?? {},
}
this.listeners.forEach((listener) => {
try {
listener(payload)
} catch (error) {
console.error('长期记忆进度监听器执行失败:', error)
}
})
})
this.initialized = true
}
async subscribe(
listener: ProgressListener,
topics: MemoryProgressTopic[] = KNOWN_TOPICS,
): Promise<() => Promise<void>> {
this.initialize()
this.listeners.add(listener)
// 仅订阅尚未激活的 topic避免重复 subscribe
for (const topic of topics) {
if (this.activeTopics.has(topic)) {
continue
}
try {
await unifiedWsClient.subscribe(DOMAIN, topic)
this.activeTopics.add(topic)
} catch (error) {
// 后端可能尚未实现该 topic订阅失败时只记录不抛出确保 polling 仍可作为兜底
console.warn(`订阅长期记忆 topic 失败(将退化到轮询兜底): ${topic}`, error)
}
}
return async () => {
this.listeners.delete(listener)
if (this.listeners.size === 0) {
const topicsToRelease = Array.from(this.activeTopics)
this.activeTopics.clear()
for (const topic of topicsToRelease) {
try {
await unifiedWsClient.unsubscribe(DOMAIN, topic)
} catch (error) {
console.warn(`取消订阅长期记忆 topic 失败: ${topic}`, error)
}
}
}
}
}
}
export const memoryProgressClient = new MemoryProgressClient()