Skip to content

F083: Interactive Conversation Mode (Breaking Change) #313

@pocky

Description

@pocky

F083: Interactive Conversation Mode (Breaking Change)

Scope

In Scope

  • Refactor ConversationConfig to only retain ContinueFrom
  • Remove automated conversation loop fields (MaxTurns, StopCondition, InjectContext, Strategy, MaxContextTokens)
  • Remove InitialPrompt from AgentConfigPrompt serves as first message
  • Add UserInputReader port with CLI stdin implementation
  • Refactor ConversationManager to interactive user→agent→user loop
  • Add StopReasonUserExit stop reason, remove obsolete stop reasons
  • Update YAML validation to reject removed fields
  • Update documentation and changelog with migration guide

Out of Scope

  • Readline/history support for stdin input (basic bufio.Scanner only)
  • Rich TUI input (multiline editing, autocomplete)
  • Automated conversation mode replacement (no headless multi-turn)
  • Timeout-based auto-exit from conversation

Deferred

Item Rationale Follow-up
Readline/history for input Adds dependency, basic stdin sufficient for v0.7.0 future
Validation that mode: conversation not in parallel steps Separate validation concern F084 or future
Headless multi-turn mode (agent-to-agent) Requires different design; current automated mode was broken by design future

User Stories

US1: Interactive Conversation with an Agent (P1 - Must Have)

As a workflow user,
I want to have a back-and-forth conversation with an AI agent within a workflow step,
So that I can iteratively refine outputs, ask follow-up questions, and get contextual assistance without restarting the workflow.

Why this priority: This is the core value proposition. Without interactive input, conversation mode is just a multi-shot step with extra complexity. The user-in-the-loop is what makes conversation mode useful.

Acceptance Scenarios:

  1. Given a workflow with a step mode: conversation and prompt: "Hello", When I run the workflow, Then the agent receives "Hello", streams a response to the terminal, and I see a > prompt waiting for my input.
  2. Given the agent has responded and I see the > prompt, When I type a message and press Enter, Then the agent receives my message and streams its response to the terminal.
  3. Given the agent has responded and I see the > prompt, When I press Enter without typing anything, Then the conversation ends and the step completes with the last assistant response as output.
  4. Given a conversation step with system_prompt configured, When the step starts, Then the system prompt is sent to the provider on the first turn before the user prompt.

Independent Test: Run awf run on a workflow with a conversation step using a mock UserInputReader that sends two messages then an empty string. Verify three turns execute, output equals last assistant response, and stop reason is UserExit.

US2: Resume a Previous Conversation (P2 - Should Have)

As a workflow author,
I want to continue a conversation from a previous step using continue_from,
So that I can build multi-phase workflows where context carries across steps.

Why this priority: ContinueFrom is retained functionality that enables workflow composition. Not strictly needed for MVP interactive mode but critical for real-world workflow design.

Acceptance Scenarios:

  1. Given step A completed a conversation with session ID stored in state, When step B has continue_from: A, Then step B resumes the same provider session and the agent retains context from step A.
  2. Given step B has continue_from: A but step A has no session ID in state, When step B starts, Then the conversation starts fresh with a warning logged (graceful fallback).

Independent Test: Run a two-step workflow where step 2 uses continue_from: step1. Verify the provider receives the session ID from step 1's state.

US3: Context Cancellation Stops Conversation (P3 - Nice to Have)

As a workflow user,
I want Ctrl+C to cleanly exit the conversation and the workflow,
So that I can abort without leaving orphan processes or corrupted state.

Why this priority: Graceful cancellation is important for UX but the existing context propagation (B008) already handles most of this. This story ensures the ReadInput call respects context.

Acceptance Scenarios:

  1. Given a conversation step is waiting for user input at the > prompt, When the context is cancelled (Ctrl+C or step timeout), Then ReadInput returns a context error and the conversation stops with state persisted.

Independent Test: Use a mock UserInputReader that blocks until context cancellation. Cancel context after 100ms. Verify the conversation exits with a context error, not a hang.

Edge Cases

  • What happens when stdin is not a terminal (piped input)? The UserInputReader reads until EOF; each line is a turn, EOF exits.
  • What happens when the provider returns an error mid-conversation? The conversation stops, error is returned, last successful response is preserved in state.
  • What happens when prompt is empty? Validation rejects mode: conversation without a non-empty prompt (first message is required).
  • What happens when a workflow YAML still uses removed fields (max_turns, stop_condition, etc.)? YAML parsing fails with a clear error listing the removed field and migration guidance.

