CtrlK
CommunityDocumentationLog inGet started
Tessl Logo

tessl/maven-com-embabel-agent--embabel-agent-shell

Interactive Spring Shell-based command-line interface for the Embabel Agent platform, providing terminal interaction, chat sessions, and agent management commands.

Overview
Eval results
Files

output-handling.mddocs/guides/

Output Handling Guide

Learn how to handle and customize agent output in the terminal.

Output Channels

Creating an Output Channel

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
    }
}

Output Event Types

The output channel handles various event types:

MessageOutputChannelEvent

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.

ContentOutputChannelEvent

Displays content events:

import com.embabel.agent.api.channel.ContentOutputChannelEvent

// Displays raw content data

ProgressOutputChannelEvent

Displays progress updates with "▶" prefix:

import com.embabel.agent.api.channel.ProgressOutputChannelEvent

// Format: "▶ {progress message}"
// Example: "▶ Processing step 2 of 5..."

LoggingOutputChannelEvent

Displays log messages with "🪵" prefix:

import com.embabel.agent.api.channel.LoggingOutputChannelEvent

// Format: "🪵 {log message}"
// Example: "🪵 Initialized agent platform"

Text Wrapping

All output is automatically wrapped according to configured line length:

embabel:
  agent:
    shell:
      lineLength: 140  # Default

Formatting Process Output

Basic Formatting

Format 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)

Output Format Sections

The formatted output includes:

  1. Agent Process Info (verbose):

    • Process ID
    • Agent details
    • Goal information
  2. User Request:

    You asked: {original intent}
  3. Formatted Output:

    • Content with appropriate formatting
    • Markdown converted to ANSI styles
    • JSON pretty-printed
    • Text wrapped to line length
  4. Cost Information (verbose):

    • Token usage
    • API costs
    • Model information
  5. Tool Statistics (verbose):

    • Tool call counts
    • Execution times

Output Type Handling

Different output types are formatted differently:

HasContent Output

Content with text or data:

// If content contains "#" (markdown indicator):
// → Converted with markdownToConsole()
// Otherwise:
// → Wrapped to line length

InternetResources Output

List of web resources:

Links:
1. {url}
   Summary: {summary}

2. {url}
   Summary: {summary}

Other Types

Any other output type:

{
  "formatted": "as",
  "pretty": "printed",
  "json": true
}

Markdown to Console Conversion

Basic Usage

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)

Supported Markdown Features

Text Styling

MarkdownANSI StyleCode
**bold**Bold\u001B[1m
*italic*Italic\u001B[3m
__underline__Underline\u001B[4m
~~strikethrough~~Strikethrough\u001B[9m

Headers

# H1 Header
## H2 Header
### H3 Header

Alternative H1
==============

Alternative H2
--------------

All headers styled: Cyan bold

Lists

- Bulleted item
* Another bullet
1. Numbered item
2. Another number

Bullets/numbers: Magenta bold List text: Regular

Code

Inline code:

Use the `agent.execute()` method

Style: Black text on gray background

Code blocks:

```kotlin
fun main() {
    println("Hello")
}
```

Language: Italic bold Code: Black on gray background

Blockquotes

> Important note here

Style: Italic, blue, bold

Links and Images

[Link text](https://example.com)
![Image alt](image.png)

Text/alt: Blue URL: Blue underlined

ANSI Color Reference

Colors used by markdownToConsole:

ColorCodeUsage
Bold\u001B[1mEmphasis, headers
Italic\u001B[3mItalic text, code lang
Underline\u001B[4mUnderlined text, URLs
Strikethrough\u001B[9mStrikethrough text
Blue\u001B[34mLinks, blockquotes
Magenta\u001B[35mList bullets/numbers
Cyan\u001B[36mHeaders
Black on gray\u001B[57;107mCode blocks
Reset\u001B[0m, \u001B[22mEnd styling

Limitations

The markdown converter has some limitations:

  • Simple regex-based parsing (not a full markdown parser)
  • Nested formatting may not work correctly
  • No support for tables
  • No support for definition lists
  • No support for advanced markdown features
  • Code block syntax highlighting is minimal

These limitations are acceptable for typical agent output formatting.

Color Palettes

Using Color Palettes

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
)

Available Color Palettes

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.

Interactive Elements

Handling Awaitables

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
}

Confirmation Dialogs

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
}

Form Handling

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 validation

Supported form controls:

  • TextField: Text input with validation (required, maxLength, pattern)
  • Button: Submit button
  • Other types: Display "Unsupported control type" message

Terminal Printing

Direct Printing

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.

Advanced Output Patterns

Custom Output Channel

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
        }
    }
}

Combining Output Channels

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))

Output Configuration

Line Length

Configure maximum line length for text wrapping:

embabel:
  agent:
    shell:
      lineLength: 120  # Default: 140

Affects:

  • Text wrapping in output channels
  • Formatted process output
  • Chat session output

Verbose Mode

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
)

Troubleshooting

Output Not Wrapping

Check line length configuration:

embabel:
  agent:
    shell:
      lineLength: 140

Markdown Not Rendering

Ensure content contains "#" marker or call markdownToConsole explicitly:

val content = result.content
val styled = if (content.contains("#")) {
    markdownToConsole(content)
} else {
    content
}

ANSI Codes Displayed as Text

Terminal may not support ANSI escape codes. Try:

  • Using a modern terminal emulator
  • Checking terminal TERM environment variable
  • Testing with simple ANSI code: echo -e "\u001B[31mRed\u001B[0m"

Output Events Not Appearing

Verify output channel is properly connected:

val outputChannel = terminalServices.outputChannel(agentPlatform)
// Pass outputChannel to agent execution

Related Documentation

tessl i tessl/maven-com-embabel-agent--embabel-agent-shell@0.3.0

docs

guides

chat-sessions.md

customization.md

output-handling.md

task-execution.md

examples.md

index.md

quickstart.md

troubleshooting.md

tile.json