{"record":{"id":"98932e5954474d4a","repo":"666ghj/MiroFish","slug":"t-step5-noresponse","errorCode":null,"errorMessage":"t('step5.noResponse')","messagePattern":"t\\('step5\\.noResponse'\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"frontend/src/components/Step5Interaction.vue","lineNumber":769,"sourceCode":"      const twitterKey = `twitter_${agentId}`\n      const agentResult = resultsDict[redditKey] || resultsDict[twitterKey] || Object.values(resultsDict)[0]\n      if (agentResult) {\n        responseContent = agentResult.response || agentResult.answer\n      }\n    } else if (Array.isArray(resultsDict) && resultsDict.length > 0) {\n      // 兼容数组格式\n      responseContent = resultsDict[0].response || resultsDict[0].answer\n    }\n    \n    if (responseContent) {\n      chatHistory.value.push({\n        role: 'assistant',\n        content: responseContent,\n        timestamp: new Date().toISOString()\n      })\n      addLog(t('log.agentReplied', { name: selectedAgent.value.username }))\n    } else {\n      throw new Error(t('step5.noResponse'))\n    }\n  } else {\n    throw new Error(res.error || t('step5.requestFailed'))\n  }\n}\n\nconst scrollToBottom = () => {\n  nextTick(() => {\n    if (chatMessages.value) {\n      chatMessages.value.scrollTop = chatMessages.value.scrollHeight\n    }\n  })\n}\n\n// Survey Methods\nconst toggleAgentSelection = (idx) => {\n  const newSet = new Set(selectedAgents.value)\n  if (newSet.has(idx)) {","sourceCodeStart":751,"sourceCodeEnd":787,"githubUrl":"https://github.com/666ghj/MiroFish/blob/b5b53acc57189a4a42e44a23e149dc655c98fe82/frontend/src/components/Step5Interaction.vue#L751-L787","documentation":"Thrown in sendToAgent when the interviewAgents call succeeded (res.success && res.data) but the per-agent response could not be extracted: the results dictionary (keys like reddit_<id> / twitter_<id>) had no entry for the selected agent_id, or the entry existed but contained neither response nor answer. It marks a shape/empty-content mismatch between what the backend interview pipeline returned and what the component expects.","triggerScenarios":"interviewAgents returns results keyed for different agent ids (e.g. reddit_0 exists but user selected agent 2); the platform worker for that agent crashed so its key is missing; the LLM returned an empty string so response/answer are empty; or the backend changed its results schema (renamed fields, nested deeper).","commonSituations":"Agent id mismatch after profiles list and results list get out of sync (frontend indexes by array position, backend by platform agent id); one social-platform worker failing silently in a multi-platform simulation; upstream schema drift after a backend update; LLM returning empty content under strict token limits.","solutions":["Log the raw resultsDict (res.data.result.results) when the error fires to see which keys the backend actually returned.","Check the backend interview/simulation logs for the failing agent_id to find the worker or LLM failure.","Confirm the key mapping: the component looks up `reddit_${agentId}` then `twitter_${agentId}` then the first value — verify agentId matches the backend's numbering.","If keys exist but values are empty, fix the LLM call for that agent (prompt/model/timeout) server-side.","Add a schema check on the backend so it always returns response or answer per requested agent_id, or an explicit per-agent error entry."],"exampleFix":"// before\nif (agentResult) {\n  responseContent = agentResult.response || agentResult.answer\n}\n// ...\n} else {\n  throw new Error(t('step5.noResponse'))\n}\n\n// after - include the agent id and returned keys for diagnosis\nif (agentResult) {\n  responseContent = agentResult.response || agentResult.answer\n}\n// ...\n} else {\n  throw new Error(\n    t('step5.noResponse') +\n    ` (agent_id=${agentId}, keys=${Object.keys(resultsDict).join(',')})`\n  )\n}","handlingStrategy":"type-guard","validationCode":"const resultData = res.data.result || res.data\nconst resultsDict = resultData.results || resultData\nconst agentId = selectedAgentIndex.value\nconst hasEntry =\n  (typeof resultsDict === 'object' && resultsDict !== null && !Array.isArray(resultsDict) &&\n    (resultsDict[`reddit_${agentId}`] || resultsDict[`twitter_${agentId}`] || Object.values(resultsDict).length > 0)) ||\n  (Array.isArray(resultsDict) && resultsDict.length > 0)","typeGuard":"function extractAgentResponse(resultsDict, agentId) {\n  if (Array.isArray(resultsDict)) {\n    const hit = resultsDict[0]\n    return hit?.response ?? hit?.answer ?? null\n  }\n  if (resultsDict && typeof resultsDict === 'object') {\n    const entry = resultsDict[`reddit_${agentId}`] || resultsDict[`twitter_${agentId}`] || Object.values(resultsDict)[0]\n    return entry?.response ?? entry?.answer ?? null\n  }\n  return null\n}","tryCatchPattern":"try {\n  const responseContent = extractAgentResponse(resultsDict, agentId)\n  if (!responseContent) {\n    throw new Error(`${t('step5.noResponse')} (agent_id=${agentId}, keys=${Object.keys(resultsDict).join(',')})`)\n  }\n  /* push assistant message */\n} catch (err) {\n  addLog(t('log.sendFailed', { error: err.message }))\n}","preventionTips":["Log the raw resultsDict whenever extraction fails so schema drift is visible immediately.","Pin the backend interview response schema (response or answer per requested agent_id) and add a contract test.","Have the backend return an explicit per-agent error entry instead of omitting the key when a worker fails.","Keep frontend agent_id numbering and backend keys (reddit_<id>/twitter_<id>) in one shared definition."],"tags":["frontend","vue","chat","schema-mismatch","empty-response"],"backgroundTag":null,"analyzedSha":"b5b53acc57189a4a42e44a23e149dc655c98fe82","analyzedAt":"2026-08-14T22:29:33.146Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}