666ghj/MiroFish · warning · Error

t('step5.selectAgentFirst')

Error message

t('step5.selectAgentFirst')

What it means

Thrown at the top of sendToAgent when the user tries to chat with an individual agent but selectedAgent is falsy or selectedAgentIndex is null. It is a client-side precondition check: the chat target dropdown defaults to report_agent, and switching to a single agent requires clicking an agent in the list, which sets both refs. The throw is a guard, not a server condition.

Source

Thrown at frontend/src/components/Step5Interaction.vue:714

    message: message,
    chat_history: historyForApi
  })
  
  if (res.success && res.data) {
    chatHistory.value.push({
      role: 'assistant',
      content: res.data.response || res.data.answer || t('step5.noResponse'),
      timestamp: new Date().toISOString()
    })
    addLog(t('log.reportAgentReplied'))
  } else {
    throw new Error(res.error || t('step5.requestFailed'))
  }
}

const sendToAgent = async (message) => {
  if (!selectedAgent.value || selectedAgentIndex.value === null) {
    throw new Error(t('step5.selectAgentFirst'))
  }
  
  addLog(t('log.sendToAgent', { name: selectedAgent.value.username, message: message.substring(0, 50) }))
  
  // Build prompt with chat history
  let prompt = message
  if (chatHistory.value.length > 1) {
    const historyContext = chatHistory.value
      .slice(0, -1)
      .slice(-6)
      .map(msg => `${msg.role === 'user' ? '提问者' : '你'}:${msg.content}`)
      .join('\n')
    prompt = `以下是我们之前的对话:\n${historyContext}\n\n现在我的新问题是:${message}`
  }
  
  const res = await interviewAgents({
    simulation_id: props.simulationId,
    interviews: [{

View on GitHub (pinned to b5b53acc57)

Solutions

  1. Select an agent in the agent list before sending, or switch the chat target back to report_agent.
  2. Disable the chat input/send button while chatTarget === 'agent' && !selectedAgent so the state is unreachable.
  3. When profiles are reloaded or the simulation changes, reset chatTarget to 'report_agent' and clear selectedAgent/selectedAgentIndex together.
  4. Validate selectedAgentIndex < profiles.length before sending, since the index is used to build the interview payload.

Example fix

// before
const sendToAgent = async (message) => {
  if (!selectedAgent.value || selectedAgentIndex.value === null) {
    throw new Error(t('step5.selectAgentFirst'))
  }

// after - block at the UI boundary so the throw never fires
const canChatWithAgent = computed(() =>
  chatTarget.value !== 'agent' || (selectedAgent.value !== null && selectedAgentIndex.value !== null)
)
// template: <input :disabled="!canChatWithAgent" ...>
const sendToAgent = async (message) => {
  if (!selectedAgent.value || selectedAgentIndex.value === null) {
    throw new Error(t('step5.selectAgentFirst'))
  }
Defensive patterns

Strategy: validation

Validate before calling

const canSendToAgent = computed(() =>
  chatTarget.value !== 'agent' ||
  (selectedAgent.value !== null && selectedAgentIndex.value !== null && selectedAgentIndex.value < profiles.value.length)
)
// template: <textarea :disabled="chatTarget === 'agent' && !canSendToAgent">

Type guard

function hasSelectedAgent(sel, idx, profiles) {
  return sel != null && idx !== null && Number.isInteger(idx) && idx >= 0 && idx < profiles.length
}

Prevention

When it happens

Trigger: chatTarget is 'agent' (single-agent mode) but the user never clicked an agent profile; the selected agent was removed after profiles reloaded (selection not reset together); or a keyboard/enter submission races the click that sets selectedAgent before the watcher runs.

Common situations: UI lets the user type and press Enter before selecting an agent (send button/input not disabled in agent mode); agent list refresh clears selectedAgent but leaves chatTarget on 'agent'; profile array re-indexed after a simulation reload while an old index stayed selected.

Related errors


AI-assisted analysis of 666ghj/MiroFish@b5b53acc57 (2026-08-14). Data as JSON: /api/errors/5b61a0cd1e419b26. Report an issue: GitHub.