Interactive Spring Shell-based command-line interface for the Embabel Agent platform, providing terminal interaction, chat sessions, and agent management commands.
Learn how to handle and customize agent output in the terminal.
Create a terminal-based output channel for agent communication:
import com.embabel.agent.shell.TerminalServices
import com.embabel.agent.api.channel.OutputChannel
@Component
class MyService(
private val terminalServices: TerminalServices,
private val agentPlatform: AgentPlatform
) {
fun runAgentWithOutput() {
val outputChannel = terminalServices.outputChannel(agentPlatform)
// Use outputChannel with your agent execution
}
}The output channel handles various event types:
Displays messages with sender and content:
import com.embabel.agent.api.channel.MessageOutputChannelEvent
// Event format: "{sender}: {content}"
// Example: "Agent: Processing your request..."Automatically handles awaitables within messages.
Displays content events:
import com.embabel.agent.api.channel.ContentOutputChannelEvent
// Displays raw content dataDisplays progress updates with "▶" prefix:
import com.embabel.agent.api.channel.ProgressOutputChannelEvent
// Format: "▶ {progress message}"
// Example: "▶ Processing step 2 of 5..."Displays log messages with "🪵" prefix:
import com.embabel.agent.api.channel.LoggingOutputChannelEvent
// Format: "🪵 {log message}"
// Example: "🪵 Initialized agent platform"All output is automatically wrapped according to configured line length:
embabel:
agent:
shell:
lineLength: 140 # DefaultFormat agent process execution results for console display:
import com.embabel.agent.shell.formatProcessOutput
import com.embabel.agent.api.common.autonomy.AgentProcessExecution
import com.embabel.agent.spi.logging.ColorPalette
import com.fasterxml.jackson.databind.ObjectMapper
val formatted = formatProcessOutput(
result = executionResult,
colorPalette = myColorPalette,
objectMapper = objectMapper,
lineLength = 140
)
println(formatted)The formatted output includes:
Agent Process Info (verbose):
User Request:
You asked: {original intent}Formatted Output:
Cost Information (verbose):
Tool Statistics (verbose):
Different output types are formatted differently:
Content with text or data:
// If content contains "#" (markdown indicator):
// → Converted with markdownToConsole()
// Otherwise:
// → Wrapped to line lengthList of web resources:
Links:
1. {url}
Summary: {summary}
2. {url}
Summary: {summary}Any other output type:
{
"formatted": "as",
"pretty": "printed",
"json": true
}Convert Markdown text to ANSI-styled console output:
import com.embabel.agent.shell.markdownToConsole
val markdown = """
# Agent Report
The agent found **3 results**:
1. First result
2. Second result
3. Third result
See `agent.log` for details.
""".trimIndent()
val styled = markdownToConsole(markdown)
println(styled)| Markdown | ANSI Style | Code |
|---|---|---|
**bold** | Bold | \u001B[1m |
*italic* | Italic | \u001B[3m |
__underline__ | Underline | \u001B[4m |
~~strikethrough~~ | Strikethrough | \u001B[9m |
# H1 Header
## H2 Header
### H3 Header
Alternative H1
==============
Alternative H2
--------------All headers styled: Cyan bold
- Bulleted item
* Another bullet
1. Numbered item
2. Another numberBullets/numbers: Magenta bold List text: Regular
Inline code:
Use the `agent.execute()` methodStyle: Black text on gray background
Code blocks:
```kotlin
fun main() {
println("Hello")
}
```Language: Italic bold Code: Black on gray background
> Important note hereStyle: Italic, blue, bold
[Link text](https://example.com)
Text/alt: Blue URL: Blue underlined
Colors used by markdownToConsole:
| Color | Code | Usage |
|---|---|---|
| Bold | \u001B[1m | Emphasis, headers |
| Italic | \u001B[3m | Italic text, code lang |
| Underline | \u001B[4m | Underlined text, URLs |
| Strikethrough | \u001B[9m | Strikethrough text |
| Blue | \u001B[34m | Links, blockquotes |
| Magenta | \u001B[35m | List bullets/numbers |
| Cyan | \u001B[36m | Headers |
| Black on gray | \u001B[57;107m | Code blocks |
| Reset | \u001B[0m, \u001B[22m | End styling |
The markdown converter has some limitations:
These limitations are acceptable for typical agent output formatting.
Color palettes define color schemes for output:
import com.embabel.agent.spi.logging.ColorPalette
import com.embabel.agent.spi.logging.DefaultColorPalette
// Default palette
val defaultPalette = DefaultColorPalette()
// Use with output formatting
val formatted = formatProcessOutput(
result = executionResult,
colorPalette = defaultPalette,
objectMapper = objectMapper,
lineLength = 140
)Personality-themed color palettes:
import com.embabel.agent.shell.personality.starwars.StarWarsColorPalette
import com.embabel.agent.shell.personality.severance.LumonColorPalette
import com.embabel.agent.shell.personality.hitchhiker.HitchhikerColorPalette
import com.embabel.agent.shell.personality.colossus.ColossusColorPalette
import com.embabel.agent.shell.personality.montypython.MontyPythonColorPalette
// Example usage
val colorPalette = StarWarsColorPalette()See Customization Guide for details on each palette.
The terminal services automatically handle interactive elements:
import com.embabel.agent.shell.TerminalServices
import com.embabel.agent.api.common.autonomy.Awaitable
val terminalServices: TerminalServices = ...
val awaitable: Awaitable<*, *> = ... // from agent process
val response = terminalServices.handleAwaitable(awaitable)
if (response != null) {
// User provided response
awaitable.onResponse(response, agentProcess)
} else {
// User cancelled
}Simple yes/no confirmations:
import com.embabel.agent.shell.TerminalServices
val terminalServices: TerminalServices = ...
if (terminalServices.confirm("Do you want to continue?")) {
// User confirmed (typed "y")
} else {
// User declined
}Interactive forms with validation:
import com.embabel.agent.api.common.autonomy.FormBindingRequest
import com.embabel.agent.form.TextField
// FormBindingRequest with text fields is automatically handled
// User is prompted for each field with validationSupported form controls:
Print text without interfering with input prompt:
import com.embabel.agent.shell.TerminalServices
val terminalServices: TerminalServices = ...
terminalServices.print("Processing request...")
terminalServices.print("Step 1 complete.")Uses JLine's printAbove to maintain input state while displaying information.
Create a custom output channel implementation:
import com.embabel.agent.api.channel.OutputChannel
import com.embabel.agent.api.channel.OutputChannelEvent
import com.embabel.agent.api.channel.MessageOutputChannelEvent
class MyCustomOutputChannel : OutputChannel {
override fun send(event: OutputChannelEvent) {
when (event) {
is MessageOutputChannelEvent -> {
// Custom message handling
println("[${event.sender}] ${event.content}")
}
// Handle other event types
}
}
}Combine terminal output with other output destinations:
class MultiOutputChannel(
private val channels: List<OutputChannel>
) : OutputChannel {
override fun send(event: OutputChannelEvent) {
channels.forEach { it.send(event) }
}
}
val terminalChannel = terminalServices.outputChannel(agentPlatform)
val logChannel = LoggingOutputChannel()
val multiChannel = MultiOutputChannel(listOf(terminalChannel, logChannel))Configure maximum line length for text wrapping:
embabel:
agent:
shell:
lineLength: 120 # Default: 140Affects:
Control verbosity of output in code:
// Process options control what's shown
val processOptions = ProcessOptions(
showPrompts = true, // Show LLM prompts
showLlmResponses = true, // Show LLM responses
debug = true, // Show debug info
showPlanning = true // Show planning details
)Check line length configuration:
embabel:
agent:
shell:
lineLength: 140Ensure content contains "#" marker or call markdownToConsole explicitly:
val content = result.content
val styled = if (content.contains("#")) {
markdownToConsole(content)
} else {
content
}Terminal may not support ANSI escape codes. Try:
echo -e "\u001B[31mRed\u001B[0m"Verify output channel is properly connected:
val outputChannel = terminalServices.outputChannel(agentPlatform)
// Pass outputChannel to agent executiontessl i tessl/maven-com-embabel-agent--embabel-agent-shell@0.3.0