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

terminal-services.mddocs/reference/

Terminal Services

The TerminalServices class provides terminal interaction capabilities including chat session management, form handling, confirmation dialogs, and output channels for agent communication.

Import

import com.embabel.agent.shell.TerminalServices

Component Declaration

@Component
class TerminalServices(
    private val terminal: Terminal,
    private val shellProperties: ShellProperties
) : GoalChoiceApprover

The class is automatically instantiated by Spring when included in your application's component scan. It implements the GoalChoiceApprover interface for human-in-the-loop goal approval.

Chat Session Management

Run Chat Session

Run an interactive chat session in the terminal.

fun chat(
    chatSession: ChatSession,
    welcome: String? = null,
    colorPalette: ColorPalette = DefaultColorPalette()
): String

Parameters:

  • chatSession: The chat session to run
  • welcome: Optional welcome message to display (default: null)
  • colorPalette: Color scheme for terminal output (default: DefaultColorPalette())

Returns: "Conversation finished" when the session ends

Java Interoperability: This method is annotated with @JvmOverloads, allowing Java callers to omit the optional welcome and colorPalette parameters. Java code can call this method as:

  • chat(chatSession) - uses default values for both optional parameters
  • chat(chatSession, welcome) - uses default value for colorPalette
  • chat(chatSession, welcome, colorPalette) - provides all parameters explicitly

Behavior:

  • Displays welcome message if provided
  • Shows session start message with conversation ID
  • Prompts user with "You: " in highlighted color
  • Processes user input through the chat session
  • Type "exit" (case-insensitive) to end the session
  • Type "/help" for available commands

Usage:

import com.embabel.agent.shell.TerminalServices
import com.embabel.chat.ChatSession

val terminalServices: TerminalServices = ... // injected
val chatSession: ChatSession = ... // created from chatbot

val result = terminalServices.chat(
    chatSession = chatSession,
    welcome = "Welcome to the agent chat!",
    colorPalette = myColorPalette
)

Output Channel

Create Output Channel

Create a terminal-based output channel for agent communication.

fun outputChannel(agentPlatform: AgentPlatform): OutputChannel

Parameters:

  • agentPlatform: The agent platform to use for process lookup

Returns: OutputChannel implementation that sends events to the terminal

Behavior:

  • Creates a TerminalOutputChannel instance
  • Handles various output channel events:
    • MessageOutputChannelEvent: Displays messages with sender and content, handles awaitables
    • ContentOutputChannelEvent: Displays content events
    • ProgressOutputChannelEvent: Displays progress with "▶" prefix
    • LoggingOutputChannelEvent: Displays log messages with "🪵" prefix
  • Automatically handles awaitable responses in messages
  • Wraps text according to configured line length

Usage:

import com.embabel.agent.shell.TerminalServices
import com.embabel.agent.core.AgentPlatform
import com.embabel.agent.api.channel.OutputChannel

val terminalServices: TerminalServices = ... // injected
val agentPlatform: AgentPlatform = ... // injected

val outputChannel = terminalServices.outputChannel(agentPlatform)
// Use outputChannel for agent communication

Form Handling

Handle Awaitable

Handle awaitable requests (confirmations, forms) from agent processes.

fun handleAwaitable(awaitable: Awaitable<*, *>): AwaitableResponse?

Parameters:

  • awaitable: The awaitable to handle (ConfirmationRequest or FormBindingRequest)

Returns: AwaitableResponse if operation completes, null if cancelled by user

Supported Awaitable Types:

  • ConfirmationRequest: Prompts user for yes/no confirmation
  • FormBindingRequest: Prompts user to fill out form fields

Form Field Handling:

  • TextField: Text input with validation
    • Required field validation (if control.required is true)
    • Maximum length validation (if control.maxLength is specified)
    • Pattern validation (if control.validationPattern is specified)
    • Custom validation messages (via control.validationMessage)
  • Button: Submit button (partial implementation)
  • Other control types: Display "Unsupported control type" message

Form Submission:

  • User is prompted to confirm submission with "Submit form? (y/n): "
  • Returns null if user chooses not to submit
  • Returns FormResponse with form submission data if user confirms

Usage:

import com.embabel.agent.shell.TerminalServices
import com.embabel.agent.api.common.autonomy.Awaitable
import com.embabel.agent.core.AgentProcess
import com.embabel.agent.api.common.autonomy.AwaitableResponse

