diff --git a/core/kernel/src/main/kotlin/com/correx/core/kernel/orchestration/SessionOrchestrator.kt b/core/kernel/src/main/kotlin/com/correx/core/kernel/orchestration/SessionOrchestrator.kt index 2c2d3c4f..593cab7f 100644 --- a/core/kernel/src/main/kotlin/com/correx/core/kernel/orchestration/SessionOrchestrator.kt +++ b/core/kernel/src/main/kotlin/com/correx/core/kernel/orchestration/SessionOrchestrator.kt @@ -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()),