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 AgentConfig — Prompt 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:
- 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.
- 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.
- 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.
- 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:
- 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.
- 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:
- 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.
F083: Interactive Conversation Mode (Breaking Change)
Scope
In Scope
ConversationConfigto only retainContinueFromMaxTurns,StopCondition,InjectContext,Strategy,MaxContextTokens)InitialPromptfromAgentConfig—Promptserves as first messageUserInputReaderport with CLI stdin implementationConversationManagerto interactive user→agent→user loopStopReasonUserExitstop reason, remove obsolete stop reasonsOut of Scope
bufio.Scanneronly)Deferred
mode: conversationnot in parallel stepsUser 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:
mode: conversationandprompt: "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.>prompt, When I type a message and press Enter, Then the agent receives my message and streams its response to the terminal.>prompt, When I press Enter without typing anything, Then the conversation ends and the step completes with the last assistant response as output.system_promptconfigured, 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 runon a workflow with a conversation step using a mockUserInputReaderthat sends two messages then an empty string. Verify three turns execute, output equals last assistant response, and stop reason isUserExit.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:
ContinueFromis retained functionality that enables workflow composition. Not strictly needed for MVP interactive mode but critical for real-world workflow design.Acceptance Scenarios:
continue_from: A, Then step B resumes the same provider session and the agent retains context from step A.continue_from: Abut 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
ReadInputcall respects context.Acceptance Scenarios:
>prompt, When the context is cancelled (Ctrl+C or step timeout), ThenReadInputreturns a context error and the conversation stops with state persisted.Independent Test: Use a mock
UserInputReaderthat blocks until context cancellation. Cancel context after 100ms. Verify the conversation exits with a context error, not a hang.Edge Cases
UserInputReaderreads until EOF; each line is a turn, EOF exits.promptis empty? Validation rejectsmode: conversationwithout a non-emptyprompt(first message is required).max_turns,stop_condition, etc.)? YAML parsing fails with a clear error listing the removed field and migration guidance.Requirements
Functional Requirements
MaxTurns,StopCondition,InjectContext,Strategy, andMaxContextTokensfromConversationConfigInitialPromptfromAgentConfig;Promptfield serves as the first conversation messageStopReasonUserExitconstant and removeStopReasonCondition,StopReasonMaxTurns,StopReasonMaxTokensUserInputReaderport interface withReadInput(ctx context.Context) (string, error)UserInputReaderthat reads from stdin with a>prompt prefixConversationManager.ExecuteConversationMUST implement the loop: send prompt → stream response → read user input → repeat until empty inputStopReasonUserExitContinueFromMUST remain functional for resuming provider sessions across stepsmax_turns,stop_condition,inject_context,strategy,max_context_tokens,initial_prompt) with a clear error messageUserInputReader.ReadInputMUST respect context cancellationNon-Functional Requirements
make lintandmake lint-archmust pass with zero violationsSuccess Criteria
ContinueFromsuccessfully resumes a prior conversation session across stepsUserInputReaderKey Entities
ConversationConfigContinueFrom string(only remaining field)UserInputReaderReadInput(ctx) (string, error)StdinInputReader>, bufio.ScannerStopReasonStopReasonUserExit(new),StopReasonError(existing)ConversationStateTurns,SessionID,TotalTokens(unchanged)Assumptions
ExecuteConversationcontinues to work as implemented in F079/F080Promptfield inAgentConfigalready supports interpolation and will serve as the first message without changes to resolution logicMetadata
Dependencies
Clarifications
Section populated during clarify step with resolved ambiguities.
Notes
evaluateTurnCompletion()method inConversationManageris deleted entirely — the loop is now trivial: send/receive/read/repeat.AgentConfig.InitialPromptremoval is clean:Promptalready exists and is resolved via interpolation.InitialPromptwas redundant.UserInputReaderport enables test mocking without stdin hacks. Mock implementation returns pre-configured responses in sequence.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.