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.OrchestrationPausedEvent
|
||||||
import com.correx.core.events.events.OrchestrationResumedEvent
|
import com.correx.core.events.events.OrchestrationResumedEvent
|
||||||
import com.correx.core.events.events.RiskAssessedEvent
|
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.ToolInvocationRequestedEvent
|
||||||
|
import com.correx.core.events.events.ToolReceipt
|
||||||
import com.correx.core.events.events.ToolRequest
|
import com.correx.core.events.events.ToolRequest
|
||||||
import com.correx.core.events.events.TransitionExecutedEvent
|
import com.correx.core.events.events.TransitionExecutedEvent
|
||||||
import com.correx.core.events.events.WorkflowCompletedEvent
|
import com.correx.core.events.events.WorkflowCompletedEvent
|
||||||
@@ -371,6 +375,14 @@ abstract class SessionOrchestrator(
|
|||||||
}
|
}
|
||||||
emitDecisionResolved(sessionId, domainRequest, decision)
|
emitDecisionResolved(sessionId, domainRequest, decision)
|
||||||
if (!decision.isApproved) {
|
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))
|
emit(sessionId, OrchestrationResumedEvent(sessionId, stageId))
|
||||||
val sourceId = toolCall.id ?: invocationId.value
|
val sourceId = toolCall.id ?: invocationId.value
|
||||||
val assistantEntry = ContextEntry(
|
val assistantEntry = ContextEntry(
|
||||||
@@ -381,14 +393,13 @@ abstract class SessionOrchestrator(
|
|||||||
content = Json.encodeToString(ToolCallRequest.serializer(), toolCall),
|
content = Json.encodeToString(ToolCallRequest.serializer(), toolCall),
|
||||||
tokenEstimate = toolCall.function.arguments.length / 4,
|
tokenEstimate = toolCall.function.arguments.length / 4,
|
||||||
)
|
)
|
||||||
val reason = decision.reason ?: "approval denied"
|
|
||||||
val resultEntry = ContextEntry(
|
val resultEntry = ContextEntry(
|
||||||
id = ContextEntryId(UUID.randomUUID().toString()),
|
id = ContextEntryId(UUID.randomUUID().toString()),
|
||||||
layer = ContextLayer.L2,
|
layer = ContextLayer.L2,
|
||||||
sourceType = "toolResult",
|
sourceType = "toolResult",
|
||||||
sourceId = sourceId,
|
sourceId = sourceId,
|
||||||
content = "ERROR: $reason",
|
content = "ERROR: $rejectReason",
|
||||||
tokenEstimate = reason.length / 4,
|
tokenEstimate = rejectReason.length / 4,
|
||||||
)
|
)
|
||||||
return@flatMap listOf(assistantEntry, resultEntry)
|
return@flatMap listOf(assistantEntry, resultEntry)
|
||||||
}
|
}
|
||||||
@@ -421,6 +432,29 @@ abstract class SessionOrchestrator(
|
|||||||
artifactContentCache["${sessionId.value}:${slot.name.value}"] = jsonContent
|
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 sourceId = toolCall.id ?: invocationId.value
|
||||||
val assistantEntry = ContextEntry(
|
val assistantEntry = ContextEntry(
|
||||||
id = ContextEntryId(UUID.randomUUID().toString()),
|
id = ContextEntryId(UUID.randomUUID().toString()),
|
||||||
|
|||||||
Reference in New Issue
Block a user