Quellcode durchsuchen

WIP: 保留群聊无限回复轮次

[gstack-context]
Decisions: -1 继续表示无限回复;有限轮次按服务端上限 100 校验
Remaining: 最终完整测试、重启 8800、真实页面复核
Tried: v3 管理端到端用例覆盖 -1 并通过
Skill: /investigate
[/gstack-context]
samien vor 2 Monaten
Ursprung
Commit
a15cb70972

+ 4 - 3
src/client/components/groups/GroupManager.vue

@@ -104,9 +104,10 @@ watch(() => props.agents, agents => {
 }, { deep: true, immediate: true })
 
 function saveRoom() {
+  const replyRounds = Number(form.replyRounds)
   emit('updateRoom', {
     name: form.name.trim() || props.room.name,
-    replyRounds: Math.min(12, Math.max(1, Number(form.replyRounds) || 1)),
+    replyRounds: replyRounds === -1 ? -1 : Math.min(100, Math.max(1, replyRounds || 1)),
   })
 }
 
@@ -186,7 +187,7 @@ function statusLabel(status: GroupAgent['status']): string {
     <section>
       <h3>房间</h3>
       <label><span>名称</span><input v-model="form.name" maxlength="80" @change="saveRoom" /></label>
-      <label class="rounds"><span>最多回复轮数</span><input v-model.number="form.replyRounds" type="number" min="1" max="12" @change="saveRoom" /></label>
+      <label class="rounds"><span>最多回复轮数<small>-1 表示无限</small></span><input v-model.number="form.replyRounds" type="number" min="-1" max="100" aria-label="最多回复轮数" @change="saveRoom" /></label>
     </section>
 
     <section>
@@ -264,7 +265,7 @@ section { padding: 17px 0; border-top: 1px solid var(--line); } section:first-of
 h3 { margin: 0 0 13px; color: var(--text-secondary); font-size: 10px; font-weight: 650; letter-spacing: .06em; text-transform: uppercase; } h3 em { color: var(--text-muted); font-style: normal; font-weight: 500; }
 label { display: flex; flex-direction: column; gap: 5px; margin: 0 0 11px; color: var(--text-muted); font-size: 10px; }
 input, textarea, select { width: 100%; padding: 8px 9px; border: 1px solid var(--line); border-radius: 9px; outline: 0; resize: vertical; background: var(--surface-soft); color: var(--text-primary); font-size: 11px; } input:focus, textarea:focus, select:focus { border-color: var(--line-strong); box-shadow: 0 0 0 3px var(--focus-ring); }
-.rounds { flex-direction: row; align-items: center; justify-content: space-between; }.rounds input { width: 62px; text-align: center; }
+.rounds { flex-direction: row; align-items: center; justify-content: space-between; }.rounds > span { display: flex; flex-direction: column; gap: 2px; }.rounds small { color: var(--text-muted); font-size: 9px; }.rounds input { width: 62px; text-align: center; }
 .agent-list { display: flex; flex-direction: column; gap: 7px; }.agent-list article { display: grid; grid-template-columns: 32px minmax(0,1fr) repeat(3, 28px); align-items: center; gap: 7px; padding: 8px; border: 1px solid transparent; border-radius: 10px; background: var(--surface-soft); }.agent-list article.expanded { border-color: var(--line); background: var(--surface); }
 .agent-avatar { position: relative; display: grid; place-items: center; width: 32px; height: 32px; border-radius: 9px; background: var(--accent); color: var(--text-on-solid); font-size: 10px; font-weight: 700; }.agent-avatar i { position: absolute; right: -2px; bottom: -2px; width: 8px; height: 8px; border: 2px solid var(--surface-soft); border-radius: 50%; background: var(--text-muted); }.agent-avatar .status-running, .agent-avatar .status-queued { background: var(--warning); }.agent-avatar .status-idle { background: var(--success); }.agent-avatar .status-awaiting_input { background: var(--warning); }
 .agent-copy { display: flex; min-width: 0; flex-direction: column; }.agent-copy strong, .agent-copy small { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }.agent-copy strong { font-size: 11px; }.agent-copy small { margin-top: 2px; color: var(--text-muted); font-size: 9px; }

+ 1 - 0
tests/e2e/workspace.spec.ts

@@ -102,6 +102,7 @@ test('edits every protocol v3 Agent setting with one inspector close control', a
 
   await expect(page.getByRole('button', { name: '关闭群聊管理' })).toHaveCount(1)
   await expect(page.getByRole('button', { name: '关闭预览' })).toHaveCount(0)
+  await expect(page.getByLabel('最多回复轮数')).toHaveValue('-1')
   await page.getByRole('button', { name: '设置夭夭' }).click()
 
   const editor = page.getByRole('group', { name: '夭夭 Agent 设置' })

+ 1 - 1
tests/fixtures/fake-hermes.mjs

@@ -60,7 +60,7 @@ const groupAgent = { id: agentId, roomId, profile: 'yaoyao', displayName: '夭
 const groupMessage = { seq: 1, id: '44444444-4444-4444-8444-444444444444', roomId, senderKind: 'human', senderId: 'demo-user', senderName: '验收用户', content: '大家好,检查一下群聊输入框。', status: 'completed', createdAt: now() - 120, updatedAt: now() - 120 }
 const groupAssistantMessage = { seq: 2, id: '55555555-5555-4555-8555-555555555555', roomId, senderKind: 'agent', senderId: agentId, senderName: '夭夭', content: '历史兼容:MEDIA:/brand/AppIcon-1024.png', status: 'completed', createdAt: now() - 100, updatedAt: now() - 100 }
 const groupMessages = [groupMessage, groupAssistantMessage]
-const room = { id: roomId, name: '设计与工程协作', cwd: '/tmp', createdAt: now() - 2000, updatedAt: now(), archived: false, agentCount: 1, maxReplyRounds: 3, lastMessage: groupAssistantMessage, unreadCount: 0 }
+const room = { id: roomId, name: '设计与工程协作', cwd: '/tmp', createdAt: now() - 2000, updatedAt: now(), archived: false, agentCount: 1, maxReplyRounds: -1, lastMessage: groupAssistantMessage, unreadCount: 0 }
 const rpcRequests = []
 const previewPdf = Buffer.from('JVBERi0xLjQKMSAwIG9iago8PC9UeXBlL0NhdGFsb2cvUGFnZXMgMiAwIFI+PgplbmRvYmoKMiAwIG9iago8PC9UeXBlL1BhZ2VzL0tpZHNbMyAwIFJdL0NvdW50IDE+PgplbmRvYmoKMyAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDIgMCBSL01lZGlhQm94WzAgMCAyMDAgMjAwXT4+CmVuZG9iagp4cmVmCjAgNAowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTAgMDAwMDAgbiAKMDAwMDAwMDA1MyAwMDAwMCBuIAowMDAwMDAwMTA1IDAwMDAwIG4gCnRyYWlsZXIKPDwvU2l6ZSA0L1Jvb3QgMSAwIFI+PgpzdGFydHhyZWYKMTY2CiUlRU9G', 'base64')