feat: add ToolCallAssessedEvent for plane-2 tool-call assessment
This commit is contained in:
@@ -7,5 +7,6 @@ plugins {
|
|||||||
dependencies {
|
dependencies {
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-datetime"
|
implementation "org.jetbrains.kotlinx:kotlinx-datetime"
|
||||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version"
|
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinx_coroutines_version"
|
||||||
|
testImplementation "org.jetbrains.kotlin:kotlin-test"
|
||||||
}
|
}
|
||||||
tasks.named("koverVerify").configure { enabled = false }
|
tasks.named("koverVerify").configure { enabled = false }
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package com.correx.core.events.events
|
||||||
|
|
||||||
|
import com.correx.core.events.risk.RiskAction
|
||||||
|
import com.correx.core.events.types.SessionId
|
||||||
|
import com.correx.core.events.types.StageId
|
||||||
|
import com.correx.core.events.types.ToolInvocationId
|
||||||
|
import kotlinx.serialization.SerialName
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AssessedIssue(
|
||||||
|
val code: String,
|
||||||
|
val message: String,
|
||||||
|
val severity: String,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ToolCallObservation(
|
||||||
|
val ruleCode: String,
|
||||||
|
val facts: Map<String, String> = emptyMap(),
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
@SerialName("ToolCallAssessed")
|
||||||
|
data class ToolCallAssessedEvent(
|
||||||
|
val invocationId: ToolInvocationId,
|
||||||
|
val sessionId: SessionId,
|
||||||
|
val stageId: StageId,
|
||||||
|
val toolName: String,
|
||||||
|
val issues: List<AssessedIssue> = emptyList(),
|
||||||
|
val observations: List<ToolCallObservation> = emptyList(),
|
||||||
|
val disposition: RiskAction,
|
||||||
|
val timestampMs: Long,
|
||||||
|
) : EventPayload
|
||||||
@@ -25,6 +25,7 @@ import com.correx.core.events.events.RiskAssessedEvent
|
|||||||
import com.correx.core.events.events.StageCompletedEvent
|
import com.correx.core.events.events.StageCompletedEvent
|
||||||
import com.correx.core.events.events.StageFailedEvent
|
import com.correx.core.events.events.StageFailedEvent
|
||||||
import com.correx.core.events.events.SteeringNoteAddedEvent
|
import com.correx.core.events.events.SteeringNoteAddedEvent
|
||||||
|
import com.correx.core.events.events.ToolCallAssessedEvent
|
||||||
import com.correx.core.events.events.ToolExecutionCompletedEvent
|
import com.correx.core.events.events.ToolExecutionCompletedEvent
|
||||||
import com.correx.core.events.events.ToolExecutionFailedEvent
|
import com.correx.core.events.events.ToolExecutionFailedEvent
|
||||||
import com.correx.core.events.events.ToolExecutionRejectedEvent
|
import com.correx.core.events.events.ToolExecutionRejectedEvent
|
||||||
@@ -49,6 +50,7 @@ val eventModule = SerializersModule {
|
|||||||
subclass(ToolExecutionCompletedEvent::class)
|
subclass(ToolExecutionCompletedEvent::class)
|
||||||
subclass(ToolExecutionFailedEvent::class)
|
subclass(ToolExecutionFailedEvent::class)
|
||||||
subclass(ToolExecutionRejectedEvent::class)
|
subclass(ToolExecutionRejectedEvent::class)
|
||||||
|
subclass(ToolCallAssessedEvent::class)
|
||||||
subclass(SteeringNoteAddedEvent::class)
|
subclass(SteeringNoteAddedEvent::class)
|
||||||
subclass(StageFailedEvent::class)
|
subclass(StageFailedEvent::class)
|
||||||
subclass(StageCompletedEvent::class)
|
subclass(StageCompletedEvent::class)
|
||||||
|
|||||||
+51
@@ -0,0 +1,51 @@
|
|||||||
|
package com.correx.core.events.serialization
|
||||||
|
|
||||||
|
import com.correx.core.events.events.AssessedIssue
|
||||||
|
import com.correx.core.events.events.EventPayload
|
||||||
|
import com.correx.core.events.events.ToolCallAssessedEvent
|
||||||
|
import com.correx.core.events.events.ToolCallObservation
|
||||||
|
import com.correx.core.events.risk.RiskAction
|
||||||
|
import com.correx.core.events.types.SessionId
|
||||||
|
import com.correx.core.events.types.StageId
|
||||||
|
import com.correx.core.events.types.ToolInvocationId
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
class ToolCallAssessedEventSerializationTest {
|
||||||
|
|
||||||
|
private val sample = ToolCallAssessedEvent(
|
||||||
|
invocationId = ToolInvocationId("inv-1"),
|
||||||
|
sessionId = SessionId("sess-1"),
|
||||||
|
stageId = StageId("stage-1"),
|
||||||
|
toolName = "file_write",
|
||||||
|
issues = listOf(AssessedIssue("PATH_OUTSIDE_WORKSPACE", "outside: /tmp/x", "WARNING")),
|
||||||
|
observations = listOf(
|
||||||
|
ToolCallObservation(
|
||||||
|
ruleCode = "PATH_CONTAINMENT",
|
||||||
|
facts = mapOf("path" to "/tmp/x", "exists" to "false", "inWorkspace" to "false", "privileged" to "false"),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
disposition = RiskAction.PROMPT_USER,
|
||||||
|
timestampMs = 42L,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `round-trips as polymorphic EventPayload`() {
|
||||||
|
val encoded = eventJson.encodeToString(EventPayload.serializer(), sample)
|
||||||
|
assertTrue(encoded.contains("\"type\":\"ToolCallAssessed\""), "SerialName must be present: $encoded")
|
||||||
|
val decoded = eventJson.decodeFromString(EventPayload.serializer(), encoded)
|
||||||
|
assertEquals(sample, decoded)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `decodes hand-written ToolCallAssessed JSON`() {
|
||||||
|
val json = """
|
||||||
|
{"type":"ToolCallAssessed","invocationId":"inv-9","sessionId":"s","stageId":"st",
|
||||||
|
"toolName":"shell","issues":[],"observations":[],"disposition":"PROCEED","timestampMs":1}
|
||||||
|
""".trimIndent()
|
||||||
|
val decoded = eventJson.decodeFromString(EventPayload.serializer(), json)
|
||||||
|
assertTrue(decoded is ToolCallAssessedEvent)
|
||||||
|
assertEquals(RiskAction.PROCEED, (decoded as ToolCallAssessedEvent).disposition)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user