fix: emit ToolExecutionCompleted/Failed/Rejected events after tool dispatch
ToolInvocationRequestedEvent was emitted but the corresponding outcome events were never emitted, so the TUI permanently showed tools as RUNNING. Now the orchestrator closes every tool invocation with the appropriate event: - ToolExecutionCompletedEvent (Success path) - ToolExecutionFailedEvent (Failure path) - ToolExecutionRejectedEvent (approval denied path)
This commit is contained in:
+37
-3
@@ -29,7 +29,11 @@ import com.correx.core.events.events.NewEvent
|
||||
import com.correx.core.events.events.OrchestrationPausedEvent
|
||||
import com.correx.core.events.events.OrchestrationResumedEvent
|
||||
import com.correx.core.events.events.RiskAssessedEvent
|
||||
import com.correx.core.events.events.ToolExecutionCompletedEvent
|
||||
import com.correx.core.events.events.ToolExecutionFailedEvent
|
||||
import com.correx.core.events.events.ToolExecutionRejectedEvent
|
||||
import com.correx.core.events.events.ToolInvocationRequestedEvent
|
||||
import com.correx.core.events.events.ToolReceipt
|
||||
import com.correx.core.events.events.ToolRequest
|
||||
import com.correx.core.events.events.TransitionExecutedEvent
|
||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||
@@ -371,6 +375,14 @@ abstract class SessionOrchestrator(
|
||||
}
|
||||
emitDecisionResolved(sessionId, domainRequest, decision)
|
||||
if (!decision.isApproved) {
|
||||
val rejectReason = decision.reason ?: "approval denied"
|
||||
emit(sessionId, ToolExecutionRejectedEvent(
|
||||
invocationId = invocationId,
|
||||
sessionId = sessionId,
|
||||
toolName = toolCall.function.name,
|
||||
tier = tier,
|
||||
reason = rejectReason,
|
||||
))
|
||||
emit(sessionId, OrchestrationResumedEvent(sessionId, stageId))
|
||||
val sourceId = toolCall.id ?: invocationId.value
|
||||
val assistantEntry = ContextEntry(
|
||||
@@ -381,14 +393,13 @@ abstract class SessionOrchestrator(
|
||||
content = Json.encodeToString(ToolCallRequest.serializer(), toolCall),
|
||||
tokenEstimate = toolCall.function.arguments.length / 4,
|
||||
)
|
||||
val reason = decision.reason ?: "approval denied"
|
||||
val resultEntry = ContextEntry(
|
||||
id = ContextEntryId(UUID.randomUUID().toString()),
|
||||
layer = ContextLayer.L2,
|
||||
sourceType = "toolResult",
|
||||
sourceId = sourceId,
|
||||
content = "ERROR: $reason",
|
||||
tokenEstimate = reason.length / 4,
|
||||
content = "ERROR: $rejectReason",
|
||||
tokenEstimate = rejectReason.length / 4,
|
||||
)
|
||||
return@flatMap listOf(assistantEntry, resultEntry)
|
||||
}
|
||||
@@ -421,6 +432,29 @@ abstract class SessionOrchestrator(
|
||||
artifactContentCache["${sessionId.value}:${slot.name.value}"] = jsonContent
|
||||
}
|
||||
|
||||
when (result) {
|
||||
is ToolResult.Success -> emit(sessionId, ToolExecutionCompletedEvent(
|
||||
invocationId = invocationId,
|
||||
sessionId = sessionId,
|
||||
toolName = toolCall.function.name,
|
||||
receipt = ToolReceipt(
|
||||
invocationId = invocationId,
|
||||
toolName = toolCall.function.name,
|
||||
exitCode = result.exitCode,
|
||||
outputSummary = result.output.take(500),
|
||||
durationMs = 0,
|
||||
tier = tier,
|
||||
timestamp = Clock.System.now(),
|
||||
),
|
||||
))
|
||||
is ToolResult.Failure -> emit(sessionId, ToolExecutionFailedEvent(
|
||||
invocationId = invocationId,
|
||||
sessionId = sessionId,
|
||||
toolName = toolCall.function.name,
|
||||
reason = result.reason,
|
||||
))
|
||||
}
|
||||
|
||||
val sourceId = toolCall.id ?: invocationId.value
|
||||
val assistantEntry = ContextEntry(
|
||||
id = ContextEntryId(UUID.randomUUID().toString()),
|
||||
|
||||
Reference in New Issue
Block a user