Skip to content

fix(ai): agent nodes drop Question.metadata when emitting an Answer #1748

Description

@nihalnihalani

Context

Found while addressing review feedback on #683. Splitting it out rather than widening that PR, for a reason given below.

#683 established the contract that a node which answers a question carries that question's metadata onto the Answer it emits, so an evaluator downstream can still find the reference it should be scored against. It applied that at two sites:

  • packages/ai/src/ai/common/llm_base.py:98,103
  • packages/ai/src/ai/common/chat.py:719,740

Problem

packages/ai/src/ai/common/agent/agent.py — the emit_answers_lane block in run_agent, around :233 — builds its Answer and writes it without merging question.metadata:

answer = Answer(expectJson=False)
answer.setAnswer(answer_payload.get('content', ''))
iInstance.instance.writeAnswers(answer)

question is in scope (it is a required keyword argument of run_agent, :92).

This is one shared site covering all six agent nodes:

  • agent_crewai/crewai_agent, agent_crewai/crewai_manager
  • agent_deepagent/deepagent_agent
  • agent_langchain
  • agent_llamaindex
  • agent_rocketride

Impact

eval_cobalt cannot score an agent's output. "Evaluate my agent" is an obvious use of the evaluation nodes added in #683, and today it silently produces cobalt_score: 0.0 — the same failure mode #683 fixed for the prompt node, at a different hop.

Fix

One line, plus one import:

# packages/ai/src/ai/common/agent/agent.py:25
from ai.common.utils import merge_metadata, safe_str

# in run_agent, before writeAnswers
merge_metadata(answer, getattr(question, 'metadata', None))

Why this was not done in #683

It needs a test that carries a reference across the agent hop, and that is not cheap to write honestly. AgentBase.run_agent pulls in AgentHostServices and ToolDescriptor from rocketlib and performs tool discovery, so an offline test means rebuilding a good chunk of the engine surface from stubs.

@asclearuc's blocking note on #683 was that all 175 tests exercised each node in isolation behind mocks, and that this is precisely why the metadata bug shipped green for four review rounds. Adding a second untested cross-node metadata fix in the same PR would have repeated that mistake. This deserves a test built on something more real than a stub tower.

Out of scope for this issue

Other terminal nodes also emit Answers without metadata, but they synthesize an answer from query results rather than answering the question, so each needs its own judgement call:

  • packages/ai/src/ai/common/database/db_instance_base.py:652 (postgres/mysql/clickhouse)
  • packages/ai/src/ai/common/graph/graph_instance_base.py:498,537, nodes/src/nodes/graph_arango/IInstance.py:243
  • nodes/src/nodes/rerank_cohere/IInstance.py:128-131 (also terminates the questions lane entirely)
  • nodes/src/nodes/search_exa/exa_search.py:114-115 (forwards the question correctly; only its Answer lacks metadata)
  • vector-store answers lane, packages/ai/src/ai/common/store/document_store.py:373 (questions lane forwards correctly, so RAG → LLM → eval works today)

Refs #683, #1747

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions