fix(agent): preserve broadcast consultation context

This commit is contained in:
2026-07-25 00:12:53 +08:00
parent a67444645e
commit 5f8d8f96f0
10 changed files with 48 additions and 22 deletions
+1 -1
View File
@@ -2991,7 +2991,7 @@ onUnload(() => {
border-radius: 999px;
background: #eef3f8;
color: #5b6b7f;
font-size: 11px;
font-size: 12px;
}
.agent-clarification {
+1 -1
View File
@@ -111,7 +111,7 @@ export const normalizeAgentResponse = (
rewrittenQuery: question,
resources: response.resources || [],
memoryCandidate,
broadcastContext: null,
broadcastContext: response.broadcastContext || null,
agentStatus: response.status,
agentIntent: response.intent,
sourceSummary: response.sourceSummary || [],
+1
View File
@@ -261,6 +261,7 @@ export interface AgentResponse {
sourceSummary: AgentSourceSummary[];
citations: KnowledgeCitation[];
resources: KnowledgeResource[];
broadcastContext?: BroadcastKnowledgeContext | null;
data?: unknown;
actionDraft?: AgentActionDraft | null;
clarification?: AgentClarification | null;
+6 -4
View File
@@ -81,17 +81,19 @@ test('问师傅在真正开始会话后收起首次使用引导,保留对话
test('消息咨询只以消息 ID 作为受控上下文,并让每轮文字或语音请求携带它', async () => {
const [page, service, types] = await Promise.all([
read('../src/pages/user/sop/index.vue'),
read('../src/services/knowledge.ts'),
read('../src/services/agent.ts'),
read('../src/types/api.ts')
]);
assert.match(page, /getBroadcastMessage\(pending\.messageId\)/);
assert.match(page, /messageId: message\.id,\s*title: message\.title,\s*publishedAt: message\.publishedAt/);
assert.match(page, /broadcastMessageId \? undefined : currentProject\.value\?\.projectCode/);
assert.match(page, /options\.voice \? 'mobile_uni_voice' : 'mobile_uni_sop',\s*broadcastMessageId/);
assert.match(page, /const agentOptions = \{[\s\S]*?broadcastMessageId,[\s\S]*?\}/);
assert.match(page, /askAgent\(text, agentOptions\)/);
assert.match(service, /broadcastMessageId\?: number/);
assert.match(service, /\? \{ broadcastMessageId \}/);
assert.match(service, /broadcastContext: response\.broadcastContext \|\| legacy\.broadcastContext \|\| null/);
assert.match(service, /broadcastMessageId: options\.broadcastMessageId/);
assert.match(service, /\/api\/aihr\/agent\/messages/);
assert.match(service, /broadcastContext: response\.broadcastContext \|\| null/);
assert.match(types, /export interface BroadcastKnowledgeContext/);
assert.match(types, /broadcastContext\?: BroadcastKnowledgeContext \| null/);
});
+8 -8
View File
@@ -61,11 +61,11 @@ test('语音 profile 透传方言枚举,并保持普通话默认值', async ()
pageSource('../src/services/speech.ts')
]);
assert.match(apiTypes, /dialect\?: 'mandarin' \| 'cantonese' \| 'sichuanese'/);
assert.match(apiTypes, /dialect\?: 'mandarin' \| 'cantonese'[\s\S]*\| 'sichuanese'/);
assert.match(speechService, /dialect: 'mandarin'/);
assert.match(speechService, /customerVoiceProfile = \([\s\S]*?dialect:/);
assert.match(speechService, /dialect === 'cantonese'.*'zh-HK'/);
assert.match(speechService, /dialect === 'sichuanese'[\s\S]*?当前设备语音不支持四川话/);
assert.match(speechService, /dialect && dialect !== 'mandarin'/);
});
test('M3 将业主 TTS 绑定到当前训练会话与准确回合,供主管复盘回放', async () => {
@@ -77,7 +77,7 @@ test('M3 将业主 TTS 绑定到当前训练会话与准确回合,供主管复
assert.match(apiTypes, /export interface PracticeTtsContext/);
assert.match(speechService, /practiceContext\?: PracticeTtsContext/);
assert.match(speechService, /data: \{ text: text\.trim\(\)\.slice\(0, 300\), voiceProfile, practiceContext \}/);
assert.match(speechService, /data: \{ text: text\.trim\(\)\.slice\(0, 300\), voiceProfile: resolveTtsVoiceProfile\(voiceProfile\), practiceContext \}/);
assert.match(practicePage, /\{ sessionId: sessionId\.value, turnIndex: Number\(customerTurnIndex\), role: 'customer' \}/);
assert.match(practicePage, /speechPlayback\.preload\(spoken, profile, practiceContext\)/);
assert.match(practicePage, /turnVoice\(index\)\.profile, turnVoice\(index\)\.practiceContext/);
@@ -481,10 +481,10 @@ test('主管专项从正式团队名单按姓名多选并一次批量派发', as
});
test('问师傅支持现场媒体、答案播报和总结卡图片下载', async () => {
const [source, composerSource, knowledgeService, speechService, imageService] = await Promise.all([
const [source, composerSource, agentService, speechService, imageService] = await Promise.all([
pageSource('../src/pages/user/sop/index.vue'),
pageSource('../src/components/chat/ChatComposer.vue'),
pageSource('../src/services/knowledge.ts'),
pageSource('../src/services/agent.ts'),
pageSource('../src/services/speech.ts'),
pageSource('../src/services/summary-card-image.ts')
]);
@@ -492,11 +492,11 @@ test('问师傅支持现场媒体、答案播报和总结卡图片下载', async
assert.match(source, /@pick-media="pickMedia"/);
assert.match(composerSource, /图片\/视频/);
assert.match(composerSource, /仅用于本次现场分析/);
assert.match(source, /searchKnowledgeWithMedia/);
assert.match(source, /askAgentWithMedia/);
assert.match(source, /toggleAnswerSpeech/);
assert.match(source, /toggleSummarySpeech/);
assert.match(source, /downloadSummaryCardImage/);
assert.match(knowledgeService, /\/api\/knowledge\/query-media/);
assert.match(agentService, /\/api\/aihr\/agent\/messages\/media/);
assert.match(speechService, /\/api\/ai\/tts/);
assert.match(speechService, /SpeechSynthesisUtterance/);
assert.match(speechService, /playWithBrowserSpeech/);
@@ -580,7 +580,7 @@ test('播报复用已合成音频且总结图按内容高度生成并及时释
assert.match(speechService, /const sourceCache = new Map<string, string>\(\)/);
assert.match(speechService, /const maxCachedSources = 4/);
assert.match(speechService, /const sourceKey = cacheKey\(value, profile, practiceContext\)/);
assert.match(speechService, /const sourceKey = cacheKey\(value, effectiveProfile, practiceContext\)/);
assert.match(speechService, /const cachedSource = sourceCache\.get\(sourceKey\)/);
assert.match(speechService, /sourceCache\.clear\(\)/);
assert.match(speechService, /registerAbort\?\.\(\(\) => task\.abort\(\)\)/);
+4 -2
View File
@@ -23,8 +23,10 @@ test('个人助理客户端使用确认式记忆接口且确认请求携带稳
const card = await read('../src/components/chat/MemoryCandidateCard.vue');
assert.match(service, /\/api\/aihr\/personal-assistant\/memory-candidates/);
assert.match(service, /\$\{candidateBase\}\/\$\{candidateId\}\/confirm/);
assert.match(service, /\$\{candidateBase\}\/\$\{candidateId\}\/dismiss/);
assert.match(service, /\/api\/aihr\/agent\/actions\/\$\{encodeURIComponent\(String\(candidateRef\)\)\}\/confirm/);
assert.match(service, /\$\{candidateBase\}\/\$\{candidateRef\}\/confirm/);
assert.match(service, /\/api\/aihr\/agent\/actions\/\$\{encodeURIComponent\(String\(candidateRef\)\)\}\/dismiss/);
assert.match(service, /\$\{candidateBase\}\/\$\{candidateRef\}\/dismiss/);
assert.match(service, /\/api\/aihr\/service-memories/);
assert.match(service, /\/api\/aihr\/personal-assistant\/assistant-captures/);
assert.match(card, /const idempotencyKey = ref\(createMemoryIdempotencyKey\(props\.candidate\.id\)\)/);