fix(kernel+infra): tool approval gate and executor cleanup
- SessionOrchestrator: wire T2/T3/T4 approval gate before tool execution; emit OrchestrationPausedEvent/ApprovalRequestedEvent, await decision, return rejection as ERROR context entry so LLM sees the denial; propagate tool ERROR entries as StageExecutionResult.Failure - SandboxedToolExecutor: remove dead code and simplify - InfrastructureModule: minor wiring cleanup - LlamaCppInferenceProvider / build.gradle: related build fixes
This commit is contained in:
+1
-82
@@ -1,28 +1,15 @@
|
||||
package com.correx.infrastructure.tools
|
||||
|
||||
import com.correx.core.approvals.Tier
|
||||
import com.correx.core.approvals.domain.ApprovalEngine
|
||||
import com.correx.core.approvals.model.ApprovalContext
|
||||
import com.correx.core.approvals.model.ApprovalGrant
|
||||
import com.correx.core.approvals.model.ApprovalScopeIdentity
|
||||
import com.correx.core.approvals.model.DomainApprovalRequest
|
||||
import com.correx.core.events.EventDispatcher
|
||||
import com.correx.core.events.events.ApprovalGrantCreatedEvent
|
||||
import com.correx.core.events.events.EventPayload
|
||||
import com.correx.core.events.events.StoredEvent
|
||||
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.ToolExecutionStartedEvent
|
||||
import com.correx.core.events.events.ToolReceipt
|
||||
import com.correx.core.events.events.ToolRequest
|
||||
import com.correx.core.events.stores.EventStore
|
||||
import com.correx.core.events.types.ApprovalRequestId
|
||||
import com.correx.core.events.types.SessionId
|
||||
import com.correx.core.events.types.StageId
|
||||
import com.correx.core.events.types.ToolInvocationId
|
||||
import com.correx.core.events.types.ValidationReportId
|
||||
import com.correx.core.sessions.ApprovalMode
|
||||
import com.correx.core.tools.contract.FileAffectingTool
|
||||
import com.correx.core.tools.contract.Tool
|
||||
import com.correx.core.tools.contract.ToolExecutor
|
||||
@@ -41,8 +28,6 @@ import java.util.*
|
||||
class SandboxedToolExecutor(
|
||||
private val delegate: ToolExecutor,
|
||||
private val registry: ToolRegistry,
|
||||
private val approvalEngine: ApprovalEngine,
|
||||
private val eventStore: EventStore,
|
||||
private val eventDispatcher: EventDispatcher,
|
||||
private val workDir: Path = Path.of("/tmp/correx-sandbox"),
|
||||
) : ToolExecutor {
|
||||
@@ -61,26 +46,7 @@ class SandboxedToolExecutor(
|
||||
recoverable = false,
|
||||
)
|
||||
|
||||
// 2. approval check for T2-T4
|
||||
val requiresApproval = when (tool.tier) {
|
||||
Tier.T0, Tier.T1 -> false
|
||||
Tier.T2, Tier.T3, Tier.T4 -> true
|
||||
}
|
||||
|
||||
if (requiresApproval) {
|
||||
val sessionEvents = eventStore.read(sessionId)
|
||||
val decision = evaluateApproval(tool, sessionId, request.stageId, sessionEvents)
|
||||
if (!decision.isApproved) {
|
||||
emitRejected(sessionId, invocationId, toolName, tool.tier, decision.reason ?: "approval denied")
|
||||
return@withContext ToolResult.Failure(
|
||||
invocationId = invocationId,
|
||||
reason = decision.reason ?: "approval denied",
|
||||
recoverable = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// 3. emit started
|
||||
// 2. emit started
|
||||
emitStarted(sessionId, invocationId, toolName)
|
||||
|
||||
// 4. create working dir
|
||||
@@ -121,45 +87,6 @@ class SandboxedToolExecutor(
|
||||
}
|
||||
}
|
||||
|
||||
// --- approval ---
|
||||
|
||||
private fun evaluateApproval(
|
||||
tool: Tool,
|
||||
sessionId: SessionId,
|
||||
stageId: StageId,
|
||||
sessionEvents: List<StoredEvent>,
|
||||
) = approvalEngine.evaluate(
|
||||
request = DomainApprovalRequest(
|
||||
id = ApprovalRequestId(UUID.randomUUID().toString()),
|
||||
tier = tool.tier,
|
||||
validationReportId = ValidationReportId(UUID.randomUUID().toString()),
|
||||
riskSummaryId = null,
|
||||
timestamp = Clock.System.now(),
|
||||
causationId = null,
|
||||
correlationId = null,
|
||||
),
|
||||
context = ApprovalContext(
|
||||
identity = ApprovalScopeIdentity(sessionId, stageId, null),
|
||||
mode = ApprovalMode.PROMPT,
|
||||
),
|
||||
grants = extractGrants(sessionEvents),
|
||||
now = Clock.System.now(),
|
||||
)
|
||||
|
||||
private fun extractGrants(events: List<StoredEvent>): List<ApprovalGrant> =
|
||||
events
|
||||
.mapNotNull { it.payload as? ApprovalGrantCreatedEvent }
|
||||
.map { e ->
|
||||
ApprovalGrant(
|
||||
id = e.grantId,
|
||||
scope = e.scope,
|
||||
permittedTiers = e.permittedTiers,
|
||||
reason = e.reason,
|
||||
timestamp = Clock.System.now(),
|
||||
expiresAt = e.expiresAt,
|
||||
)
|
||||
}
|
||||
|
||||
// --- backup/restore ---
|
||||
|
||||
/**
|
||||
@@ -209,14 +136,6 @@ class SandboxedToolExecutor(
|
||||
|
||||
// --- event emission ---
|
||||
|
||||
private suspend fun emitRejected(
|
||||
sessionId: SessionId,
|
||||
invocationId: ToolInvocationId,
|
||||
toolName: String,
|
||||
tier: Tier,
|
||||
reason: String,
|
||||
) = emit(sessionId, ToolExecutionRejectedEvent(invocationId, sessionId, toolName, tier, reason))
|
||||
|
||||
private suspend fun emitStarted(
|
||||
sessionId: SessionId,
|
||||
invocationId: ToolInvocationId,
|
||||
|
||||
Reference in New Issue
Block a user