Requirements

Functional Requirements

  • FR-001: System MUST remove MaxTurns, StopCondition, InjectContext, Strategy, and MaxContextTokens from ConversationConfig
  • FR-002: System MUST remove InitialPrompt from AgentConfig; Prompt field serves as the first conversation message
  • FR-003: System MUST add StopReasonUserExit constant and remove StopReasonCondition, StopReasonMaxTurns, StopReasonMaxTokens
  • FR-004: System MUST define a UserInputReader port interface with ReadInput(ctx context.Context) (string, error)
  • FR-005: System MUST provide a CLI implementation of UserInputReader that reads from stdin with a > prompt prefix
  • FR-006: ConversationManager.ExecuteConversation MUST implement the loop: send prompt → stream response → read user input → repeat until empty input
  • FR-007: Empty user input (Enter with no text) MUST terminate the conversation with StopReasonUserExit
  • FR-008: The step result output MUST be the last assistant response text
  • FR-009: ContinueFrom MUST remain functional for resuming provider sessions across steps
  • FR-010: YAML validation MUST reject removed fields (max_turns, stop_condition, inject_context, strategy, max_context_tokens, initial_prompt) with a clear error message
  • FR-011: UserInputReader.ReadInput MUST respect context cancellation

Non-Functional Requirements

  • NFR-001: Conversation manager code size must decrease from ~230 lines to under 150 lines (complexity reduction)
  • NFR-002: No secrets exposed in conversation streaming output (existing secret masking applies)
  • NFR-003: make lint and make lint-arch must pass with zero violations
  • NFR-004: All existing non-conversation tests must continue to pass without modification (beyond fixture updates for removed fields)

Success Criteria

  • SC-001: User can have a multi-turn interactive conversation within a workflow step, typing messages and receiving streamed responses
  • SC-002: Empty Enter terminates the conversation in under 100ms
  • SC-003: Workflows using removed YAML fields fail at parse time with an actionable error message naming the removed field
  • SC-004: ContinueFrom successfully resumes a prior conversation session across steps
  • SC-005: All unit and integration tests pass, including new tests with mock UserInputReader

Key Entities

Entity Description Key Attributes
ConversationConfig Simplified conversation configuration ContinueFrom string (only remaining field)
UserInputReader Port for reading user input between turns ReadInput(ctx) (string, error)
StdinInputReader CLI implementation reading from os.Stdin prompt prefix > , bufio.Scanner
StopReason Why a conversation ended StopReasonUserExit (new), StopReasonError (existing)
ConversationState Turn history and session tracking Turns, SessionID, TotalTokens (unchanged)

Assumptions

  • The user's terminal supports basic stdin reading (no raw mode required)
  • Provider session resume via ExecuteConversation continues to work as implemented in F079/F080
  • F082 streaming display output is available and functional for showing agent responses in real-time
  • Piped stdin (non-TTY) is an acceptable input source — each line becomes a turn, EOF exits
  • The Prompt field in AgentConfig already supports interpolation and will serve as the first message without changes to resolution logic

Metadata

  • Status: backlog
  • Version: v0.7.0
  • Priority: high
  • Estimation: M

Dependencies

  • Blocked by: F080 (base CLI provider), F082 (streaming display output)
  • Unblocks: none

Clarifications

Section populated during clarify step with resolved ambiguities.

Notes

  • Breaking change: no backward compatibility shim. Workflows using removed fields will fail at YAML parse time.
  • The evaluateTurnCompletion() method in ConversationManager is deleted entirely — the loop is now trivial: send/receive/read/repeat.
  • AgentConfig.InitialPrompt removal is clean: Prompt already exists and is resolved via interpolation. InitialPrompt was redundant.
  • The UserInputReader port enables test mocking without stdin hacks. Mock implementation returns pre-configured responses in sequence.
  • Files affected: conversation.go, agent_config.go, ports/user_input.go (new), conversation_manager.go, conversation_manager_test.go, ui/stdin_input_reader.go (new), run.go, yaml_mapper.go, docs, changelog.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions