diff --git a/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt b/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt index eb5a69d6..43c1af4f 100644 --- a/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt +++ b/apps/server/src/main/kotlin/com/correx/apps/server/Main.kt @@ -44,7 +44,6 @@ import com.correx.core.toolintent.rules.ExecInterpreterRule import com.correx.core.toolintent.rules.NetworkHostRule import com.correx.core.toolintent.rules.PathContainmentRule import com.correx.infrastructure.InfrastructureModule -import com.correx.infrastructure.artifactscas.DefaultMaterializingArtifactWriter import com.correx.infrastructure.inference.DefaultProviderRegistry import com.correx.infrastructure.inference.FirstAvailableRoutingStrategy import com.correx.infrastructure.inference.llama.cpp.LlamaCppInferenceProvider @@ -92,10 +91,13 @@ fun main() { ?: toolsConfig.workingDir.takeIf { it.isNotEmpty() }?.let { Path.of(it) } ?: Path.of("").toAbsolutePath() val shellAllowedExecutables = toolsConfig.shellAllowedExecutables.toSet() + val workspaceRoot = System.getenv("CORREX_WORKSPACE_ROOT") + ?.let { Path.of(it) } + ?: toolsConfig.workspaceRoot.takeIf { it.isNotEmpty() }?.let { Path.of(it) } + ?: workingDir val toolRegistry = InfrastructureModule.createToolRegistry( buildToolConfig( - artifactStore, - sandboxRoot, + workspaceRoot, workingDir, shellAllowedExecutables, toolsConfig, @@ -110,10 +112,6 @@ fun main() { logToolInfo(sandboxRoot, workingDir, shellAllowedExecutables, toolRegistry) - val workspaceRoot = System.getenv("CORREX_WORKSPACE_ROOT") - ?.let { Path.of(it) } - ?: toolsConfig.workspaceRoot.takeIf { it.isNotEmpty() }?.let { Path.of(it) } - ?: workingDir val privilegedLocations = toolsConfig.privilegedLocations.map { Path.of(it) } val workspacePolicy = WorkspacePolicy(workspaceRoot, privilegedLocations) val toolCallAssessor = ToolCallAssessor( @@ -297,36 +295,39 @@ private fun buildRepositories( approvalRepository = InfrastructureModule.createApprovalRepository(eventStore), ) +// File tools write IN PLACE into the workspace (cwd / allow-listed dirs). The old +// sandboxRoot dual-write is retired; reversibility is event-sourced (FileWrittenEvent + +// CAS pre/post images, captured by SandboxedToolExecutor). sandboxRoot survives only as +// the executor's scratch workDir, never as a write destination. private fun buildToolConfig( - artifactStore: ArtifactStore, - sandboxRoot: Path, + workspaceRoot: Path, workingDir: Path, shellAllowedExecutables: Set, toolsConfig: com.correx.core.config.ToolsConfig, -): ToolConfig = ToolConfig( - shell = ShellConfig( - enabled = toolsConfig.shellEnabled, - allowedExecutables = shellAllowedExecutables, - workingDir = workingDir, - ), - fileRead = FileReadConfig( - enabled = toolsConfig.fileReadEnabled, - allowedPaths = setOf(sandboxRoot, workingDir), - ), - fileWrite = FileWriteConfig( - allowedPaths = setOf(sandboxRoot, workingDir), - enabled = toolsConfig.fileWriteEnabled, - artifactStore = artifactStore, - materializingWriter = DefaultMaterializingArtifactWriter(), - sandboxRoot = sandboxRoot, - workingDir = workingDir, - ), - fileEdit = FileEditConfig( - enabled = toolsConfig.fileEditEnabled, - allowedPaths = setOf(sandboxRoot, workingDir), - workingDir = workingDir, - ), -) +): ToolConfig { + val allowed = setOf(workspaceRoot, workingDir) + return ToolConfig( + shell = ShellConfig( + enabled = toolsConfig.shellEnabled, + allowedExecutables = shellAllowedExecutables, + workingDir = workingDir, + ), + fileRead = FileReadConfig( + enabled = toolsConfig.fileReadEnabled, + allowedPaths = allowed, + ), + fileWrite = FileWriteConfig( + allowedPaths = allowed, + enabled = toolsConfig.fileWriteEnabled, + workingDir = workingDir, + ), + fileEdit = FileEditConfig( + enabled = toolsConfig.fileEditEnabled, + allowedPaths = allowed, + workingDir = workingDir, + ), + ) +} private fun DefaultProviderRegistry.asServerRegistry(): ProviderRegistry = object : ProviderRegistry { override fun listAll() = this@asServerRegistry.listAll() diff --git a/infrastructure/tools/filesystem/src/main/kotlin/com/correx/infrastructure/tools/filesystem/FileWriteTool.kt b/infrastructure/tools/filesystem/src/main/kotlin/com/correx/infrastructure/tools/filesystem/FileWriteTool.kt index b5cec9bd..1a6b68a8 100644 --- a/infrastructure/tools/filesystem/src/main/kotlin/com/correx/infrastructure/tools/filesystem/FileWriteTool.kt +++ b/infrastructure/tools/filesystem/src/main/kotlin/com/correx/infrastructure/tools/filesystem/FileWriteTool.kt @@ -1,11 +1,6 @@ package com.correx.infrastructure.tools.filesystem import com.correx.core.approvals.Tier -import com.correx.core.artifacts.MaterializationResult -import com.correx.core.artifacts.MaterializingArtifactWriter -import com.correx.core.artifacts.kind.FileWrittenArtifact -import com.correx.core.artifacts.kind.FileWrittenPayload -import com.correx.core.artifactstore.ArtifactStore import com.correx.core.events.events.ToolRequest import com.correx.core.events.types.ToolInvocationId import com.correx.core.tools.contract.FileAffectingTool @@ -17,15 +12,12 @@ import com.correx.core.tools.contract.ValidationResult import kotlinx.coroutines.CancellationException import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext -import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject import kotlinx.serialization.json.JsonPrimitive import kotlinx.serialization.json.buildJsonArray import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.put import kotlinx.serialization.json.putJsonObject -import org.slf4j.Logger -import org.slf4j.LoggerFactory import java.io.IOException import java.nio.file.Files import java.nio.file.InvalidPathException @@ -34,16 +26,9 @@ import java.nio.file.Paths class FileWriteTool( allowedPaths: Set = emptySet(), - private val artifactStore: ArtifactStore? = null, - private val materializingWriter: MaterializingArtifactWriter? = null, - private val sandboxRoot: Path? = null, private val workingDir: Path? = null, ) : Tool, FileAffectingTool, ToolExecutor { - private companion object { - val log: Logger = LoggerFactory.getLogger(FileWriteTool::class.java) - } - private val normalizedAllowedPaths: Set = allowedPaths.map { it.normalize().toAbsolutePath() }.toSet() override val name: String = "file_write" @@ -174,7 +159,6 @@ class FileWriteTool( withContext(Dispatchers.IO) { AtomicFileWriter.write(path, content.toByteArray(Charsets.UTF_8)) } - storeArtifact(pathString, content, request.parameters["mode"] as? String ?: "0644") ToolResult.Success( invocationId = request.invocationId, output = "File written successfully to $pathString", @@ -206,26 +190,6 @@ class FileWriteTool( ) } - @Suppress("ReturnCount") - private suspend fun storeArtifact(pathString: String, content: String, mode: String) { - val writer = materializingWriter ?: return - val store = artifactStore ?: return - val root = sandboxRoot ?: return - val payload = FileWrittenPayload(path = pathString, content = content, mode = mode) - when (val result = writer.materialize(payload, root)) { - is MaterializationResult.Success -> { - val canonicalBytes = Json.encodeToString( - FileWrittenArtifact.serializer(), - result.artifact, - ).toByteArray(Charsets.UTF_8) - store.put(canonicalBytes) - } - - is MaterializationResult.Failure -> - log.warn("[FileWriteTool] artifact materialization failed for {}: {}", pathString, result.reason) - } - } - private fun handleExecutionException( e: Throwable, invocationId: ToolInvocationId, diff --git a/infrastructure/tools/src/main/kotlin/com/correx/infrastructure/tools/ToolConfig.kt b/infrastructure/tools/src/main/kotlin/com/correx/infrastructure/tools/ToolConfig.kt index 10076ae2..a352b809 100644 --- a/infrastructure/tools/src/main/kotlin/com/correx/infrastructure/tools/ToolConfig.kt +++ b/infrastructure/tools/src/main/kotlin/com/correx/infrastructure/tools/ToolConfig.kt @@ -1,7 +1,5 @@ package com.correx.infrastructure.tools -import com.correx.core.artifacts.MaterializingArtifactWriter -import com.correx.core.artifactstore.ArtifactStore import com.correx.core.tools.contract.Tool import com.correx.infrastructure.tools.filesystem.FileEditTool import com.correx.infrastructure.tools.filesystem.FileReadTool @@ -20,9 +18,6 @@ data class FileReadConfig(val enabled: Boolean = false, val allowedPaths: Set = emptySet(), - val artifactStore: ArtifactStore? = null, - val materializingWriter: MaterializingArtifactWriter? = null, - val sandboxRoot: Path? = null, val workingDir: Path? = null, ) @@ -61,9 +56,6 @@ fun ToolConfig.buildTools(): List = buildList { add( FileWriteTool( allowedPaths = fileWrite.allowedPaths, - artifactStore = fileWrite.artifactStore, - materializingWriter = fileWrite.materializingWriter, - sandboxRoot = fileWrite.sandboxRoot, workingDir = fileWrite.workingDir, ), )