diff --git a/apps/web/AGENTS.md b/apps/web/AGENTS.md index 32a7321a..1882099a 100644 --- a/apps/web/AGENTS.md +++ b/apps/web/AGENTS.md @@ -386,13 +386,13 @@ Stores use Composition API style (`defineStore(() => { ... })`), with persistenc Chat supports two transport modes: **Server-Sent Events (SSE)** and **WebSocket**. #### SSE Streaming -- **Endpoints**: `/bots/{bot_id}/web/stream` (send + stream), `/messages/events` (real-time message updates) +- **Endpoints**: `/bots/{bot_id}/local/stream` (send + stream), `/messages/events` (real-time message updates) - **Parsing**: `composables/api/useChat.sse.ts` reads `ReadableStream` and parses SSE `data:` lines - **Events**: `text_delta`, `reasoning_delta`, `tool_call_start/end`, `attachment_delta`, `processing_completed/failed` - **Retry**: `useRetryingStream` composable provides exponential backoff for reconnection #### WebSocket -- **Endpoint**: `/bots/{bot_id}/web/ws` (with token query param) +- **Endpoint**: `/bots/{bot_id}/local/ws` (with token query param) - **Implementation**: `composables/api/useChat.ws.ts` wraps native `WebSocket` with send, abort, close, and auto-reconnect - **State**: `store/chat-list.ts` processes streaming events from either transport into reactive message blocks in real-time - **Abort**: Stream cancellation via `AbortSignal` (SSE) or close message (WS) diff --git a/apps/web/src/components/chat-list/channel-badge/index.vue b/apps/web/src/components/chat-list/channel-badge/index.vue index 42e199f5..e4ef4f26 100644 --- a/apps/web/src/components/chat-list/channel-badge/index.vue +++ b/apps/web/src/components/chat-list/channel-badge/index.vue @@ -27,7 +27,7 @@ const { t } = useI18n() const platformKey = computed(() => (props.platform ?? '').trim().toLowerCase()) const isWebChannel = computed(() => { const k = platformKey.value - return k === 'web' || k === '' + return k === 'local' || k === '' }) const channelLabel = computed(() => { if (!platformKey.value) return '' diff --git a/apps/web/src/components/provider-icon/index.vue b/apps/web/src/components/provider-icon/index.vue index 0ce888a5..17a07ded 100644 --- a/apps/web/src/components/provider-icon/index.vue +++ b/apps/web/src/components/provider-icon/index.vue @@ -1,7 +1,7 @@ diff --git a/apps/web/src/composables/api/useChat.chat-api.ts b/apps/web/src/composables/api/useChat.chat-api.ts index cb5800e9..6940ba23 100644 --- a/apps/web/src/composables/api/useChat.chat-api.ts +++ b/apps/web/src/composables/api/useChat.chat-api.ts @@ -28,7 +28,7 @@ export async function createSession(botId: string, title?: string): Promise = { message: msg } if (overrides?.modelId) body.model_id = overrides.modelId if (overrides?.reasoningEffort) body.reasoning_effort = overrides.reasoningEffort - await postBotsByBotIdWebMessages({ + await postBotsByBotIdLocalMessages({ path: { bot_id: botId }, body: body as { message: ChannelMessage; model_id?: string; reasoning_effort?: string }, throwOnError: true, @@ -71,7 +71,7 @@ export async function streamLocalChannel( if (!id) throw new Error('bot id is required') const response = await client.get({ - url: '/bots/{bot_id}/web/stream', + url: '/bots/{bot_id}/local/stream', path: { bot_id: id }, parseAs: 'stream', signal, diff --git a/apps/web/src/composables/api/useChat.types.ts b/apps/web/src/composables/api/useChat.types.ts index 56049244..c31e4d59 100644 --- a/apps/web/src/composables/api/useChat.types.ts +++ b/apps/web/src/composables/api/useChat.types.ts @@ -42,6 +42,7 @@ export interface Message { content?: unknown metadata?: Record assets?: MessageAsset[] + display_content?: string created_at?: string } diff --git a/apps/web/src/composables/api/useChat.ws.ts b/apps/web/src/composables/api/useChat.ws.ts index 3cb0ffbe..edc37386 100644 --- a/apps/web/src/composables/api/useChat.ws.ts +++ b/apps/web/src/composables/api/useChat.ws.ts @@ -21,7 +21,7 @@ export interface ChatWebSocket { function resolveWebSocketUrl(botId: string): string { const baseUrl = String(client.getConfig().baseUrl || '').trim() - const path = `/bots/${encodeURIComponent(botId)}/web/ws` + const path = `/bots/${encodeURIComponent(botId)}/local/ws` if (!baseUrl || baseUrl.startsWith('/')) { const loc = window.location diff --git a/apps/web/src/i18n/locales/en.json b/apps/web/src/i18n/locales/en.json index df51d546..2c5fd0de 100644 --- a/apps/web/src/i18n/locales/en.json +++ b/apps/web/src/i18n/locales/en.json @@ -201,6 +201,7 @@ "sessionTypeHeartbeat": "Heartbeat", "sessionTypeSchedule": "Scheduled Task", "sessionTypeSubagent": "Subagent", + "sessionTypeDiscuss": "Discuss", "sessionTypeChat": "Chat", "sessionFilterAll": "All", "sessionSourcePrefix": "From:", @@ -1010,7 +1011,6 @@ "matrix": "Matrix", "telegram": "Telegram", "weixin": "WeChat", - "web": "Web", "local": "Local" }, "typesShort": { @@ -1020,8 +1020,7 @@ "matrix": "MX", "telegram": "TG", "weixin": "WX", - "web": "Web", - "local": "CLI" + "local": "LC" } }, "memory": { diff --git a/apps/web/src/i18n/locales/zh.json b/apps/web/src/i18n/locales/zh.json index 9b0fb62d..c3f392de 100644 --- a/apps/web/src/i18n/locales/zh.json +++ b/apps/web/src/i18n/locales/zh.json @@ -197,6 +197,7 @@ "sessionTypeHeartbeat": "心跳", "sessionTypeSchedule": "定时任务", "sessionTypeSubagent": "子智能体", + "sessionTypeDiscuss": "讨论", "sessionTypeChat": "对话", "sessionFilterAll": "全部", "sessionSourcePrefix": "来自:", @@ -1006,7 +1007,6 @@ "matrix": "Matrix", "telegram": "Telegram", "weixin": "微信", - "web": "Web", "local": "本地" }, "typesShort": { @@ -1016,8 +1016,7 @@ "matrix": "MX", "telegram": "TG", "weixin": "WX", - "web": "Web", - "local": "CLI" + "local": "本地" } }, "memory": { diff --git a/apps/web/src/pages/bots/components/bot-access.vue b/apps/web/src/pages/bots/components/bot-access.vue index 08b5fd96..310395d9 100644 --- a/apps/web/src/pages/bots/components/bot-access.vue +++ b/apps/web/src/pages/bots/components/bot-access.vue @@ -560,7 +560,7 @@ const queryCache = useQueryCache() // ---- constants ---- -const commonChannels = ['discord', 'feishu', 'qq', 'telegram', 'wecom', 'web', 'cli'] +const commonChannels = ['discord', 'feishu', 'qq', 'telegram', 'wecom', 'local'] const subjectKinds = computed(() => [ diff --git a/apps/web/src/pages/home/components/session-item.vue b/apps/web/src/pages/home/components/session-item.vue index 0070406d..4d21596d 100644 --- a/apps/web/src/pages/home/components/session-item.vue +++ b/apps/web/src/pages/home/components/session-item.vue @@ -80,7 +80,7 @@ defineEmits<{ const { t } = useI18n() -const WEB_CHANNELS = new Set(['web', '']) +const WEB_CHANNELS = new Set(['local', '']) const isIMSession = computed(() => { const ct = (props.session.channel_type ?? '').trim().toLowerCase() @@ -137,6 +137,7 @@ const avatarFallback = computed(() => { }) const subLabel = computed(() => { + if (props.session.type === 'discuss') return t('chat.sessionTypeDiscuss') if (props.session.type === 'heartbeat') return t('chat.sessionTypeHeartbeat') if (props.session.type === 'schedule') return t('chat.sessionTypeSchedule') if (props.session.type === 'subagent') return t('chat.sessionTypeSubagent') diff --git a/apps/web/src/pages/home/components/session-sidebar.vue b/apps/web/src/pages/home/components/session-sidebar.vue index 026ea12e..7f475da7 100644 --- a/apps/web/src/pages/home/components/session-sidebar.vue +++ b/apps/web/src/pages/home/components/session-sidebar.vue @@ -149,7 +149,7 @@