vibe.assistant.services.question_session_state

QuestionSessionState - Single source of truth for question state management.

This class consolidates all question-related session state operations that were previously scattered across StreamTranslator, AssistantService, and raw session access.

QuestionSessionState

Manages question state during assistant interaction.

Responsibilities: - Track which questions have been asked (with labels and field names) - Track which questions have been answered - Compute unanswered questions from definitions vs current state - Clear question state between turns

Uses SessionAccessor pattern for testability and consistency with StreamTranslator.

__init__

__init__(session_accessor: SessionAccessor, question_definitions: dict[str, Any]) -> None

Initialize the question state manager.

Parameters:
  • session_accessor (SessionAccessor) –

    Accessor for reading/writing session state

  • question_definitions (dict[str, Any]) –

    Dict of predefined question definitions from template

register_asked

register_asked(question_id: str, label: str, field_name: str, tool_call_id: str, question_type: str | None = None) -> None

Register that a question was asked by the assistant.

Parameters:
  • question_id (str) –

    The question identifier (predefined ID or generated text)

  • label (str) –

    Display label for the question

  • field_name (str) –

    Form field name for the answer

  • tool_call_id (str) –

    Tool call ID that triggered this question

  • question_type (str | None, default: None ) –

    Optional question type identifier

get_question_labels

get_question_labels() -> dict[str, str]

Get mapping of field names to question labels.

Returns:
  • dict[str, str]

    Dict mapping field_name -> label

get_question_types

get_question_types() -> dict[str, str]

Get mapping of field names to question types.

Returns:
  • dict[str, str]

    Dict mapping field_name -> question type

get_tool_call_id

get_tool_call_id(field_name: str) -> str | None

Get the tool call ID for a given form field.

Parameters:
  • field_name (str) –

    Form field name

Returns:
  • str | None

    Tool call ID or None if not found

get_last_asked

get_last_asked() -> str | None

Get the label of the last question asked.

Returns:
  • str | None

    Label string or None if no questions asked

clear_for_new_turn

clear_for_new_turn() -> None

Clear question labels after processing answers.

Called after answers have been extracted to prepare for next turn.

clear_last_question_display

clear_last_question_display() -> None

Clear the last question label and user input display state.

Called after system question bubbles have been displayed.

get_unanswered_questions

get_unanswered_questions(current_state: dict[str, Any]) -> list[dict[str, Any]]

Get list of predefined questions that haven't been answered yet.

Parameters:
  • current_state (dict[str, Any]) –

    Current template variable values (NestedValue or dict)

Returns:
  • list[dict[str, Any]]

    List of question info dicts with 'id', 'label', and 'type' keys

store_user_input_for_display

store_user_input_for_display(user_input: dict[str, Any]) -> None

Store user input for display in chat bubbles.

Parameters:
  • user_input (dict[str, Any]) –

    The user's input data to display

get_user_input_for_display

get_user_input_for_display() -> dict[str, Any] | None

Get stored user input for display.

Returns:
  • dict[str, Any] | None

    User input dict or None

needs_system_question_bubbles

needs_system_question_bubbles(is_first_llm_turn: bool) -> bool

Check if system question bubbles need to be displayed.

Parameters:
  • is_first_llm_turn (bool) –

    Whether this is the first LLM turn

Returns:
  • bool

    True if bubbles should be injected

get_label_for_predefined

get_label_for_predefined(question_id: str) -> str

Get the display label for a predefined question.

Parameters:
  • question_id (str) –

    The question identifier

Returns:
  • str

    Label from definition, or question_id if not found