Skip to content

Agent and Action Termination

Embabel provides mechanisms to terminate agents and actions early, either gracefully (at the next checkpoint) or immediately. This is useful for scenarios like user cancellation, timeout handling, resource limits, or ctitical error handling.

| Mechanism | When to Use | Behavior | | --- | --- | --- | | Graceful (Signal) | “Let me finish my work, then stop” - side effects need to complete | Terminates at next checkpoint; current operation completes normally | | Immediate (Exception) | “Stop now, nothing left to do” - no further processing needed | Terminates immediately; nothing executes after the exception being thrown |

Agent termination stops the entire agent process. The process status becomes TERMINATED.

Use terminateAgent() when the current operation should complete before stopping. The agent terminates before the next checkpoint tick.

// Signal: "Let me finish my work, then stop the agent"
@LlmTool(description = "Save all pending work and shutdown")
fun saveAndShutdown(ctx: ProcessContext): String {
repository.saveAll(pendingRecords) // side effect completes
ctx.terminateAgent("All work saved, shutting down")
return "Saved ${pendingRecords.size} records" // tool finishes normally
}

Use TerminateAgentException when the agent must stop immediately. No further tool calls or actions execute.

// Exception: "Stop now, nothing left to do"
@LlmTool(description = "Validate critical prerequisites")
fun validatePrerequisites(): String {
if (!authService.hasRequiredPermissions()) {
throw TerminateAgentException("Missing required permissions")
// nothing after this runs
}
return "Prerequisites validated"
}

Action termination stops only the current action. The agent continues with the next planned action. This is useful for skipping problematic steps while allowing the overall goal to proceed.

Use terminateAction() when the current tool call should complete before stopping the action. The action terminates between tool calls.

// Signal: "Let me finish my work, then stop"
@LlmTool(description = "Save and shutdown")
fun saveAndStop(ctx: ProcessContext): String {
customerRepository.save(record) // side effect completes
ctx.terminateAction("Save complete, no more work needed")
return "Saved" // tool finishes normally
}

Use TerminateActionException when the action must stop immediately. Remaining tool calls in the current batch are skipped.

// Exception: "Stop now, nothing left to do"
@LlmTool(description = "Check service health")
fun checkHealth(): String {
if (!mcpClient.isConnected("required_service")) {
throw TerminateActionException("Service unavailable")
// nothing after this runs
}
return "Healthy"
}

Both TerminateAgentException and TerminateActionException extend TerminationException, allowing you to catch them together:

try {
tool.execute()
} catch (e: TerminationException) {
logger.info("Terminated: ${e.reason}")
// Handle both agent and action termination
}

| Scope | Mechanism | Method/Exception | Use Case | | --- | --- | --- | --- | | Agent | Graceful | processContext.terminateAgent(reason) | “Finish current work, then stop agent” | | Agent | Immediate | throw TerminateAgentException(reason) | “Stop now - critical error, no recovery” | | Action | Graceful | processContext.terminateAction(reason) | “Finish current tool, then stop action” | | Action | Immediate | throw TerminateActionException(reason) | “Stop now - try different approach” |