val terminalServices: TerminalServices = ... // injected
val awaitable: Awaitable<*, *> = ... // from agent process

val response = terminalServices.handleAwaitable(awaitable)
if (response != null) {
    // Process the response
    awaitable.onResponse(response, agentProcess)
} else {
    // User cancelled
}

Confirmation Dialogs

Show Confirmation

Display a confirmation dialog and get user response.

fun confirm(message: String): Boolean

Parameters:

  • message: The confirmation message to display

Returns: true if user types "y" (case-insensitive), false otherwise

Behavior:

  • Displays message followed by " (y/n): " in yellow
  • Reads user input
  • Returns true only if input is "y" (case-insensitive)

Usage:

import com.embabel.agent.shell.TerminalServices

val terminalServices: TerminalServices = ... // injected

if (terminalServices.confirm("Do you want to continue?")) {
    // User confirmed
} else {
    // User declined
}

Printing

Print to Terminal

Print text to the terminal.

fun print(what: String): Unit

Parameters:

  • what: The text to print

Behavior:

  • Uses JLine's printAbove to display text without interfering with input prompt
  • Useful for displaying information while maintaining input state

Usage:

import com.embabel.agent.shell.TerminalServices

val terminalServices: TerminalServices = ... // injected

terminalServices.print("Processing request...")

Logging Management

Redirect Logging to File

Redirect all logging output to a file and return a function to restore original configuration.

fun redirectLoggingToFile(filename: String, dir: String): () -> Unit

Parameters:

  • filename: Name for the log file (without extension)
  • dir: Directory where logs subdirectory will be created

Returns: Function that restores original logging configuration when called

Behavior:

  • Detaches all current appenders from root logger
  • Creates logs directory in specified dir if it doesn't exist
  • Creates file appender writing to logs/{filename}.log
  • Configures log pattern: %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n
  • Prints message indicating log redirection
  • Returned function re-attaches original appenders and prints restoration message

Usage:

import com.embabel.agent.shell.TerminalServices

val terminalServices: TerminalServices = ... // injected

val restoreLogging = terminalServices.redirectLoggingToFile(
    filename = "chat-session",
    dir = System.getProperty("user.dir")
)

try {
    // Do work with logs redirected to file
    runChatSession()
} finally {
    // Restore original logging
    restoreLogging()
}

Goal Choice Approval

Approve Goal Choice

Implement human-in-the-loop goal choice approval.

override fun approve(goalChoiceApprovalRequest: GoalChoiceApprovalRequest): GoalChoiceApprovalResponse

Parameters:

  • goalChoiceApprovalRequest: Request containing goal to approve

Returns: GoalChoiceApproved if user confirms, GoalChoiceNotApproved otherwise

Behavior:

  • Displays confirmation dialog: "Do you approve this goal: {goal.description}?"
  • If user confirms (types "y"):
    • Returns GoalChoiceApproved with the request
  • If user declines:
    • Returns GoalChoiceNotApproved with reason "User said now" [sic]

Usage: This method is called automatically by the agent platform when human approval is required for goal selection. Typically used by passing the TerminalServices instance as a GoalChoiceApprover:

import com.embabel.agent.shell.TerminalServices
import com.embabel.agent.api.common.autonomy.Autonomy

val terminalServices: TerminalServices = ... // injected
val autonomy: Autonomy = ... // injected

val goalSeeker = autonomy.createGoalSeeker(
    intent = "Find news about AI",
    agentScope = agentPlatform,
    goalChoiceApprover = terminalServices, // Uses TerminalServices as approver
    goalSelectionOptions = GoalSelectionOptions()
)

Inner Class: TerminalOutputChannel

The TerminalOutputChannel inner class implements OutputChannel for terminal-based agent communication. It is created internally by the outputChannel() method and handles various event types:

private inner class TerminalOutputChannel(
    private val agentPlatform: AgentPlatform,
    private val colorPalette: ColorPalette = DefaultColorPalette()
) : OutputChannel {
    override fun send(event: OutputChannelEvent)
}

Event Types:

  • MessageOutputChannelEvent: Formats and displays messages with sender and content
  • ContentOutputChannelEvent: Displays content events
  • ProgressOutputChannelEvent: Displays progress messages with "▶" prefix
  • LoggingOutputChannelEvent: Displays log messages with "🪵" prefix

The output channel automatically wraps text according to shellProperties.lineLength.

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

docs

examples.md

index.md

quickstart.md

troubleshooting.md

tile.json