diff --git a/.gitignore b/.gitignore
index ee2fc73..a11dcf0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -38,6 +38,14 @@ bin/
/nbdist/
/.nb-gradle/
+### Python ###
+**/__pycache__/
+**/*.pyc
+**/.venv/
+**/.venvs/
+
+
+
### VS Code ###
.vscode/
diff --git a/.idea/gradle.xml b/.idea/gradle.xml
index e90bd0e..33bcda4 100644
--- a/.idea/gradle.xml
+++ b/.idea/gradle.xml
@@ -21,13 +21,19 @@
+
+
+
+
+
+
diff --git a/.idea/kotlinc.xml b/.idea/kotlinc.xml
index 03fcfb7..90d1b4b 100644
--- a/.idea/kotlinc.xml
+++ b/.idea/kotlinc.xml
@@ -1,6 +1,7 @@
-
+
+
\ No newline at end of file
diff --git a/app/benchmark-securityeval/src/main/kotlin/de/tuda/stg/securecoder/benchmark/Main.kt b/app/benchmark-securityeval/src/main/kotlin/de/tuda/stg/securecoder/benchmark/Main.kt
index e103dac..ca5a77f 100644
--- a/app/benchmark-securityeval/src/main/kotlin/de/tuda/stg/securecoder/benchmark/Main.kt
+++ b/app/benchmark-securityeval/src/main/kotlin/de/tuda/stg/securecoder/benchmark/Main.kt
@@ -47,10 +47,12 @@ suspend fun runSecurityEval(
val fs = InMemoryFileSystem()
val onEvent: suspend (StreamEvent) -> Unit = { ev ->
when (ev) {
- is StreamEvent.EditFiles -> {
+ is StreamEvent.ProposedEdits -> {
println(ev)
fs.applyEdits(ev.changes.searchReplaces)
}
+ is StreamEvent.ValidationStarted -> {}
+ is StreamEvent.ValidationSucceeded -> {}
is StreamEvent.SendDebugMessage -> {
if (ev.icon != EventIcon.Info) {
println("ENGINE: $ev")
@@ -67,7 +69,12 @@ suspend fun runSecurityEval(
}
}
}
- engine.run(item.prompt, fs, onEvent)
+ val result = engine.run(item.prompt, fs, onEvent)
+ if (result !is Engine.EngineResult.Success) {
+ println("Failed to generate edits for item $item: $result")
+ continue
+ }
+ fs.applyEdits(result.changes.searchReplaces)
val files = fs.allFiles().toList()
if (files.size != 1) {
println("Expected 1 file, but got ${files.size}")
diff --git a/app/intellij-plugin/build.gradle.kts b/app/intellij-plugin/build.gradle.kts
index 7da5f6b..102bba3 100644
--- a/app/intellij-plugin/build.gradle.kts
+++ b/app/intellij-plugin/build.gradle.kts
@@ -22,6 +22,11 @@ kotlin {
jvmToolchain(21)
}
+configurations.all {
+ exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-core")
+ exclude(group = "org.jetbrains.kotlinx", module = "kotlinx-coroutines-jdk8")
+}
+
tasks {
patchPluginXml {
changeNotes.set("""
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/SecureCoderAiToolWindowFactory.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/SecureCoderAiToolWindowFactory.kt
deleted file mode 100644
index 028534c..0000000
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/SecureCoderAiToolWindowFactory.kt
+++ /dev/null
@@ -1,229 +0,0 @@
-package de.tuda.stg.securecoder.plugin
-
-import com.intellij.icons.AllIcons
-import com.intellij.openapi.actionSystem.AnAction
-import com.intellij.openapi.actionSystem.AnActionEvent
-import com.intellij.openapi.application.EDT
-import com.intellij.openapi.components.service
-import com.intellij.openapi.options.ShowSettingsUtil
-import com.intellij.openapi.project.DumbAware
-import com.intellij.openapi.project.Project
-import com.intellij.openapi.ui.Messages
-import com.intellij.openapi.wm.ToolWindow
-import com.intellij.openapi.wm.ToolWindowFactory
-import com.intellij.ui.components.JBScrollPane
-import com.intellij.ui.components.JBTextArea
-import com.intellij.ui.content.ContentFactory
-import com.intellij.util.ui.JBFont
-import com.intellij.util.ui.JBUI
-import com.intellij.util.ui.JBUI.Borders
-import com.intellij.util.ui.JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground
-import de.tuda.stg.securecoder.plugin.edit.buildEditFilesPanel
-import de.tuda.stg.securecoder.plugin.engine.EngineRunnerService
-import de.tuda.stg.securecoder.plugin.engine.IntelliJProjectFileSystem
-import de.tuda.stg.securecoder.plugin.engine.event.UiStreamEvent
-import de.tuda.stg.securecoder.plugin.settings.SecureCoderSettingsConfigurable
-import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.withContext
-import java.awt.BorderLayout
-import java.awt.Component
-import java.awt.Dimension
-import javax.swing.BorderFactory
-import javax.swing.Box
-import javax.swing.BoxLayout
-import javax.swing.JButton
-import javax.swing.JCheckBox
-import javax.swing.JLabel
-import javax.swing.JPanel
-import javax.swing.JTextArea
-import javax.swing.ScrollPaneConstants
-import javax.swing.SwingUtilities
-
-class SecureCoderAiToolWindowFactory : ToolWindowFactory, DumbAware {
- private lateinit var eventsPanel: JPanel
- private lateinit var eventsScrollPane: JBScrollPane
-
- override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
- val root = createRoot(project)
- val contentFactory = ContentFactory.getInstance()
- val content = contentFactory.createContent(root, null, false)
- toolWindow.contentManager.addContent(content)
- toolWindow.setIcon(AllIcons.Ultimate.Lock) // AllIcons.Ide.Readonly
- toolWindow.setTitleActions(listOf(
- object : AnAction(
- SecureCoderBundle.message("toolwindow.settings"),
- null,
- AllIcons.General.Settings
- ), DumbAware {
- override fun actionPerformed(e: AnActionEvent) {
- ShowSettingsUtil.getInstance()
- .showSettingsDialog(project, SecureCoderSettingsConfigurable::class.java)
- }
- }
- ))
- }
-
- private fun createRoot(project: Project): JPanel = JPanel(BorderLayout()).apply {
- val inputArea = createInputArea()
- val scroll = wrapTextInScrollPane(inputArea)
- val preferredHeight = scroll.preferredSize.height
- scroll.maximumSize = Dimension(Int.MAX_VALUE, preferredHeight)
- val submit = createSubmitButton(preferredHeight)
- val checkBox = JCheckBox(SecureCoderBundle.message("toolwindow.useWholeProject"), true).apply {
- alignmentX = Component.LEFT_ALIGNMENT
- border = Borders.emptyLeft(4)
- toolTipText = SecureCoderBundle.message("toolwindow.useWholeProject.tooltip")
- }
- val header = JPanel().apply {
- layout = BoxLayout(this, BoxLayout.Y_AXIS)
- border = Borders.empty(8)
- alignmentX = Component.LEFT_ALIGNMENT
- }
- val textRow = buildTextRow(scroll)
- val controlsRow = buildControlsRow(checkBox, submit)
-
- header.add(textRow)
- header.add(Box.createRigidArea(Dimension(0, JBUI.scale(8))))
- header.add(controlsRow)
- add(header, BorderLayout.NORTH)
-
- eventsPanel = JPanel().apply {
- layout = BoxLayout(this, BoxLayout.Y_AXIS)
- border = Borders.empty(8)
- }
- eventsScrollPane = JBScrollPane(eventsPanel).apply {
- verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
- horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
- border = Borders.empty()
- }
- add(eventsScrollPane, BorderLayout.CENTER)
- setupSubmitAction(project, inputArea, submit)
- }
-
- private fun buildControlsRow(checkBox: JCheckBox, submit: JButton): JPanel = JPanel().apply {
- layout = BoxLayout(this, BoxLayout.X_AXIS)
- border = Borders.empty()
- checkBox.alignmentY = Component.CENTER_ALIGNMENT
- checkBox.maximumSize = checkBox.preferredSize
- submit.alignmentY = Component.CENTER_ALIGNMENT
- submit.maximumSize = Dimension(submit.preferredSize.width, submit.preferredSize.height)
- add(checkBox)
- add(Box.createHorizontalGlue())
- add(submit)
- }
-
- private fun createInputArea(): JBTextArea = JBTextArea().apply {
- lineWrap = true
- wrapStyleWord = true
- rows = 5
- columns = 30
- border = Borders.empty(8)
- }
-
- private fun wrapTextInScrollPane(inputArea: JBTextArea): JBScrollPane = JBScrollPane(inputArea).apply {
- verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
- horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
- }
-
- private fun createSubmitButton(height: Int): JButton = JButton(SecureCoderBundle.message("toolwindow.submit")).apply {
- maximumSize = Dimension(preferredSize.width, height)
- }
-
- private fun buildTextRow(scroll: JBScrollPane): JPanel = JPanel().apply {
- layout = BoxLayout(this, BoxLayout.X_AXIS)
- border = Borders.empty()
- add(scroll.apply {
- alignmentX = Component.LEFT_ALIGNMENT
- maximumSize = Dimension(Int.MAX_VALUE, preferredSize.height)
- })
- }
-
- private fun setupSubmitAction(project: Project, inputArea: JBTextArea, submit: JButton) {
- submit.addActionListener {
- val text = inputArea.text.trim()
- if (text.isEmpty()) {
- Messages.showWarningDialog(
- project,
- SecureCoderBundle.message("warning.emptyPrompt"),
- SecureCoderBundle.message("product.name")
- )
- } else {
- submit.isEnabled = false
- submit.text = SecureCoderBundle.message("toolwindow.streaming")
-
- eventsPanel.removeAll()
- eventsPanel.revalidate()
- eventsPanel.repaint()
- val runner = project.service()
- runner.runEngine(
- text,
- onUiEvent = { event ->
- withContext(Dispatchers.EDT) { addEventCard(event, project) }
- },
- onComplete = {
- withContext(Dispatchers.EDT) {
- submit.isEnabled = true
- submit.text = SecureCoderBundle.message("toolwindow.submit")
- }
- }
- )
- }
- }
- }
-
- private fun addEventCard(event: UiStreamEvent, project: Project) {
- val card = object : JPanel() {
- override fun getMaximumSize() = Dimension(Int.MAX_VALUE, preferredSize.height)
- }.apply {
- layout = BoxLayout(this, BoxLayout.Y_AXIS)
- border = BorderFactory.createCompoundBorder(
- Borders.customLine(separatorForeground(), 1),
- Borders.empty(6)
- )
- }
-
- val titlePanel = JPanel().apply {
- layout = BoxLayout(this, BoxLayout.X_AXIS)
- border = Borders.emptyBottom(4)
- alignmentX = Component.LEFT_ALIGNMENT
- }
- val title = when (event) {
- is UiStreamEvent.Message -> event.title
- is UiStreamEvent.EditFiles -> "Edit Files"
- }
- val icon = when (event) {
- is UiStreamEvent.Message -> event.icon
- is UiStreamEvent.EditFiles -> AllIcons.Actions.EditSource
- }
- val titleLabel = JLabel(title, icon, JLabel.LEADING).apply {
- font = JBFont.label().asBold()
- }
- titlePanel.add(titleLabel)
-
- val content = when (event) {
- is UiStreamEvent.Message -> JTextArea(event.description).apply {
- isEditable = false
- lineWrap = true
- wrapStyleWord = true
- border = Borders.empty()
- background = card.background
- alignmentX = Component.LEFT_ALIGNMENT
- }
- is UiStreamEvent.EditFiles -> buildEditFilesPanel(project, event.changes, IntelliJProjectFileSystem(project))
- }
-
- card.add(titlePanel)
- card.add(content)
-
- eventsPanel.add(card)
- eventsPanel.add(Box.createRigidArea(Dimension(0, JBUI.scale(8))))
- eventsPanel.revalidate()
- eventsPanel.repaint()
-
- SwingUtilities.invokeLater {
- val vBar = eventsScrollPane.verticalScrollBar
- vBar.value = vBar.maximum
- }
- }
-}
-
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/edit/BuildEditFilesPanel.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/edit/BuildEditFilesPanel.kt
index 5233245..c16d5d1 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/edit/BuildEditFilesPanel.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/edit/BuildEditFilesPanel.kt
@@ -36,6 +36,7 @@ import de.tuda.stg.securecoder.engine.file.edit.ApplyChanges
import de.tuda.stg.securecoder.engine.file.edit.ApplyChanges.applyEdits
import de.tuda.stg.securecoder.filesystem.FileSystem
import de.tuda.stg.securecoder.plugin.SecureCoderBundle
+import com.intellij.openapi.diagnostic.Logger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runBlocking
import javax.swing.BorderFactory
@@ -98,12 +99,13 @@ fun buildEditFilesPanel(
project
)
}
- } catch (t: Throwable) {
+ } catch (throwable: Throwable) {
+ LOG.error("Failed to apply edits", throwable)
SwingUtilities.invokeLater {
Notifications.Bus.notify(
notification(
SecureCoderBundle.message("edit.apply.error.title"),
- t.message ?: t.toString(),
+ throwable.message ?: throwable.toString(),
NotificationType.ERROR
),
project
@@ -167,6 +169,8 @@ fun buildEditFilesPanel(
return panel
}
+private val LOG: Logger = Logger.getInstance("BuildEditFilesPanel")
+
private fun openDiffForFile(project: Project, fileUrl: String, edits: List) {
val vfm = VirtualFileManager.getInstance()
val vFile: VirtualFile? = vfm.findFileByUrl(fileUrl)
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/DummyAgentStreamer.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/DummyAgentStreamer.kt
index 7b23fd6..7055cd8 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/DummyAgentStreamer.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/DummyAgentStreamer.kt
@@ -6,6 +6,7 @@ import de.tuda.stg.securecoder.engine.file.edit.Changes
import de.tuda.stg.securecoder.engine.file.edit.Changes.*
import de.tuda.stg.securecoder.engine.stream.EventIcon
import de.tuda.stg.securecoder.engine.stream.StreamEvent
+import de.tuda.stg.securecoder.engine.stream.ProposalId
import de.tuda.stg.securecoder.filesystem.FileSystem
import kotlinx.coroutines.delay
import java.util.concurrent.ThreadLocalRandom
@@ -39,7 +40,7 @@ class DummyAgentStreamer : Engine {
val icon = randomPick(EventIcon.entries)
onEvent(StreamEvent.SendDebugMessage(title, desc, icon))
if (idx % 3 == 0) {
- onEvent(StreamEvent.EditFiles(Changes(listOf(
+ onEvent(StreamEvent.ProposedEdits(ProposalId.newId(), Changes(listOf(
SearchReplace("app.py", SearchedText.append(), "print(\"Hello World!\")"),
SearchReplace("app2.py", SearchedText.append(), "print(\"Hello World!\")"),
SearchReplace("app.py", SearchedText.append(), "\nprint(\"Hello World!2\")"),
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/EngineRunnerService.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/EngineRunnerService.kt
index 0df29c9..fc6aca7 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/EngineRunnerService.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/EngineRunnerService.kt
@@ -52,7 +52,7 @@ class EngineRunnerService(
PromptEnricher.PASSTHROUGH
}
val guardians = listOfNotNull(
- if (settings.enableDummyGuardian) DummyGuardian() else null,
+ if (settings.enableDummyGuardian) DummyGuardian(sleepMillis = 2000) else null,
if (settings.enableCodeQLGuardian) CodeQLGuardian(settings.codeqlBinary) else null
)
@@ -78,19 +78,20 @@ class EngineRunnerService(
withBackgroundProgress(project, "Running engine…", cancellable = false) {
val fileSystem = IntelliJProjectFileSystem(project)
var handle: EngineHandle? = null
+ val mapper = StreamEventMapper()
try {
handle = buildEngine()
val result = handle.engine.run(
text,
fileSystem,
- { engineEvent -> onUiEvent(StreamEventMapper.map(engineEvent)) },
+ { engineEvent -> onUiEvent(mapper.map(engineEvent)) },
buildContext(reduceContextToOpenFiles)
)
- onUiEvent(EngineResultMapper.map(result))
+ EngineResultMapper.map(mapper, result)?.let { onUiEvent(it) }
} catch (exception: Exception) {
thisLogger().error("Uncaught exception within the engine", exception)
- onUiEvent(StreamEventMapper.mapException(exception))
+ onUiEvent(mapper.mapException(exception))
} finally {
runCatching { handle?.close?.invoke() }.onFailure {
thisLogger().warn("Failed closing engine handle", it)
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/EngineResultMapper.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/EngineResultMapper.kt
index df16a81..07ed713 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/EngineResultMapper.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/EngineResultMapper.kt
@@ -3,15 +3,15 @@ package de.tuda.stg.securecoder.plugin.engine.event
import de.tuda.stg.securecoder.engine.Engine.EngineResult
object EngineResultMapper {
- fun map(result: EngineResult): UiStreamEvent {
+ fun map(mapper: StreamEventMapper, result: EngineResult): UiStreamEvent? {
return when (result) {
EngineResult.Failure.GenerationFailure -> {
- StreamEventMapper.createGenerationError()
+ mapper.createGenerationError()
}
is EngineResult.Failure.ValidationFailure -> {
- StreamEventMapper.createValidationError(result.maxGuardianRetries)
+ mapper.createValidationError(result.maxGuardianRetries)
}
- is EngineResult.Success -> UiStreamEvent.EditFiles(result.changes)
+ is EngineResult.Success -> null
}
}
}
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/StreamEventMapper.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/StreamEventMapper.kt
index 8aad468..f21ac34 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/StreamEventMapper.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/StreamEventMapper.kt
@@ -1,12 +1,32 @@
package de.tuda.stg.securecoder.plugin.engine.event
import com.intellij.icons.AllIcons
+import de.tuda.stg.securecoder.engine.stream.ProposalId
import de.tuda.stg.securecoder.engine.stream.StreamEvent
import de.tuda.stg.securecoder.plugin.SecureCoderBundle
+import de.tuda.stg.securecoder.plugin.engine.event.UiStreamEvent.EditFilesValidation
+
+class StreamEventMapper {
+ private val proposals = mutableMapOf()
-object StreamEventMapper {
fun map(event: StreamEvent): UiStreamEvent = when (event) {
- is StreamEvent.EditFiles -> UiStreamEvent.EditFiles(event.changes)
+ is StreamEvent.ProposedEdits -> {
+ val pid = event.id
+ val current = proposals[pid]
+ val merged = (current ?: UiStreamEvent.EditFiles(
+ changes = event.changes,
+ proposalId = pid,
+ validation = EditFilesValidation.NotAvailable,
+ )).copy(changes = event.changes)
+ proposals[pid] = merged
+ merged
+ }
+ is StreamEvent.ValidationStarted -> {
+ updateProposalValidation(event.id, EditFilesValidation.Running)
+ }
+ is StreamEvent.ValidationSucceeded -> {
+ updateProposalValidation(event.id, EditFilesValidation.Succeeded)
+ }
is StreamEvent.SendDebugMessage -> {
UiStreamEvent.Message(
@@ -25,28 +45,103 @@ object StreamEventMapper {
}
is StreamEvent.GuardianWarning -> {
- UiStreamEvent.Message(
- title = SecureCoderBundle.message("warning.guardian.title"),
- description = SecureCoderBundle.message("warning.guardian.description", event.violations),
- icon = AllIcons.General.Warning
- )
+ val messages = mutableListOf()
+ val ruleNames = event.result.violations.map { v ->
+ val n = v.rule.name
+ if (n.isNullOrBlank()) v.rule.id else n
+ }.distinct()
+ if (ruleNames.isNotEmpty()) {
+ messages += SecureCoderBundle.message(
+ "warning.guardian.short.violation",
+ ruleNames.joinToString { "\"$it\"" },
+ )
+ }
+ if (event.result.failures.isNotEmpty()) {
+ messages += SecureCoderBundle.message(
+ "warning.guardian.short.failure",
+ event.result.failures.joinToString { f -> f.guardian }
+ )
+ }
+
+ val summary = messages.joinToString(" ")
+ val details = buildGuardianDetailsText(event)
+ updateProposalValidation(event.id, EditFilesValidation.Failed(summary, details))
}
is StreamEvent.InvalidLlmOutputWarning -> {
UiStreamEvent.Message(
title = SecureCoderBundle.message("warning.llm.title"),
- description = SecureCoderBundle.message("warning.llm.description", event.parseErrors.joinToString("\n")),
- icon = AllIcons.General.Warning
+ description = SecureCoderBundle.message("warning.llm.description"),
+ icon = AllIcons.General.Warning,
+ debugText = buildExchangeText(event)
)
}
}
+ private fun updateProposalValidation(pid: ProposalId, newValidation: EditFilesValidation): UiStreamEvent.EditFiles {
+ val current = proposals[pid] ?: throw IllegalStateException("Unknown proposal $pid")
+ val merged = current.copy(validation = newValidation)
+ proposals[pid] = merged
+ return merged
+ }
+
+ private fun buildGuardianDetailsText(event: StreamEvent.GuardianWarning): String {
+ val result = event.result
+ val sb = StringBuilder()
+ if (result.violations.isNotEmpty()) {
+ sb.appendLine("Violations:")
+ result.violations.forEachIndexed { index, v ->
+ val ruleName = if (v.rule.name.isNullOrBlank()) v.rule.id else v.rule.name
+ sb.appendLine("#${index + 1} - Rule: $ruleName (id=${v.rule.id})")
+ sb.appendLine("Message: ${v.message}")
+ sb.appendLine("Location: ${v.location.file}:${v.location.startLine ?: "?"}-${v.location.endLine ?: "?"}")
+ v.confidence?.let { sb.appendLine("Confidence: $it") }
+ v.raw?.let { sb.appendLine("Raw: $it") }
+ sb.appendLine()
+ }
+ } else {
+ sb.appendLine("No violations reported.")
+ }
+
+ if (result.failures.isNotEmpty()) {
+ sb.appendLine("Guardian Failures:")
+ result.failures.forEachIndexed { index, f ->
+ sb.appendLine("#${index + 1} - ${f.guardian}: ${f.message}")
+ }
+ sb.appendLine()
+ }
+
+ if (result.files.isNotEmpty()) {
+ sb.appendLine("Analyzed files:")
+ result.files.forEach { f -> sb.appendLine("- ${f.name}") }
+ }
+ return sb.toString()
+ }
+
+ private fun buildExchangeText(event: StreamEvent.InvalidLlmOutputWarning): String {
+ val sb = StringBuilder()
+ sb.appendLine("Input messages:")
+ event.chatExchange.input.forEachIndexed { idx, msg ->
+ sb.appendLine("#${idx + 1} ${msg.role}:")
+ sb.appendLine(msg.content)
+ sb.appendLine()
+ }
+ sb.appendLine("Model output:")
+ sb.appendLine(event.chatExchange.output)
+ sb.appendLine()
+ sb.appendLine("Parse errors:")
+ event.parseErrors.forEachIndexed { index, error ->
+ sb.appendLine("#${index + 1}: $error")
+ }
+ return sb.toString()
+ }
+
fun mapException(exception: Exception): UiStreamEvent.Message {
return UiStreamEvent.Message(
title = SecureCoderBundle.message("error.uncaught.title"),
description = SecureCoderBundle.message(
"error.uncaught.description",
- exception.message ?: "N/A",
+ exception.message ?: SecureCoderBundle.message("common.notAvailable"),
exception.javaClass.simpleName
),
icon = AllIcons.General.Error
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/UiStreamEvent.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/UiStreamEvent.kt
index 0800b0e..0ba87f3 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/UiStreamEvent.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/engine/event/UiStreamEvent.kt
@@ -3,12 +3,32 @@ package de.tuda.stg.securecoder.plugin.engine.event
import com.intellij.icons.AllIcons
import de.tuda.stg.securecoder.engine.file.edit.Changes
import de.tuda.stg.securecoder.engine.stream.EventIcon
+import de.tuda.stg.securecoder.engine.stream.ProposalId
import javax.swing.Icon
sealed interface UiStreamEvent {
- data class Message(val title: String, val description: String, val icon: Icon) : UiStreamEvent
+ data class Message(
+ val title: String,
+ val description: String,
+ val icon: Icon,
+ val debugText: String? = null
+ ) : UiStreamEvent
- data class EditFiles(val changes: Changes) : UiStreamEvent
+ data class EditFiles(
+ val changes: Changes,
+ val proposalId: ProposalId,
+ val validation: EditFilesValidation,
+ ) : UiStreamEvent
+
+ sealed interface EditFilesValidation {
+ object NotAvailable : EditFilesValidation
+ object Running : EditFilesValidation
+ object Succeeded : EditFilesValidation
+ data class Failed(
+ val summary: String,
+ val details: String,
+ ) : EditFilesValidation
+ }
}
fun EventIcon.toIntellijIcon(): Icon = when (this) {
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/CodeQLInstaller.java b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/CodeQLInstaller.java
index e856a86..3ba5448 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/CodeQLInstaller.java
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/CodeQLInstaller.java
@@ -59,7 +59,7 @@ private String resolveCodeQLVersion(ProgressIndicator indicator) {
try {
return fetchLatestVersion();
} catch (IOException e) {
- LOG.warn(SecureCoderBundle.INSTANCE.message("codeql.fetchLatestVersion.failed", FALLBACK_VERSION), e);
+ LOG.warn("Failed to fetch latest CodeQL version from GitHub API. Falling back to " + FALLBACK_VERSION, e);
return FALLBACK_VERSION;
}
}
@@ -76,13 +76,13 @@ private String fetchLatestVersion() throws IOException {
LOG.info("Detected latest CodeQL version: " + version);
return version;
}
- throw new IOException(SecureCoderBundle.INSTANCE.message("codeql.parseVersion.error"));
+ throw new IOException("Could not parse version from GitHub API response");
});
}
private void installCodeQL(String version, Path installDir, ProgressIndicator indicator) throws IOException {
String downloadUrl = getDownloadUrl(version);
- LOG.info(SecureCoderBundle.INSTANCE.message("codeql.downloading.from", downloadUrl));
+ LOG.info("Downloading CodeQL from: " + downloadUrl);
File tempZip = FileUtil.createTempFile("codeql", ".zip");
@@ -102,7 +102,7 @@ private void installCodeQL(String version, Path installDir, ProgressIndicator in
return parent != null && "bin".equals(parent.getFileName().toString()) && Files.isRegularFile(p);
}).forEach(this::setExecutablePermissions);
} catch (IOException e) {
- LOG.warn(SecureCoderBundle.INSTANCE.message("codeql.walkToolsDir.failed", toolsDir.toString()), e);
+ LOG.warn("Failed to walk tools directory for permissions: " + toolsDir.toString(), e);
}
}
setExecutablePermissions(executable);
@@ -127,7 +127,7 @@ private String getDownloadUrl(String version) {
} else if (SystemInfo.isLinux) {
platform = "linux64";
} else {
- throw new IllegalStateException(SecureCoderBundle.INSTANCE.message("codeql.unsupported.os", SystemInfo.OS_NAME));
+ throw new IllegalStateException("Unsupported operating system: " + SystemInfo.OS_NAME);
}
return DOWNLOAD_BASE_URL + version + "/codeql-" + platform + ".zip";
}
@@ -136,10 +136,10 @@ private void setExecutablePermissions(Path executable) {
try {
File file = executable.toFile();
if (!file.setExecutable(true, true)) {
- throw new IOException(SecureCoderBundle.INSTANCE.message("codeql.setPermissions.failed", executable.toString()));
+ throw new IOException("");
}
} catch (Exception e) {
- LOG.warn(SecureCoderBundle.INSTANCE.message("codeql.setPermissions.failed", executable.toString()), e);
+ LOG.warn("Failed to set executable permissions for: " + executable, e);
}
}
}
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsConfigurable.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsConfigurable.kt
index 860d3c6..7bc59a8 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsConfigurable.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsConfigurable.kt
@@ -162,4 +162,12 @@ class SecureCoderSettingsConfigurable : BoundConfigurable(SecureCoderBundle.mess
}.enabledIf(codeql.selected)
}
}
+
+ override fun apply() {
+ super.apply()
+ ApplicationManager.getApplication()
+ .messageBus
+ .syncPublisher(SecureCoderSettingsState.topic)
+ .settingsChanged(settings.state)
+ }
}
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsState.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsState.kt
index 5a5e883..b6c4516 100644
--- a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsState.kt
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/settings/SecureCoderSettingsState.kt
@@ -4,6 +4,7 @@ import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
+import com.intellij.util.messages.Topic
@State(name = "SecureCoderSettings", storages = [Storage("SecureCoderSettings.xml")])
@Service(Service.Level.APP)
@@ -22,7 +23,7 @@ class SecureCoderSettingsState : PersistentStateComponent = Topic.create(
+ "SecureCoderSettingsChanged",
+ SecureCoderSettingsListener::class.java
+ )
+ }
private var state: StateData = StateData()
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/EventsPanel.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/EventsPanel.kt
new file mode 100644
index 0000000..1f9b46c
--- /dev/null
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/EventsPanel.kt
@@ -0,0 +1,157 @@
+package de.tuda.stg.securecoder.plugin.toolwindow
+
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.ui.DialogWrapper
+import com.intellij.ui.components.IconLabelButton
+import com.intellij.ui.components.JBScrollPane
+import com.intellij.util.ui.JBFont
+import com.intellij.util.ui.JBUI
+import de.tuda.stg.securecoder.plugin.edit.buildEditFilesPanel
+import de.tuda.stg.securecoder.plugin.SecureCoderBundle
+import de.tuda.stg.securecoder.plugin.engine.IntelliJProjectFileSystem
+import de.tuda.stg.securecoder.plugin.engine.event.UiStreamEvent
+import de.tuda.stg.securecoder.plugin.engine.event.UiStreamEvent.EditFilesValidation
+import java.awt.Component
+import java.awt.Dimension
+import javax.swing.BorderFactory
+import javax.swing.Box
+import javax.swing.BoxLayout
+import javax.swing.JButton
+import javax.swing.JComponent
+import javax.swing.JLabel
+import javax.swing.JPanel
+import javax.swing.JTextArea
+
+object EventsPanel {
+ fun addEventCard(event: UiStreamEvent, project: Project): JPanel {
+ val card = object : JPanel() {
+ override fun getMaximumSize() = Dimension(Int.MAX_VALUE, preferredSize.height)
+ }.apply {
+ layout = BoxLayout(this, BoxLayout.Y_AXIS)
+ border = BorderFactory.createCompoundBorder(
+ JBUI.Borders.customLine(JBUI.CurrentTheme.CustomFrameDecorations.separatorForeground(), 1),
+ JBUI.Borders.empty(6)
+ )
+ }
+
+ val titlePanel = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.X_AXIS)
+ border = JBUI.Borders.emptyBottom(4)
+ alignmentX = Component.LEFT_ALIGNMENT
+ }
+ val title = when (event) {
+ is UiStreamEvent.Message -> event.title
+ is UiStreamEvent.EditFiles -> "Edit Files"
+ }
+ val icon = when (event) {
+ is UiStreamEvent.Message -> event.icon
+ is UiStreamEvent.EditFiles -> AllIcons.Actions.EditSource
+ }
+ val titleLabel = JLabel(title, icon, JLabel.LEADING).apply {
+ font = JBFont.label().asBold()
+ }
+ titlePanel.add(titleLabel)
+
+ if (event is UiStreamEvent.Message && event.debugText != null) {
+ val debugButton = IconLabelButton(
+ AllIcons.General.InspectionsEye,
+ { showDebugTextDialog(project, event.debugText) }
+ ).apply {
+ toolTipText = SecureCoderBundle.message("toolwindow.events.show.debug.tooltip")
+ }
+ titlePanel.add(Box.createHorizontalGlue())
+ titlePanel.add(debugButton)
+ }
+
+ val content = when (event) {
+ is UiStreamEvent.Message -> JTextArea(event.description).apply {
+ isEditable = false
+ lineWrap = true
+ wrapStyleWord = true
+ border = JBUI.Borders.empty()
+ background = card.background
+ alignmentX = Component.LEFT_ALIGNMENT
+ }
+ is UiStreamEvent.EditFiles -> buildEditFilesPanel(
+ project,
+ event.changes,
+ IntelliJProjectFileSystem(project)
+ )
+ }
+
+ card.add(titlePanel)
+ card.add(content)
+
+ if (event is UiStreamEvent.EditFiles) {
+ val bottomPanel = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.X_AXIS)
+ border = JBUI.Borders.emptyTop(6)
+ alignmentX = Component.LEFT_ALIGNMENT
+ }
+
+ when (val validation = event.validation) {
+ is EditFilesValidation.NotAvailable -> { /* no status shown */ }
+ is EditFilesValidation.Running -> bottomPanel.add(
+ JLabel(
+ SecureCoderBundle.message("validation.in_progress"),
+ AllIcons.Actions.Refresh,
+ JLabel.LEADING
+ )
+ )
+ is EditFilesValidation.Succeeded -> bottomPanel.add(
+ JLabel(
+ SecureCoderBundle.message("validation.succeeded"),
+ AllIcons.General.InspectionsOK,
+ JLabel.LEADING
+ )
+ )
+ is EditFilesValidation.Failed -> {
+ bottomPanel.add(
+ JLabel(
+ validation.summary,
+ AllIcons.General.Warning,
+ JLabel.LEADING
+ )
+ )
+ val showAllBtn = IconLabelButton(
+ AllIcons.General.InspectionsEye,
+ { showDebugTextDialog(project, validation.details) }
+ ).apply {
+ toolTipText = SecureCoderBundle.message("toolwindow.events.show.debug.tooltip")
+ alignmentX = Component.RIGHT_ALIGNMENT
+ }
+ bottomPanel.add(Box.createHorizontalGlue())
+ bottomPanel.add(showAllBtn)
+ }
+ }
+
+ if (bottomPanel.componentCount > 0) {
+ card.add(bottomPanel)
+ }
+ }
+ return card
+ }
+
+ private fun showDebugTextDialog(project: Project, text: String) {
+ object : DialogWrapper(project) {
+ init {
+ title = SecureCoderBundle.message("toolwindow.events.debug.title")
+ init()
+ setSize(800, 600)
+ }
+
+ override fun createCenterPanel(): JComponent {
+ val area = JTextArea(text).apply {
+ isEditable = false
+ lineWrap = true
+ wrapStyleWord = true
+ border = JBUI.Borders.empty()
+ }
+ return JBScrollPane(area).apply {
+ border = JBUI.Borders.empty()
+ }
+ }
+ }.showAndGet()
+ }
+}
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/NotConfiguredPanel.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/NotConfiguredPanel.kt
new file mode 100644
index 0000000..f0a2a9d
--- /dev/null
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/NotConfiguredPanel.kt
@@ -0,0 +1,43 @@
+package de.tuda.stg.securecoder.plugin.toolwindow
+
+import com.intellij.openapi.options.ShowSettingsUtil
+import com.intellij.openapi.project.Project
+import com.intellij.util.ui.JBFont
+import com.intellij.util.ui.JBUI
+import de.tuda.stg.securecoder.plugin.SecureCoderBundle
+import de.tuda.stg.securecoder.plugin.settings.SecureCoderSettingsConfigurable
+import java.awt.BorderLayout
+import java.awt.Component
+import java.awt.Dimension
+import javax.swing.Box
+import javax.swing.BoxLayout
+import javax.swing.JButton
+import javax.swing.JLabel
+import javax.swing.JPanel
+
+object NotConfiguredPanel {
+ fun build(project: Project): JPanel = JPanel(BorderLayout()).apply {
+ border = JBUI.Borders.empty(12)
+ val panel = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.Y_AXIS)
+ alignmentX = Component.LEFT_ALIGNMENT
+ }
+ val title = JLabel(SecureCoderBundle.message("toolwindow.notConfigured.title")).apply {
+ font = JBFont.h2()
+ border = JBUI.Borders.emptyBottom(6)
+ }
+ val desc = JLabel(SecureCoderBundle.message("toolwindow.notConfigured.desc"))
+ val openSettings = JButton(SecureCoderBundle.message("toolwindow.notConfigured.openSettings")).apply {
+ alignmentX = Component.LEFT_ALIGNMENT
+ addActionListener {
+ ShowSettingsUtil.getInstance()
+ .showSettingsDialog(project, SecureCoderSettingsConfigurable::class.java)
+ }
+ }
+ panel.add(title)
+ panel.add(desc)
+ panel.add(Box.createRigidArea(Dimension(0, JBUI.scale(8))))
+ panel.add(openSettings)
+ add(panel, BorderLayout.NORTH)
+ }
+}
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/PromptInputPanel.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/PromptInputPanel.kt
new file mode 100644
index 0000000..2766f4b
--- /dev/null
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/PromptInputPanel.kt
@@ -0,0 +1,105 @@
+package de.tuda.stg.securecoder.plugin.toolwindow
+
+import com.intellij.openapi.project.Project
+import com.intellij.ui.components.JBScrollPane
+import com.intellij.ui.components.JBTextArea
+import com.intellij.util.ui.JBUI
+import de.tuda.stg.securecoder.plugin.SecureCoderBundle
+import java.awt.Component
+import java.awt.Dimension
+import javax.swing.Box
+import javax.swing.BoxLayout
+import javax.swing.JButton
+import javax.swing.JCheckBox
+import javax.swing.JPanel
+import javax.swing.ScrollPaneConstants
+import com.intellij.openapi.ui.Messages
+
+class PromptInputPanel(
+ private val project: Project,
+ private val onSubmit: (promptText: String, projectAsContext: Boolean, onFinished: () -> Unit) -> Unit
+) {
+ val component: JPanel
+
+ private val inputArea: JBTextArea = JBTextArea().apply {
+ lineWrap = true
+ wrapStyleWord = true
+ rows = 5
+ columns = 30
+ border = JBUI.Borders.empty(8)
+ getEmptyText().setText(SecureCoderBundle.message("edit.placeholder"))
+ }
+
+ private fun wrapTextInScrollPane(): JBScrollPane = JBScrollPane(inputArea).apply {
+ verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
+ horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
+ }
+
+ init {
+ val scroll = wrapTextInScrollPane()
+ val preferredHeight = scroll.preferredSize.height
+ scroll.maximumSize = Dimension(Int.MAX_VALUE, preferredHeight)
+
+ val submit = JButton(SecureCoderBundle.message("toolwindow.submit")).apply {
+ maximumSize = Dimension(preferredSize.width, preferredHeight)
+ }
+
+ val checkBox = JCheckBox(SecureCoderBundle.message("toolwindow.useWholeProject"), true).apply {
+ alignmentX = Component.LEFT_ALIGNMENT
+ border = JBUI.Borders.emptyLeft(4)
+ toolTipText = SecureCoderBundle.message("toolwindow.useWholeProject.tooltip")
+ }
+
+ val textRow = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.X_AXIS)
+ border = JBUI.Borders.empty()
+ add(scroll.apply {
+ alignmentX = Component.LEFT_ALIGNMENT
+ maximumSize = Dimension(Int.MAX_VALUE, preferredHeight)
+ })
+ }
+
+ val controlsRow = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.X_AXIS)
+ border = JBUI.Borders.empty()
+ checkBox.alignmentY = Component.CENTER_ALIGNMENT
+ checkBox.maximumSize = checkBox.preferredSize
+ submit.alignmentY = Component.CENTER_ALIGNMENT
+ submit.maximumSize = Dimension(submit.preferredSize.width, submit.preferredSize.height)
+ add(checkBox)
+ add(Box.createHorizontalGlue())
+ add(submit)
+ }
+
+ component = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.Y_AXIS)
+ border = JBUI.Borders.empty(8)
+ alignmentX = Component.LEFT_ALIGNMENT
+ add(textRow)
+ add(Box.createRigidArea(Dimension(0, JBUI.scale(8))))
+ add(controlsRow)
+ }
+
+ submit.addActionListener {
+ val text = inputArea.text.trim()
+ if (text.isEmpty()) {
+ Messages.showWarningDialog(
+ project,
+ SecureCoderBundle.message("warning.emptyPrompt"),
+ SecureCoderBundle.message("product.name")
+ )
+ return@addActionListener
+ }
+
+ submit.isEnabled = false
+ submit.text = SecureCoderBundle.message("toolwindow.streaming")
+
+ val onFinished = {
+ submit.isEnabled = true
+ submit.text = SecureCoderBundle.message("toolwindow.submit")
+ }
+
+ onSubmit(text, checkBox.isSelected, onFinished)
+ }
+ }
+}
diff --git a/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/SecureCoderAiToolWindowFactory.kt b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/SecureCoderAiToolWindowFactory.kt
new file mode 100644
index 0000000..53722e0
--- /dev/null
+++ b/app/intellij-plugin/src/main/java/de/tuda/stg/securecoder/plugin/toolwindow/SecureCoderAiToolWindowFactory.kt
@@ -0,0 +1,136 @@
+package de.tuda.stg.securecoder.plugin.toolwindow
+
+import com.intellij.icons.AllIcons
+import com.intellij.openapi.actionSystem.AnAction
+import com.intellij.openapi.actionSystem.AnActionEvent
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.application.EDT
+import com.intellij.openapi.components.service
+import com.intellij.openapi.options.ShowSettingsUtil
+import com.intellij.openapi.project.DumbAware
+import com.intellij.openapi.project.Project
+import com.intellij.openapi.wm.ToolWindow
+import com.intellij.openapi.wm.ToolWindowFactory
+import com.intellij.ui.components.JBScrollPane
+import com.intellij.ui.content.ContentFactory
+import com.intellij.util.ui.JBUI
+import de.tuda.stg.securecoder.engine.stream.ProposalId
+import de.tuda.stg.securecoder.plugin.SecureCoderBundle
+import de.tuda.stg.securecoder.plugin.engine.EngineRunnerService
+import de.tuda.stg.securecoder.plugin.engine.event.UiStreamEvent
+import de.tuda.stg.securecoder.plugin.settings.SecureCoderSettingsConfigurable
+import de.tuda.stg.securecoder.plugin.settings.SecureCoderSettingsState
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.withContext
+import java.awt.BorderLayout
+import java.awt.Dimension
+import javax.swing.Box
+import javax.swing.BoxLayout
+import javax.swing.JPanel
+import javax.swing.ScrollPaneConstants
+import javax.swing.SwingUtilities
+
+class SecureCoderAiToolWindowFactory : ToolWindowFactory, DumbAware {
+ private lateinit var eventsPanel: JPanel
+ private lateinit var eventsScrollPane: JBScrollPane
+ private val editCardsByProposal = mutableMapOf()
+
+ private data class EditCardState(var event: UiStreamEvent.EditFiles, var panel: JPanel)
+
+ override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
+ val root = createRoot(project)
+ val contentFactory = ContentFactory.getInstance()
+ val content = contentFactory.createContent(root, null, false)
+ toolWindow.contentManager.addContent(content)
+ toolWindow.setIcon(AllIcons.Ultimate.Lock) // AllIcons.Ide.Readonly
+ toolWindow.setTitleActions(listOf(
+ object : AnAction(
+ SecureCoderBundle.message("toolwindow.settings"),
+ null,
+ AllIcons.General.Settings
+ ), DumbAware {
+ override fun actionPerformed(e: AnActionEvent) {
+ ShowSettingsUtil.getInstance()
+ .showSettingsDialog(project, SecureCoderSettingsConfigurable::class.java)
+ }
+ }
+ ))
+
+ val connection = ApplicationManager.getApplication().messageBus.connect(toolWindow.disposable)
+ connection.subscribe(
+ SecureCoderSettingsState.topic,
+ SecureCoderSettingsState.SecureCoderSettingsListener {
+ SwingUtilities.invokeLater {
+ content.component = createRoot(project)
+ }
+ })
+ }
+
+ private fun createRoot(project: Project): JPanel {
+ if (!service().state.hasLLMProviderConfigured()) {
+ return NotConfiguredPanel.build(project)
+ }
+
+ val root = JPanel(BorderLayout())
+
+ val promptPanel = PromptInputPanel(project) { promptText, projectAsContext, onFinished ->
+ val runner = project.service()
+ eventsPanel.removeAll()
+ eventsPanel.revalidate()
+ eventsPanel.repaint()
+ editCardsByProposal.clear()
+
+ runner.runEngine(
+ promptText,
+ onUiEvent = { event -> withContext(Dispatchers.EDT) {
+ addEventCard(event, project)
+ }},
+ onComplete = { withContext(Dispatchers.EDT) { onFinished() } },
+ reduceContextToOpenFiles = !projectAsContext
+ )
+ }
+ root.add(promptPanel.component, BorderLayout.NORTH)
+
+ eventsPanel = JPanel().apply {
+ layout = BoxLayout(this, BoxLayout.Y_AXIS)
+ border = JBUI.Borders.empty(8)
+ }
+ eventsScrollPane = JBScrollPane(eventsPanel).apply {
+ verticalScrollBarPolicy = ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
+ horizontalScrollBarPolicy = ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER
+ border = JBUI.Borders.empty()
+ }
+ root.add(eventsScrollPane, BorderLayout.CENTER)
+
+ return root
+ }
+
+ private fun addEventCard(
+ event: UiStreamEvent,
+ project: Project
+ ) {
+ val existingState = (event as? UiStreamEvent.EditFiles)?.let { editCardsByProposal[it.proposalId] }
+ val existingIndex = existingState?.panel?.let { eventsPanel.getComponentZOrder(it) } ?: -1
+ val card = EventsPanel.addEventCard(event, project)
+
+ if (existingIndex >= 0 && existingState != null) {
+ eventsPanel.remove(existingState.panel)
+ eventsPanel.add(card, existingIndex)
+ } else {
+ eventsPanel.add(card)
+ eventsPanel.add(Box.createRigidArea(Dimension(0, JBUI.scale(8))))
+ }
+
+ if (event is UiStreamEvent.EditFiles) {
+ editCardsByProposal[event.proposalId] = EditCardState(event, card)
+ }
+
+ eventsPanel.revalidate()
+ eventsPanel.repaint()
+
+ SwingUtilities.invokeLater {
+ val vBar = eventsScrollPane.verticalScrollBar
+ vBar.value = vBar.maximum
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/intellij-plugin/src/main/resources/META-INF/plugin.xml b/app/intellij-plugin/src/main/resources/META-INF/plugin.xml
index 8fd1fa1..ff76646 100644
--- a/app/intellij-plugin/src/main/resources/META-INF/plugin.xml
+++ b/app/intellij-plugin/src/main/resources/META-INF/plugin.xml
@@ -2,7 +2,7 @@
de.tuda.securecoderSecureCoderSoftware Technology Group at TU Darmstadt
- 0.0.2
+ 0.0.3
@@ -13,7 +13,7 @@
+ factoryClass="de.tuda.stg.securecoder.plugin.toolwindow.SecureCoderAiToolWindowFactory"/>
("run") {
- val keys = listOf(
- "OPENROUTER_KEY",
- "MODEL",
- "OLLAMA_BASE_URL",
- "OLLAMA_KEEP_ALIVE",
- "PORT"
- )
- keys.forEach { key ->
- System.getProperty(key)?.let { value ->
- systemProperty(key, value)
- }
- }
+ mainClass.set("de.tuda.stg.securecoder.openaibridge.MainKt")
}
diff --git a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/AgentService.kt b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/AgentService.kt
similarity index 94%
rename from app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/AgentService.kt
rename to app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/AgentService.kt
index 92bd6c9..31a6d09 100644
--- a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/AgentService.kt
+++ b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/AgentService.kt
@@ -1,4 +1,4 @@
-package de.tuda.stg.securecoder.openapibridge
+package de.tuda.stg.securecoder.openaibridge
import de.tuda.stg.securecoder.engine.Engine
import de.tuda.stg.securecoder.engine.file.edit.ApplyChanges.applyEdits
@@ -14,7 +14,7 @@ class AgentService(private val engine: Engine) {
val fileSystem = InMemoryFileSystem()
val userPrompt = messages.lastOrNull { it.role == "user" }?.content ?: ""
val result = engine.run(
- prompt = userPrompt,
+ prompt = "$userPrompt\nOnly create ONE file!",
filesystem = fileSystem,
onEvent = { event ->
println("Internal Agent Event: $event")
diff --git a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/EngineFactory.kt b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/EngineFactory.kt
similarity index 96%
rename from app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/EngineFactory.kt
rename to app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/EngineFactory.kt
index 0c1adf4..577518b 100644
--- a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/EngineFactory.kt
+++ b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/EngineFactory.kt
@@ -1,4 +1,4 @@
-package de.tuda.stg.securecoder.openapibridge
+package de.tuda.stg.securecoder.openaibridge
import de.tuda.stg.securecoder.engine.Engine
import de.tuda.stg.securecoder.engine.llm.LlmClient
diff --git a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/Main.kt b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/Main.kt
similarity index 94%
rename from app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/Main.kt
rename to app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/Main.kt
index 7336b9d..b3479ed 100644
--- a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/Main.kt
+++ b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/Main.kt
@@ -1,4 +1,4 @@
-package de.tuda.stg.securecoder.openapibridge
+package de.tuda.stg.securecoder.openaibridge
import io.ktor.serialization.kotlinx.json.json
import io.ktor.server.application.install
diff --git a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/OpenAIRoutes.kt b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/OpenAIRoutes.kt
similarity index 89%
rename from app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/OpenAIRoutes.kt
rename to app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/OpenAIRoutes.kt
index a1e69f4..6f286a8 100644
--- a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/OpenAIRoutes.kt
+++ b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/OpenAIRoutes.kt
@@ -1,4 +1,4 @@
-package de.tuda.stg.securecoder.openapibridge
+package de.tuda.stg.securecoder.openaibridge
import io.ktor.server.request.*
import io.ktor.server.response.*
diff --git a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/OpenApiModels.kt b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/OpenApiModels.kt
similarity index 94%
rename from app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/OpenApiModels.kt
rename to app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/OpenApiModels.kt
index fbc7f36..0656bb0 100644
--- a/app/openapi-bridge/src/main/java/de/tuda/stg/securecoder/openapibridge/OpenApiModels.kt
+++ b/app/openai-bridge/src/main/java/de/tuda/stg/securecoder/openaibridge/OpenApiModels.kt
@@ -1,4 +1,4 @@
-package de.tuda.stg.securecoder.openapibridge
+package de.tuda.stg.securecoder.openaibridge
import kotlinx.serialization.Serializable
diff --git a/app/openapi-bridge/README.md b/app/openapi-bridge/README.md
deleted file mode 100644
index 69cbd3a..0000000
--- a/app/openapi-bridge/README.md
+++ /dev/null
@@ -1,63 +0,0 @@
-# OpenAPI Bridge Server
-This module contains the HTTP server. It exposes a minimal OpenAI-style `POST /v1/chat/completions` endpoint backed by the SecureCoder engine.
-
-## Prerequisites
-- JDK 21
-- Optional but recommended for security analysis features: CodeQL CLI in `PATH` (the Guardian uses it when analyzing code). If not present, some security analysis steps may fail.
-
-
-## Configuration (Environment Variables or -D system properties)
-The server reads its configuration from either environment variables or JVM system properties (`-DNAME=value`).
-
-- `PORT` — HTTP port (default: `8080`)
-- LLM selection (EngineFactory picks the first matching provider):
- - OpenRouter mode:
- - `OPENROUTER_KEY` — your OpenRouter API key
- - `MODEL` — model ID (default: `openai/gpt-oss-20b`)
- - Ollama mode (used when `OPENROUTER_KEY` is not set):
- - `MODEL` — Ollama model name, e.g. `llama3.1:8b`
- - `OLLAMA_BASE_URL` — base URL to Ollama (default: `http://127.0.0.1:11434`)
- - `OLLAMA_KEEP_ALIVE` — keep-alive duration (default: `5m`)
-
-
-## How to run the server
-
-On macOS/Linux (using -D system properties):
-
-```
-./gradlew :app:openapi-bridge:run -DOPENROUTER_KEY=... -DMODEL=...
-```
-
-Or with environment variables:
-
-```
-export OPENROUTER_KEY=...
-export MODEL=...
-./gradlew :app:openapi-bridge:run
-```
-
-On Windows
-
-```
-set OPENROUTER_KEY=...
-set MODEL=...
-gradlew.bat :app:openapi-bridge:run
-```
-
-## Endpoint
-
-- `POST /v1/chat/completions` — accepts a minimal OpenAI-style request and returns a single choice with the SecureCoder engine’s response.
-
-Example request (curl):
-
-```
-curl -X POST "http://localhost:8080/v1/chat/completions" \
- -H "Content-Type: application/json" \
- -d '{
- "model": "llama3.1:8b",
- "messages": [
- {"role": "user", "content": "Create a Java class named Hello with a main method that prints Hello"}
- ],
- "stream": false
- }'
-```
diff --git a/engine/build.gradle.kts b/engine/build.gradle.kts
index daf8cf1..0b4efbb 100644
--- a/engine/build.gradle.kts
+++ b/engine/build.gradle.kts
@@ -9,4 +9,7 @@ dependencies {
implementation(libs.ktor.client.java)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.serialization.json)
+ testImplementation(kotlin("test"))
+ testImplementation(libs.kotlinx.serialization.json)
+ testImplementation(libs.kotlinx.coroutines.core)
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/FilesInContextPromptBuilder.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/FilesInContextPromptBuilder.kt
similarity index 88%
rename from engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/FilesInContextPromptBuilder.kt
rename to engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/FilesInContextPromptBuilder.kt
index b073204..808cc0b 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/FilesInContextPromptBuilder.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/FilesInContextPromptBuilder.kt
@@ -1,15 +1,14 @@
-package de.tuda.stg.securecoder.engine.llm
+package de.tuda.stg.securecoder.engine.file
import de.tuda.stg.securecoder.filesystem.FileSystem
-
object FilesInContextPromptBuilder {
suspend fun build(files: Iterable, edit: Boolean = false) = buildString {
if (files.count() == 0) {
appendLine("You have no files in the context.")
appendLine("If you saw files they are only part of the prompt and dont exists yet!")
if (edit) {
- appendLine("You may create new files (keep in mind that searchedText needs to be empty in this case!)")
+ appendLine("You may create new files (keep in mind that searched text needs to be empty in this case!)")
}
return@buildString
}
@@ -20,4 +19,4 @@ object FilesInContextPromptBuilder {
appendLine("<<>>")
}
}
-}
+}
\ No newline at end of file
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/ApplyChanges.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/ApplyChanges.kt
index 23e459b..f1c216c 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/ApplyChanges.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/ApplyChanges.kt
@@ -21,6 +21,12 @@ object ApplyChanges {
return when (match) {
is Success.Append -> original + action.replaceText
is Success.Match -> buildString {
+ if (match.end > original.length) {
+ throw IllegalStateException(
+ "Match end index (${match.end}) is out of bounds for string of length ${original.length}. "
+ + "Range: [${match.start}, ${match.end}), Replacement: '${action.replaceText}'"
+ )
+ }
append(original, 0, match.start)
append(action.replaceText)
append(original, match.end, original.length)
@@ -41,7 +47,7 @@ object ApplyChanges {
}
}
- fun match(text: String, search: Changes.SearchedText): MatchResult {
+ fun match(text: String?, search: Changes.SearchedText): MatchResult {
return Matcher.RootMatcher.match(text, search)
}
@@ -50,8 +56,8 @@ object ApplyChanges {
val headerMessage: String = when (matchResult) {
is Error.NoMatch ->
"your *SEARCH* pattern not found in file $file"
- is Error.ReplaceOnEmpty ->
- "can only append to file $file as it is empty or does not exist but your *SEARCH* pattern is not empty"
+ is Error.ReplaceOnNotExistent ->
+ "can only append to file $file as it is does not exist but your *SEARCH* pattern is not empty"
is Error.MultipleMatch ->
"your *SEARCH* pattern has several matches in $file"
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/EditFilesLlmWrapper.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/EditFilesLlmWrapper.kt
index 48f3f9f..583622c 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/EditFilesLlmWrapper.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/EditFilesLlmWrapper.kt
@@ -5,6 +5,7 @@ import de.tuda.stg.securecoder.engine.llm.ChatMessage
import de.tuda.stg.securecoder.engine.llm.ChatMessage.Role
import de.tuda.stg.securecoder.engine.llm.LlmClient
import de.tuda.stg.securecoder.filesystem.FileSystem
+import de.tuda.stg.securecoder.engine.llm.ChatExchange
import kotlin.collections.plusAssign
class EditFilesLlmWrapper(
@@ -40,20 +41,20 @@ class EditFilesLlmWrapper(
messages: List,
fileSystem: FileSystem,
params: LlmClient.GenerationParams = LlmClient.GenerationParams(),
- onParseError: suspend (List) -> Unit = {},
+ onParseError: suspend (parseErrors: List, llm: ChatExchange) -> Unit = { _, _ -> },
attempts: Int = 3
): ChatResult {
val messages = messages.toMutableList()
- messages += ChatMessage(Role.System, prompt)
+ appendPromptToLastSystem(messages)
repeat(attempts) {
- val response = llmClient.chat(messages, params)
+ val llmInput = messages.toList()
+ val response = llmClient.chat(llmInput, params)
messages += ChatMessage(Role.Assistant, response)
when (val result = parse(response, fileSystem)) {
is ParseResult.Ok -> return ChatResult(messages, result.value)
is ParseResult.Err -> {
- println("LLM parse failed: ${result.buildMessage()}")
messages += ChatMessage(Role.User, result.buildMessage())
- onParseError(result.messages)
+ onParseError(result.messages, ChatExchange(llmInput, response))
}
}
}
@@ -72,7 +73,7 @@ class EditFilesLlmWrapper(
appendLine("It violated the required format.")
appendLine("Errors:")
messages.forEach { appendLine(it) }
- appendLine("Respond again with ONLY blocks that strictly follow the rules. Do NOT include prose, markdown, or explanations.")
+ appendLine("Respond again with ONLY edit blocks that strictly follow the rules. Do NOT include prose, markdown, or explanations.")
appendLine("IMPORTANT: Resend the COMPLETE set of edits you intend to apply from your previous message")
}
}
@@ -83,14 +84,30 @@ class EditFilesLlmWrapper(
val allErrors = mutableListOf()
val contentCopy = if (content.endsWith("\n")) content else content + "\n"
val editsRegex = Regex(
- "(.*?)", setOf(
- RegexOption.MULTILINE, RegexOption.DOT_MATCHES_ALL
- )
+ "(.*?)",
+ setOf(RegexOption.MULTILINE, RegexOption.DOT_MATCHES_ALL)
)
val matches = editsRegex.findAll(contentCopy).toList()
if (matches.isEmpty()) {
- allErrors += "Did not find any *SEARCH/REPLACE* block within the `` tag"
+ allErrors += """
+ Could not find any edit blocks in the response.
+ Example for the expected format:
+
+ src/Main.java
+
+ ...exact old text...
+
+
+ ...new text...
+
+
+
+ src/new.java
+
+ append
+
+ """.trimIndent()
return ParseResult.Err(allErrors)
}
@@ -122,7 +139,7 @@ class EditFilesLlmWrapper(
continue
}
val replace = Changes.SearchReplace(currentFileName, SearchedText(searchPart ?: ""), replacePart ?: "")
- val content = fileSystem.getFile(currentFileName)?.content() ?: ""
+ val content = fileSystem.getFile(currentFileName)?.content()
val match = ApplyChanges.match(content, replace.searchedText)
if (match is Matcher.MatchResult.Error) {
allErrors += ApplyChanges.buildErrorMessage(currentFileName, searchPart ?: "", match)
@@ -135,16 +152,14 @@ class EditFilesLlmWrapper(
return ParseResult.Err(allErrors)
}
- val seen = HashSet>()
- val deduped = results.filter { sr ->
- seen.add(sr.fileName to sr.searchedText.text)
- }
-
- return ParseResult.Ok(Changes(deduped))
+ return ParseResult.Ok(Changes(results))
}
private fun getTextByXMLTag(container: String, tag: String): String? {
- val regex = Regex("<$tag>(.*?)$tag>", setOf(RegexOption.MULTILINE, RegexOption.DOT_MATCHES_ALL))
+ val regex = Regex(
+ "<$tag>(.*?)$tag>",
+ setOf(RegexOption.MULTILINE, RegexOption.DOT_MATCHES_ALL)
+ )
return regex.find(container)?.groups?.get(1)?.value
}
@@ -152,4 +167,15 @@ class EditFilesLlmWrapper(
if (content == null) return null
return content.replaceFirst(Regex("^\\n"), "")
}
+
+ private fun appendPromptToLastSystem(messages: MutableList) {
+ val lastSystemIndex = messages.indexOfLast { it.role == Role.System }
+ if (lastSystemIndex >= 0) {
+ val existing = messages[lastSystemIndex]
+ val combined = "${existing.content}\n\n$prompt"
+ messages[lastSystemIndex] = ChatMessage(Role.System, combined)
+ } else {
+ messages += ChatMessage(Role.System, prompt)
+ }
+ }
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/Matcher.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/Matcher.kt
index 445620a..b442e7b 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/Matcher.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/Matcher.kt
@@ -6,25 +6,31 @@ import de.tuda.stg.securecoder.engine.file.edit.Matcher.MatchResult.Success
interface Matcher {
sealed interface MatchResult {
sealed interface Error : MatchResult {
- object ReplaceOnEmpty : Error
+ object ReplaceOnNotExistent : Error
object NoMatch : Error
data class MultipleMatch (val matches: List) : Error
}
sealed interface Success : MatchResult {
object Append : Success
- class Match (val start: Int, val end: Int) : Success
+ class Match (val start: Int, val end: Int) : Success {
+ init {
+ require(end >= start) {
+ "End index ($end) cannot be less than start index ($start)"
+ }
+ }
+ }
}
}
- fun match(text: String, search: Changes.SearchedText): MatchResult
+ fun match(text: String?, search: Changes.SearchedText): MatchResult
object RootMatcher : Matcher {
- override fun match(text: String, search: Changes.SearchedText): MatchResult {
+ override fun match(text: String?, search: Changes.SearchedText): MatchResult {
if (search.isAppend()) {
return Success.Append
}
- if (text.isEmpty()) {
- return Error.ReplaceOnEmpty
+ if (text == null) {
+ return Error.ReplaceOnNotExistent
}
val matchers = listOf(IndexOfMatcher, TrimmedLinesMatcher)
matchers.forEach {
@@ -37,9 +43,12 @@ interface Matcher {
object IndexOfMatcher : Matcher {
override fun match(
- text: String,
+ text: String?,
search: Changes.SearchedText
): MatchResult {
+ if (text == null) {
+ return Error.NoMatch
+ }
val idx = text.indexesOf(search.text)
return when (idx.size) {
1 -> Success.Match(idx.first(), idx.first() + search.text.length)
@@ -63,7 +72,10 @@ interface Matcher {
}
object TrimmedLinesMatcher : Matcher {
- override fun match(text: String, search: Changes.SearchedText): MatchResult {
+ override fun match(text: String?, search: Changes.SearchedText): MatchResult {
+ if (text == null) {
+ return Error.NoMatch
+ }
val searchedTrimmed = splitToLinesAndTrimLast(search.text).map { it.trim() }
val documentLines = text.split("\n")
val documentLinesTrimmed = documentLines.map { it.trim() }
@@ -81,7 +93,8 @@ interface Matcher {
val lineStarts = IntArray(documentLines.size + 1)
for (i in documentLines.indices) {
- lineStarts[i + 1] = lineStarts[i] + documentLines[i].length + 1
+ val newline = if (i < documentLines.lastIndex) 1 else 0
+ lineStarts[i + 1] = lineStarts[i] + documentLines[i].length + newline
}
val startOffset = lineStarts[firstLine]
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/StructuredEditFilesLlmWrapper.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/StructuredEditFilesLlmWrapper.kt
new file mode 100644
index 0000000..2f3c58a
--- /dev/null
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/file/edit/StructuredEditFilesLlmWrapper.kt
@@ -0,0 +1,137 @@
+package de.tuda.stg.securecoder.engine.file.edit
+
+import de.tuda.stg.securecoder.engine.file.edit.Changes.SearchedText
+import de.tuda.stg.securecoder.engine.llm.ChatMessage
+import de.tuda.stg.securecoder.engine.llm.ChatMessage.Role
+import de.tuda.stg.securecoder.engine.llm.LlmClient
+import de.tuda.stg.securecoder.engine.llm.LLMDescription
+import de.tuda.stg.securecoder.engine.llm.chatStructured
+import de.tuda.stg.securecoder.filesystem.FileSystem
+import de.tuda.stg.securecoder.engine.llm.ChatExchange
+import kotlinx.serialization.Serializable
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+import kotlin.collections.plusAssign
+
+class StructuredEditFilesLlmWrapper(
+ private val llmClient: LlmClient
+) {
+ //TODO path => **uri** ; EditFilesLlmWrapper should be separate from the filesystem implementation
+ private val prompt = """
+ Your task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!
+
+ It's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.
+ To create a file: search must be empty and replace must contain the entire file content
+ Each *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.
+ Do not use a part of the line as *search* pattern. You must use full lines.
+ Include enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.
+ Do not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.
+ Do not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.
+ Do not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.
+ Do not use the same value for *search* and *REPLACE* parameters, as this will make no changes.
+
+ If you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.
+ """.trimIndent()
+
+
+ suspend fun chat(
+ messages: List,
+ fileSystem: FileSystem,
+ params: LlmClient.GenerationParams = LlmClient.GenerationParams(),
+ onParseError: suspend (parseErrors: List, llm: ChatExchange) -> Unit = { _, _ -> },
+ attempts: Int = 3
+ ): ChatResult {
+ val messages = messages.toMutableList()
+ appendPromptToLastSystem(messages)
+ repeat(attempts) {
+ val llmInput = messages.toList()
+ val structured = llmClient.chatStructured(llmInput, params)
+ messages += ChatMessage(Role.Assistant, Json.encodeToString(structured))
+ when (val result = validateAndConvert(structured, fileSystem)) {
+ is ParseResult.Ok -> return ChatResult(messages, result.value)
+ is ParseResult.Err -> {
+ messages += ChatMessage(Role.User, result.buildMessage())
+ onParseError(result.messages, ChatExchange(llmInput, messages.last().content))
+ }
+ }
+ }
+ return ChatResult(messages, null)
+ }
+
+ data class ChatResult(val messages: List, val changes: Changes?) {
+ fun changesMessage() = messages.last { it.role == Role.Assistant }
+ }
+
+ sealed interface ParseResult {
+ data class Ok(val value: Changes) : ParseResult
+ data class Err(val messages: List) : ParseResult {
+ fun buildMessage() = buildString {
+ appendLine("Your previous output could not be applied.")
+ appendLine("It violated the required format.")
+ appendLine("Errors:")
+ messages.forEach { appendLine(it) }
+ appendLine("Respond again with ONLY edit blocks that strictly follow the rules. Do NOT include prose, markdown, or explanations.")
+ appendLine("IMPORTANT: Resend the COMPLETE set of edits you intend to apply from your previous message")
+ }
+ }
+ }
+
+ private suspend fun validateAndConvert(structured: StructuredEdits, fileSystem: FileSystem): ParseResult {
+ val results = mutableListOf()
+ val allErrors = mutableListOf()
+ if (structured.edits.isEmpty()) {
+ allErrors += "No edits provided. Provide at least one edit block."
+ return ParseResult.Err(allErrors)
+ }
+ for (e in structured.edits) {
+ val file = e.filePath.trim()
+ val searchPart = e.search
+ val replacePart = e.replace
+ if (file.isEmpty()) {
+ allErrors += "`filePath` should not be empty"
+ continue
+ }
+ if (searchPart == replacePart) {
+ allErrors += "`search` and `replace` parameters are the same"
+ continue
+ }
+ val replace = Changes.SearchReplace(file, SearchedText(searchPart), replacePart)
+ val content = fileSystem.getFile(file)?.content()
+ val match = ApplyChanges.match(content, replace.searchedText)
+ if (match is Matcher.MatchResult.Error) {
+ allErrors += ApplyChanges.buildErrorMessage(file, searchPart, match)
+ continue
+ }
+ results += replace
+ }
+ if (results.isEmpty()) return ParseResult.Err(allErrors)
+ return ParseResult.Ok(Changes(results))
+ }
+
+ private fun appendPromptToLastSystem(messages: MutableList) {
+ val lastSystemIndex = messages.indexOfLast { it.role == Role.System }
+ if (lastSystemIndex >= 0) {
+ val existing = messages[lastSystemIndex]
+ val combined = "${existing.content}\n\n$prompt\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations."
+ messages[lastSystemIndex] = ChatMessage(Role.System, combined)
+ } else {
+ messages += ChatMessage(Role.System, "$prompt\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.")
+ }
+ }
+
+ @Serializable
+ data class StructuredEdits(
+ @LLMDescription("List of edit operations to apply")
+ val edits: List
+ )
+
+ @Serializable
+ data class EditOperation(
+ @LLMDescription("The full **uri** of the file that will be modified")
+ val filePath: String,
+ @LLMDescription("A continuous, yet concise block of lines to search for in the existing source code (*search* pattern). If this section is empty, the lines from `replace` will be added to the end of the file.")
+ val search: String,
+ @LLMDescription("The lines to replace the existing code found using `search`. If this section is empty, the lines specified in `search` will be removed.")
+ val replace: String,
+ )
+}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatExchange.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatExchange.kt
new file mode 100644
index 0000000..c8aaf95
--- /dev/null
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatExchange.kt
@@ -0,0 +1,6 @@
+package de.tuda.stg.securecoder.engine.llm
+
+data class ChatExchange(
+ val input: List,
+ val output: String
+)
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatMessage.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatMessage.kt
index 6f92101..81668c4 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatMessage.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/ChatMessage.kt
@@ -1,5 +1,5 @@
package de.tuda.stg.securecoder.engine.llm
-class ChatMessage (val role: Role, val content: String) {
+data class ChatMessage (val role: Role, val content: String) {
enum class Role { System, User, Assistant }
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/KxJsonSchemaFormat.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/KxJsonSchemaFormat.kt
new file mode 100644
index 0000000..b71f180
--- /dev/null
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/KxJsonSchemaFormat.kt
@@ -0,0 +1,94 @@
+package de.tuda.stg.securecoder.engine.llm
+
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.descriptors.PolymorphicKind
+import kotlinx.serialization.descriptors.PrimitiveKind
+import kotlinx.serialization.descriptors.SerialDescriptor
+import kotlinx.serialization.descriptors.SerialKind
+import kotlinx.serialization.descriptors.StructureKind
+import kotlinx.serialization.json.JsonArray
+import kotlinx.serialization.json.JsonObject
+import kotlinx.serialization.json.JsonObjectBuilder
+import kotlinx.serialization.json.JsonPrimitive
+import kotlinx.serialization.json.buildJsonArray
+import kotlinx.serialization.json.buildJsonObject
+
+@OptIn(ExperimentalSerializationApi::class)
+class KxJsonSchemaFormat {
+ fun format(serializer: KSerializer): JsonObject =
+ schemaForDescriptor(serializer.descriptor, seen = HashSet())
+
+ private fun schemaForDescriptor(desc: SerialDescriptor, seen: MutableSet): JsonObject {
+ val key = desc.serialName
+ if (!seen.add(key)) {
+ throw IllegalStateException("Recursive type detected: $key")
+ }
+ val jsonType = when (desc.kind) {
+ PrimitiveKind.BOOLEAN -> type("boolean")
+ PrimitiveKind.BYTE, PrimitiveKind.SHORT, PrimitiveKind.INT, PrimitiveKind.LONG -> type("integer")
+ PrimitiveKind.FLOAT, PrimitiveKind.DOUBLE -> type("number")
+ PrimitiveKind.CHAR, PrimitiveKind.STRING -> type("string")
+ SerialKind.ENUM -> type("string") {
+ put("enum", buildJsonArray {
+ for (i in 0 until desc.elementsCount) {
+ add(JsonPrimitive(desc.getElementName(i)))
+ }
+ })
+ }
+ StructureKind.LIST -> type("array") {
+ put("items", schemaForDescriptor(desc.getElementDescriptor(0), seen))
+ }
+ StructureKind.MAP -> type("object") {
+ val keyDesc = desc.getElementDescriptor(0)
+ if (keyDesc.kind != PrimitiveKind.STRING) {
+ throw IllegalStateException("Map keys must be strings, but was ${keyDesc.serialName}")
+ }
+ put("additionalProperties", schemaForDescriptor(desc.getElementDescriptor(1), seen))
+ }
+ StructureKind.CLASS, StructureKind.OBJECT -> type("object") {
+ put("properties", buildJsonObject {
+ for (i in 0 until desc.elementsCount) {
+ val name = desc.getElementName(i)
+ val childDesc = desc.getElementDescriptor(i)
+ val childSchema = schemaForDescriptor(childDesc, seen)
+ val propDesc = getDescription(desc.getElementAnnotations(i))
+ put(name, if (propDesc != null) addDescription(childSchema, propDesc) else childSchema)
+ }
+ })
+ val required = JsonArray(desc.requiredElements().map { name -> JsonPrimitive(name) })
+ if (required.isNotEmpty()) put("required", required)
+ put("additionalProperties", JsonPrimitive(false))
+ }
+ PolymorphicKind.SEALED, PolymorphicKind.OPEN, SerialKind.CONTEXTUAL
+ -> throw IllegalStateException("Polymorphic types are not supported")
+ }
+ seen.remove(key)
+ if (desc.isNullable) {
+ throw IllegalStateException("Nullable types are not supported")
+ }
+ val selfDesc = getDescription(desc.annotations)
+ return if (selfDesc != null) addDescription(jsonType, selfDesc) else jsonType
+ }
+
+ private fun type(name: String, builderAction: JsonObjectBuilder.() -> Unit = {}): JsonObject =
+ buildJsonObject {
+ put("type", JsonPrimitive(name))
+ builderAction()
+ }
+
+ private fun SerialDescriptor.requiredElements(): List = (0 until elementsCount)
+ .filter { !isElementOptional(it) }
+ .map { getElementName(it) }
+
+ private fun JsonArray.isNotEmpty(): Boolean = this.size > 0
+
+ private fun getDescription(annotations: List): String? =
+ annotations.filterIsInstance().firstOrNull()?.text
+
+ private fun addDescription(obj: JsonObject, text: String): JsonObject =
+ buildJsonObject {
+ obj.forEach { (k, v) -> put(k, v) }
+ put("description", JsonPrimitive(text))
+ }
+}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LLMDescription.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LLMDescription.kt
new file mode 100644
index 0000000..c52dbed
--- /dev/null
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LLMDescription.kt
@@ -0,0 +1,10 @@
+package de.tuda.stg.securecoder.engine.llm
+
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.SerialInfo
+
+@OptIn(ExperimentalSerializationApi::class)
+@SerialInfo
+@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY)
+@Retention(AnnotationRetention.RUNTIME)
+annotation class LLMDescription(val text: String)
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LlmClient.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LlmClient.kt
index fb6633b..bed5da9 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LlmClient.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/LlmClient.kt
@@ -1,13 +1,27 @@
package de.tuda.stg.securecoder.engine.llm
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.serializer
+
interface LlmClient : AutoCloseable {
suspend fun chat(
messages: List,
params: GenerationParams = GenerationParams(),
): String
+ suspend fun chatStructured(
+ messages: List,
+ serializer: KSerializer,
+ params: GenerationParams = GenerationParams(),
+ ): T
+
data class GenerationParams(
val temperature: Double? = null,
val maxTokens: Int? = null
)
}
+
+suspend inline fun LlmClient.chatStructured(
+ messages: List,
+ params: LlmClient.GenerationParams = LlmClient.GenerationParams(),
+): T = this.chatStructured(messages, serializer(), params)
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OllamaClient.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OllamaClient.kt
index 6d7fe91..f81b694 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OllamaClient.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OllamaClient.kt
@@ -11,16 +11,20 @@ import io.ktor.http.*
import io.ktor.serialization.kotlinx.json.*
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
+import kotlinx.serialization.SerializationException
+import kotlinx.serialization.KSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.buildJsonObject
+import org.slf4j.LoggerFactory
class OllamaClient(
private val model: String,
baseUrl: String = "http://127.0.0.1:11434",
private val keepAlive: String = "5m",
) : LlmClient {
+ private val logger = LoggerFactory.getLogger("OllamaClient")
private val json: Json = Json {
ignoreUnknownKeys = true
explicitNulls = false
@@ -40,7 +44,8 @@ class OllamaClient(
val messages: List,
val stream: Boolean = false,
val options: JsonObject = buildJsonObject {},
- @SerialName("keep_alive") val keepAlive: String? = null
+ @SerialName("keep_alive") val keepAlive: String? = null,
+ val format: JsonObject? = null,
)
@Serializable
@@ -49,11 +54,11 @@ class OllamaClient(
val message: OllamaMsg
)
- override suspend fun chat(
- messages: List,
- params: GenerationParams
- ): String {
- val mapped = messages.map {
+ @Serializable
+ private data class OllamaError(val error: String)
+
+ private fun mapMessages(messages: List): List =
+ messages.map {
val role = when (it.role) {
Role.System -> "system"
Role.User -> "user"
@@ -62,29 +67,66 @@ class OllamaClient(
OllamaMsg(role, it.content)
}
- val options = buildJsonObject {
- params.temperature?.let { put("temperature", JsonPrimitive(it)) }
- params.maxTokens?.let { put("num_predict", JsonPrimitive(it)) }
- }
+ private fun buildOptions(params: GenerationParams) = buildJsonObject {
+ params.temperature?.let { put("temperature", JsonPrimitive(it)) }
+ params.maxTokens?.let { put("num_predict", JsonPrimitive(it)) }
+ }
- val req = OllamaChatRequest(
- model = model,
- messages = mapped,
- options = options,
- keepAlive = keepAlive
- )
- println("Sending llm request: $req")
+ private suspend fun performRequest(req: OllamaChatRequest): OllamaChatResponse {
+ logger.debug("Sending LLM request: {}", req)
val resp = http.post(endpoint) {
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
setBody(req)
}
val body = resp.bodyAsText()
- println("Got llm response: $body")
- val respObj = json.decodeFromString(body)
+ logger.debug("Got LLM response: {}", body)
+ if (!resp.status.isSuccess()) {
+ val errorMessage = try {
+ json.decodeFromString(body).error
+ } catch (_: SerializationException) {
+ body.ifBlank { "" }
+ }
+ throw RuntimeException("Failed to call Ollama got ${resp.status}: $errorMessage")
+ }
+ return json.decodeFromString(body)
+ }
+ override suspend fun chat(
+ messages: List,
+ params: GenerationParams
+ ): String {
+ val req = OllamaChatRequest(
+ model = model,
+ messages = mapMessages(messages),
+ options = buildOptions(params),
+ keepAlive = keepAlive
+ )
+ val respObj = performRequest(req)
return respObj.message.content
}
+ override suspend fun chatStructured(
+ messages: List,
+ serializer: KSerializer,
+ params: GenerationParams
+ ): T {
+ val schema = KxJsonSchemaFormat().format(serializer)
+ val req = OllamaChatRequest(
+ model = model,
+ messages = mapMessages(messages),
+ options = buildOptions(params),
+ keepAlive = keepAlive,
+ format = schema
+ )
+ val respObj = performRequest(req)
+ val content = respObj.message.content
+ return try {
+ json.decodeFromString(serializer, content)
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to decode Ollama structured content. Content: $content", e)
+ }
+ }
+
override fun close() = http.close()
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OpenRouterClient.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OpenRouterClient.kt
index abef7da..4149a82 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OpenRouterClient.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/llm/OpenRouterClient.kt
@@ -15,17 +15,22 @@ import io.ktor.http.HttpHeaders
import io.ktor.http.contentType
import io.ktor.http.isSuccess
import io.ktor.serialization.kotlinx.json.json
+import kotlinx.serialization.KSerializer
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
+import kotlinx.serialization.SerializationException
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.put
+import org.slf4j.LoggerFactory
class OpenRouterClient (
private val apiKey: String,
private val model: String,
private val siteName: String? = null,
) : LlmClient {
+ private val logger = LoggerFactory.getLogger("OpenRouterClient")
private val json: Json = Json {
ignoreUnknownKeys = true
explicitNulls = false
@@ -47,7 +52,8 @@ class OpenRouterClient (
val temperature: Double? = null,
@SerialName("max_tokens") val maxTokens: Int? = null,
val stream: Boolean = false,
- val metadata: JsonObject = buildJsonObject {}
+ val metadata: JsonObject = buildJsonObject {},
+ @SerialName("response_format") val responseFormat: JsonObject? = null,
)
@Serializable
@@ -56,11 +62,8 @@ class OpenRouterClient (
@Serializable
private data class OpenRouterChatResponse(val choices: List)
- override suspend fun chat(
- messages: List,
- params: LlmClient.GenerationParams
- ): String {
- val mapped = messages.map {
+ private fun mapMessages(messages: List): List =
+ messages.map {
val role = when (it.role) {
Role.System -> "system"
Role.User -> "user"
@@ -69,13 +72,10 @@ class OpenRouterClient (
OpenRouterMessage(role, it.content)
}
- val req = OpenRouterChatRequest(
- model = model,
- messages = mapped,
- temperature = params.temperature,
- maxTokens = params.maxTokens
- )
-
+ private suspend fun performRequest(
+ req: OpenRouterChatRequest,
+ ): OpenRouterChatResponse {
+ logger.debug("Sending LLM request: {}", req)
val resp: HttpResponse = http.post(endpoint) {
contentType(ContentType.Application.Json)
accept(ContentType.Application.Json)
@@ -85,16 +85,70 @@ class OpenRouterClient (
}
val body = resp.bodyAsText()
+ logger.debug("Got LLM response: {}", body)
if (!resp.status.isSuccess()) {
- error("OpenRouter Error ${resp.status.value}: $body")
+ val errorMessage = body.ifBlank { "" }
+ throw RuntimeException("OpenRouter Error ${resp.status.value}: $errorMessage")
+ }
+ return try {
+ json.decodeFromString(body)
+ } catch (e: SerializationException) {
+ val formattedBody = body.ifBlank { "" }
+ throw RuntimeException("Failed to parse OpenRouter response body. Raw body: $formattedBody", e)
}
+ }
- println("OpenRouter response: $body")
- val obj = json.decodeFromString(body)
+ override suspend fun chat(
+ messages: List,
+ params: LlmClient.GenerationParams
+ ): String {
+ val mapped = mapMessages(messages)
+
+ val req = OpenRouterChatRequest(
+ model = model,
+ messages = mapped,
+ temperature = params.temperature,
+ maxTokens = params.maxTokens
+ )
+ val obj = performRequest(req)
val content = obj.choices.firstOrNull()?.message?.content
- ?: error("OpenRouter lieferte keine Antwortnachricht.")
+ ?: error("OpenRouter did not return any response choices ")
return content
}
+ override suspend fun chatStructured(
+ messages: List,
+ serializer: KSerializer,
+ params: LlmClient.GenerationParams
+ ): T {
+ val mapped = mapMessages(messages)
+
+ val schema = KxJsonSchemaFormat().format(serializer)
+ val responseFormat = buildJsonObject {
+ put("type", "json_schema")
+ put("json_schema", buildJsonObject {
+ put("name", serializer.descriptor.serialName.ifBlank { "securecoder_schema" })
+ put("strict", true)
+ put("schema", schema)
+ })
+ }
+
+ val req = OpenRouterChatRequest(
+ model = model,
+ messages = mapped,
+ temperature = params.temperature,
+ maxTokens = params.maxTokens,
+ responseFormat = responseFormat
+ )
+ val obj = performRequest(req)
+ val content = obj.choices.firstOrNull()?.message?.content
+ ?: error("OpenRouter did not return any response choices ")
+ return try {
+ json.decodeFromString(serializer, content)
+ } catch (e: Exception) {
+ throw RuntimeException("Failed to decode OpenRouter structured content into ${'$'}{serializer.descriptor.serialName}. Content: ${'$'}content", e)
+ }
+ }
+
override fun close() = http.close()
}
\ No newline at end of file
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/ProposalId.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/ProposalId.kt
new file mode 100644
index 0000000..43194e6
--- /dev/null
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/ProposalId.kt
@@ -0,0 +1,11 @@
+package de.tuda.stg.securecoder.engine.stream
+
+import java.util.UUID
+
+data class ProposalId(val value: String) {
+ override fun toString(): String = value
+
+ companion object {
+ fun newId(): ProposalId = ProposalId(UUID.randomUUID().toString())
+ }
+}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/StreamEvent.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/StreamEvent.kt
index 016d48f..e07b7df 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/StreamEvent.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/stream/StreamEvent.kt
@@ -1,15 +1,40 @@
package de.tuda.stg.securecoder.engine.stream
import de.tuda.stg.securecoder.engine.file.edit.Changes
+import de.tuda.stg.securecoder.engine.llm.ChatExchange
+import de.tuda.stg.securecoder.engine.workflow.GuardianExecutor.GuardianResult
sealed interface StreamEvent {
- data class SendDebugMessage(val title: String, val description: String, val icon: EventIcon) : StreamEvent
+ data class SendDebugMessage(
+ val title: String,
+ val description: String,
+ val icon: EventIcon
+ ) : StreamEvent
- data class EditFiles(val changes: Changes) : StreamEvent
+ data class EnrichmentWarning(
+ val errorMessage: String
+ ) : StreamEvent
- data class EnrichmentWarning(val errorMessage: String) : StreamEvent
-
- data class GuardianWarning(val violations: String) : StreamEvent
-
- data class InvalidLlmOutputWarning(val parseErrors: List) : StreamEvent
+ data class InvalidLlmOutputWarning(
+ val parseErrors: List,
+ val chatExchange: ChatExchange
+ ) : StreamEvent
+
+ data class ProposedEdits(
+ val id: ProposalId,
+ val changes: Changes
+ ) : StreamEvent
+
+ data class ValidationStarted(
+ val id: ProposalId,
+ ) : StreamEvent
+
+ data class GuardianWarning(
+ val id: ProposalId,
+ val result: GuardianResult
+ ) : StreamEvent
+
+ data class ValidationSucceeded(
+ val id: ProposalId
+ ) : StreamEvent
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/GuardianExecutor.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/GuardianExecutor.kt
index 0d4535d..0d90c43 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/GuardianExecutor.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/GuardianExecutor.kt
@@ -21,10 +21,16 @@ class GuardianExecutor (
data class GuardianResult(
val violations: List,
val files: List,
+ val failures: List = emptyList(),
) {
fun hasNoViolations() = violations.isEmpty()
}
+ data class GuardianFailure(
+ val guardian: String,
+ val message: String,
+ )
+
suspend fun analyze(fileSystem: FileSystem, changes: Changes): GuardianResult {
val files = mutableListOf()
ApplyChanges.applyAll(
@@ -32,16 +38,26 @@ class GuardianExecutor (
{ fileSystem.getFile(it)?.content() },
{ file, content -> files.add(File(file, content)) }
)
- val request = AnalyzeRequest(fileSystem, files)
- val result = execute(request)
- return result
+ return execute(AnalyzeRequest(fileSystem, files))
}
private suspend fun execute(request: AnalyzeRequest): GuardianResult = coroutineScope {
+ data class Outcome(val violations: List, val failure: GuardianFailure?)
+
val deferred = guardians.map { guardian ->
- async(dispatcher) { guardian.run(request) }
+ async(dispatcher) {
+ try {
+ val resp = guardian.run(request)
+ Outcome(resp.violations, null)
+ } catch (throwable: Throwable) {
+ val name = guardian.javaClass.simpleName
+ Outcome(emptyList(), GuardianFailure(name, throwable.message ?: throwable.toString()))
+ }
+ }
}
- val violations = deferred.awaitAll().flatMap { it.violations }
- GuardianResult(violations, request.files)
+ val outcomes = deferred.awaitAll()
+ val violations = outcomes.flatMap { it.violations }
+ val failures = outcomes.mapNotNull { it.failure }
+ GuardianResult(violations, request.files, failures)
}
}
diff --git a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/WorkflowEngine.kt b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/WorkflowEngine.kt
index d8c15ae..cd333ac 100644
--- a/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/WorkflowEngine.kt
+++ b/engine/src/main/kotlin/de/tuda/stg/securecoder/engine/workflow/WorkflowEngine.kt
@@ -5,10 +5,11 @@ import de.tuda.stg.securecoder.engine.Engine.Context
import de.tuda.stg.securecoder.engine.Engine.EngineResult
import de.tuda.stg.securecoder.engine.llm.ChatMessage
import de.tuda.stg.securecoder.engine.llm.ChatMessage.Role
-import de.tuda.stg.securecoder.engine.file.edit.EditFilesLlmWrapper
-import de.tuda.stg.securecoder.engine.llm.FilesInContextPromptBuilder
+import de.tuda.stg.securecoder.engine.file.FilesInContextPromptBuilder
+import de.tuda.stg.securecoder.engine.file.edit.StructuredEditFilesLlmWrapper
import de.tuda.stg.securecoder.engine.llm.LlmClient
import de.tuda.stg.securecoder.engine.stream.StreamEvent
+import de.tuda.stg.securecoder.engine.stream.ProposalId
import de.tuda.stg.securecoder.engine.workflow.FeedbackBuilder.buildFeedbackForLlm
import de.tuda.stg.securecoder.enricher.PromptEnricher
import de.tuda.stg.securecoder.filesystem.FileSystem
@@ -19,9 +20,10 @@ class WorkflowEngine (
llmClient: LlmClient,
guardians: List = emptyList(),
private val maxGuardianRetries: Int = 6,
+ private val parseChangesAttempts: Int = 5,
) : Engine {
private val promptEnrichRunner = PromptEnrichRunner(enricher)
- private val editFiles = EditFilesLlmWrapper(llmClient)
+ private val editFiles = StructuredEditFilesLlmWrapper(llmClient)
private val guardianExecutor = GuardianExecutor(guardians)
override suspend fun run(
@@ -35,23 +37,28 @@ class WorkflowEngine (
val messages = mutableListOf(
ChatMessage(Role.System, "You are a Security Engineering Agent mainly for writing secure code"),
ChatMessage(Role.User, enrichedPrompt),
- ChatMessage(Role.System, FilesInContextPromptBuilder.build(filesInContext, edit = true)),
+ ChatMessage(Role.User, FilesInContextPromptBuilder.build(filesInContext, edit = true)),
)
repeat(maxGuardianRetries) {
val out = editFiles.chat(
messages = messages,
fileSystem = filesystem,
- onParseError = {
- onEvent(StreamEvent.InvalidLlmOutputWarning(it))
+ onParseError = { parseErrors, chatExchange ->
+ onEvent(StreamEvent.InvalidLlmOutputWarning(parseErrors, chatExchange))
},
+ attempts = parseChangesAttempts
)
messages += out.changesMessage()
val changes = out.changes ?: return EngineResult.Failure.GenerationFailure
+ val proposalId = ProposalId.newId()
+ onEvent(StreamEvent.ProposedEdits(proposalId, changes))
+ onEvent(StreamEvent.ValidationStarted(proposalId))
val guardianResult = guardianExecutor.analyze(filesystem, changes)
if (guardianResult.hasNoViolations()) {
+ onEvent(StreamEvent.ValidationSucceeded(proposalId))
return EngineResult.Success(changes)
}
- onEvent(StreamEvent.GuardianWarning(guardianResult.violations.toString()))
+ onEvent(StreamEvent.GuardianWarning(proposalId, guardianResult))
messages += ChatMessage(Role.User, guardianResult.buildFeedbackForLlm())
}
return EngineResult.Failure.ValidationFailure(maxGuardianRetries)
diff --git a/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/llm/LlmReplayModels.kt b/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/llm/LlmReplayModels.kt
new file mode 100644
index 0000000..e4314d2
--- /dev/null
+++ b/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/llm/LlmReplayModels.kt
@@ -0,0 +1,24 @@
+package de.tuda.stg.securecoder.engine.llm
+
+import kotlinx.serialization.Serializable
+
+@Serializable
+data class LoggedCall(
+ val requestHash: String,
+ val request: String,
+ val params: String,
+ val response: String,
+)
+
+@Serializable
+data class LoggedRun(
+ val modelName: String,
+ val promptKind: String,
+ val runIndex: Int,
+ val enginePrompt: String,
+ val initialFiles: Map,
+ val calls: List,
+)
+
+@Serializable
+data class LoggedSuite(val runs: List)
diff --git a/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/llm/LoggingAndReplayClients.kt b/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/llm/LoggingAndReplayClients.kt
new file mode 100644
index 0000000..a189d65
--- /dev/null
+++ b/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/llm/LoggingAndReplayClients.kt
@@ -0,0 +1,112 @@
+package de.tuda.stg.securecoder.engine.llm
+
+import kotlinx.serialization.KSerializer
+import kotlinx.serialization.json.Json
+import java.security.MessageDigest
+
+class LoggingLlmClient(
+ private val delegate: LlmClient
+) : LlmClient {
+ private val _calls = mutableListOf()
+ val calls: List get() = _calls
+
+ private fun appendLog(
+ requestHash: String,
+ messages: List,
+ params: LlmClient.GenerationParams,
+ response: String,
+ ) {
+ _calls += LoggedCall(
+ requestHash = requestHash,
+ request = messages.toString(),
+ params = params.toString(),
+ response = response,
+ )
+ }
+
+ override suspend fun chat(
+ messages: List,
+ params: LlmClient.GenerationParams
+ ): String {
+ val hash = computeHash(messages, params)
+ val response = delegate.chat(messages, params)
+ appendLog(hash, messages, params, response)
+ return response
+ }
+
+ override suspend fun chatStructured(
+ messages: List,
+ serializer: KSerializer,
+ params: LlmClient.GenerationParams
+ ): T {
+ val hash = computeHash(messages, params)
+ val result = delegate.chatStructured(messages, serializer, params)
+ val json = Json { encodeDefaults = true }
+ val response = json.encodeToString(serializer, result)
+ appendLog(hash, messages, params, response)
+ return result
+ }
+
+ override fun close() = delegate.close()
+
+ companion object Commons {
+ fun computeHash(
+ messages: List,
+ params: LlmClient.GenerationParams
+ ): String {
+ val payload = messages.toString() + params.toString()
+ val bytes = MessageDigest.getInstance("SHA-256").digest(payload.toByteArray(Charsets.UTF_8))
+ return bytes.toHexString()
+ }
+ }
+}
+
+class ReplayLlmClient(
+ private val loggedCalls: List
+) : LlmClient {
+ private var idx = 0
+
+ private fun mismatchError(
+ expected: LoggedCall,
+ calculated: String,
+ messages: List,
+ ): IllegalStateException = IllegalStateException(
+ buildString {
+ appendLine("ReplayLlmClient: input hash mismatch at call #$idx")
+ appendLine("expected: ${expected.requestHash}")
+ appendLine("actual: $calculated")
+ appendLine("expected (m): ${expected.request}")
+ appendLine("actual (m): $messages")
+ }
+ )
+
+ private fun verifyNext(
+ messages: List,
+ params: LlmClient.GenerationParams
+ ): LoggedCall {
+ if (idx >= loggedCalls.size) error("ReplayLlmClient: no more calls to replay (idx=$idx, size=${loggedCalls.size})")
+ val calculated = LoggingLlmClient.computeHash(messages, params)
+ val expected = loggedCalls[idx]
+ if (calculated != expected.requestHash) throw mismatchError(expected, calculated, messages)
+ idx++
+ return expected
+ }
+
+ override suspend fun chat(
+ messages: List,
+ params: LlmClient.GenerationParams
+ ): String {
+ return verifyNext(messages, params).response
+ }
+
+ override suspend fun chatStructured(
+ messages: List,
+ serializer: KSerializer,
+ params: LlmClient.GenerationParams
+ ): T {
+ val expected = verifyNext(messages, params)
+ return Json.decodeFromString(serializer, expected.response)
+ }
+
+ override fun close() {}
+}
diff --git a/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/workflow/EngineLlmReplayTests.kt b/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/workflow/EngineLlmReplayTests.kt
new file mode 100644
index 0000000..7489106
--- /dev/null
+++ b/engine/src/test/kotlin/de/tuda/stg/securecoder/engine/workflow/EngineLlmReplayTests.kt
@@ -0,0 +1,139 @@
+package de.tuda.stg.securecoder.engine.workflow
+
+import de.tuda.stg.securecoder.engine.Engine.EngineResult
+import de.tuda.stg.securecoder.engine.llm.*
+import de.tuda.stg.securecoder.engine.stream.StreamEvent
+import de.tuda.stg.securecoder.enricher.PromptEnricher
+import de.tuda.stg.securecoder.filesystem.InMemoryFileSystem
+import kotlinx.coroutines.runBlocking
+import kotlinx.serialization.ExperimentalSerializationApi
+import kotlinx.serialization.encodeToString
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.decodeFromStream
+import kotlin.test.Test
+import java.nio.file.Files
+import java.nio.file.Path
+import kotlin.test.Ignore
+import kotlin.test.assertIs
+import kotlin.test.assertTrue
+
+class EngineLlmReplayTests {
+ private val json = Json { prettyPrint = true; ignoreUnknownKeys = true; encodeDefaults = true }
+ private val resourceName = "llm_output.json"
+
+ @Test
+ @Ignore
+ fun generator_collects_real_llm_responses() = runBlocking {
+ val logsPath: Path = Path.of("src", "test", "resources", resourceName)
+ Files.createDirectories(logsPath.parent)
+
+ val prompts = listOf(
+ "create_project" to "Create a minimal Hello World project with one file Main.java printing Hello",
+ "edit_project" to "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ )
+
+ val models = buildList {
+ val apiKey = System.getenv("API_KEy") ?: "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"
+ //add("OR:llama3.2:latest" to OpenRouterClient(apiKey, "meta-llama/llama-3.2-3b-instruct"))
+ //add("OR:gpt-oss:20b" to OpenRouterClient(apiKey, "openai/gpt-oss-20b"))
+ val olBase = System.getenv("OLLAMA_URL") ?: "http://127.0.0.1:11434"
+ add("ollama:llama3.2:latest" to OllamaClient("llama3.2:latest", baseUrl = olBase))
+ add("ollama:gpt-oss:20b" to OllamaClient("gpt-oss:20b", baseUrl = olBase))
+ }
+
+ val runs = mutableListOf()
+ for ((modelName, rawClient) in models) {
+ rawClient.use { base ->
+ for ((kind, userPrompt) in prompts) {
+ repeat(15) { idx ->
+ println("Recording #${idx + 1} for $kind on $modelName")
+ val logging = LoggingLlmClient(base)
+ val fs = InMemoryFileSystem()
+ val initialFiles = when (kind) {
+ "edit_project" -> mapOf(
+ "src/Main.java" to """
+ public class Main {
+ public static void main(String[] args) {
+ System.out.println("Hello");
+ }
+ }
+ """.trimIndent()
+ )
+ else -> emptyMap()
+ }
+ for ((name, content) in initialFiles) fs.upsert(name, content)
+
+ val engine = WorkflowEngine(
+ enricher = PromptEnricher.PASSTHROUGH,
+ llmClient = logging,
+ guardians = emptyList(),
+ )
+ engine.run(userPrompt, fs, onEvent = { /* ignore */ }, context = null)
+ if (logging.calls.isEmpty()) throw IllegalStateException("No calls recorded!")
+ runs += LoggedRun(
+ modelName = modelName,
+ promptKind = kind,
+ runIndex = idx,
+ enginePrompt = userPrompt,
+ initialFiles = initialFiles,
+ calls = logging.calls.toList(),
+ )
+ }
+ }
+ }
+ }
+ val suite = LoggedSuite(runs)
+ Files.writeString(logsPath, json.encodeToString(suite))
+ println("Wrote logs to $logsPath")
+ }
+
+ @Test
+ @OptIn(ExperimentalSerializationApi::class)
+ fun test_replay() = runBlocking {
+ val resourceStream = this@EngineLlmReplayTests::class.java.classLoader.getResourceAsStream(resourceName)
+ ?: throw IllegalStateException("No $resourceName on classpath")
+ val suite: LoggedSuite = resourceStream.use { json.decodeFromStream(it) }
+
+ data class Group(
+ val modelName: String,
+ val promptKind: String,
+ var total: Int = 0,
+ var successes: Int = 0,
+ var parseFails: Int = 0
+ )
+ assertTrue(suite.runs.isNotEmpty())
+ suite.runs
+ .groupBy { it.modelName to it.promptKind }
+ .map { (key, runs) ->
+ val (model, kind) = key
+ val group = Group(model, kind)
+ for (run in runs) {
+ val fs = InMemoryFileSystem()
+ for ((name, content) in run.initialFiles) fs.upsert(name, content)
+
+ val client = ReplayLlmClient(run.calls)
+ val engine = WorkflowEngine(
+ PromptEnricher.PASSTHROUGH,
+ client,
+ guardians = emptyList(),
+ )
+ group.total++
+ val result = engine.run(run.enginePrompt, fs, onEvent = {
+ if (it !is StreamEvent.InvalidLlmOutputWarning) return@run
+ group.parseFails++
+ //println(it.parseErrors.joinToString("\n"))
+ //println(it.chatExchange.output)
+ })
+ if (result is EngineResult.Success) {
+ group.successes++
+ }
+ assertIs(result)
+ }
+ group
+ }
+ .forEach {
+ assertTrue(it.parseFails <= (1.5 * suite.runs.size))
+ //println("Group ${it.modelName} / ${it.promptKind}: replayed runs: ${it.total}, successes: ${it.successes} (${it.parseFails} parse failures)")
+ }
+ }
+}
diff --git a/engine/src/test/resources/llm_output.json b/engine/src/test/resources/llm_output.json
new file mode 100644
index 0000000..551e55f
--- /dev/null
+++ b/engine/src/test/resources/llm_output.json
@@ -0,0 +1,964 @@
+{
+ "runs": [
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 0,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\npublic static void main(String[] args) {\\n\\tSystem.out.println(\\\"Hello\\\");\\n}}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 1,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 2,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 3,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 4,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\n\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 5,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\npublic static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 6,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 7,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 8,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\"},{\"filePath\":\"Main.java\",\"search\":\"\\\\w+\\\\s+main\\\\s*\\\\(\",\"replace\":\"public static void main(String[] args) { println(\\\"Hello\\\"); }\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 9,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\"},{\"filePath\":\"Main.java\",\"search\":\"\\\\s*public\\\\s*class\\\\s+\",\"replace\":\"public class Hello {\\n\"},{\"filePath\":\"Main.java\",\"search\":\"\\\\s*Main\\\\s*\\\\{\",\"replace\":\"Hello {\\n\"},{\"filePath\":\"Main.java\",\"search\":\"\\\\s*System\\\\.out\\\\.println\\\\(\\\\)\",\"replace\":\"System.out.println(\\\"Hello\\\\);\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 10,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\t\\n\\tSystem.out.println(\\\"Hello\\\");\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 11,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 12,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\npublic static void main(String[] args) {\\nSystem.out.println(\\\"Hello\\\");\\n}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 13,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\npublic static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n}}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "create_project",
+ "runIndex": 14,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 0,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\\n\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"\",\"replace\":\"import java.util.Scanner;\\npublic class Main {\\n public static void main(String[] args) {\\n String name = \\\"John\\\";\\n System.out.println(Utils.greet(name));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 1,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"import java.util.function.Function;\\n\\npublic class Utils {\\n public static Function greet(String name) {\\n return () -> \\\"Hello, \\\" + name + \\\"!\\\";\\\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 2,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n\\n}\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"System\\\\.out\\\\.println\\\\(\\\"Hello\\\\\\\")\",\"replace\":\"System.out.println(\\\"Hello, \"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 3,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\npublic static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n}\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public\\\\s+static\\\\s+void\\\\s+main\\\\(String\\\\s+\\\\[args\\\\]\\\\s+)\\\\s*\\\\{\\\\s*System\\\\.out\\\\.println\\\\(\\\"Hello\\\"\\\\);\\\\s*}\\\\s*;\",\"replace\":\"public class Main {\\npublic static void main(String[] args) {\\n System.out.println(Utils.greet(args[0]));\\n}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 4,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n\\t\\n\\tpublic static String greet(String name) {\\n\\t\\treturn \\\"Hello, \\\\\\\" + name + \\\"!\\\\\\\"; \\n\\t}\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"\",\"replace\":\"\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 5,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name;\\n }\\n}\\n\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"System\\\\.out\\\\..*print\\\\(.*?\\\\);\\\\s*\\\\{\",\"replace\":\"System.out.println(greet(\\\"Main\\\"));\\\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 6,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 7,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"\",\"replace\":\"import org.example.Utils;\\n\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"System\\\\.out\\\\.println\\\\(\\\"Hello\\\\\\\")\",\"replace\":\"Utils\\\\.greet(\\\"World\\\")\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 8,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"import java.util.function Consumable;\\n\\npublic class Utils {\\n public static void greet(String name) {\\n System.out.println(\\\"Hello, \\\\\\\"+name\\\\'\\\");\\n }\\n}\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"\",\"replace\":\"import java.util.function Consumable;\\n\\npublic class Main {\\n public static void main(String[] args) {\\n Utils.greet(\\\"World\\\");\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 9,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\npublic static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n}\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"\\\\s*public\\\\s*static\\\\s*v\\\\s*main\\\\s*(\\\\(\\\\s*[\\\\s\\\\S]*\\\\)\\\\s*)\\\\s*\\\\{\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(args[0]));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 10,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\npublic static String greet(String name) {\\nreturn \\\"Hello, \\\\\\\" + name + '\\\\\\\"';\\n}\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"System\\\\.out\\\\.println\\\\(\\\"(.*?)\\\\\\\")\",\"replace\":\"System.out.println(Utils.greet($1));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 11,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Main.java\",\"search\":\"\",\"replace\":\"#import java.util.functionConsumer;\\n\\npublic class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"},{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"import java.util.functionConsumer;\\n\\npublic class Utils {\\n public static void greet(String name) {\\n System.out.println(\\\"Hello, \\\"+name+\\\"!\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 12,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {.*}.*public static void main\\\\(String\\\\[.*\\\\]\\\\)\",\"replace\":\"public class Main {\\n\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello, how are you?\\\");\\n Utils.greet(\\\"John\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 13,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Main.java\",\"search\":\"\",\"replace\":\"import com.example.Utils;\\n\\npublic class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"},{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name;\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:llama3.2:latest",
+ "promptKind": "edit_project",
+ "runIndex": 14,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n\\t\\n\\tpublic static void main(String[] args) {\\n\\tSystem.out.println(\\\"Hello\\\");\\n\\t}\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main\",\"replace\":\"import com.example.Utils;\\n\\npublic class Main {\\n\\tpublic static void main(String[] args) {\\n\\t\\tUtils.greet(\\\"World\\\");\\n\\t}\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 0,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 1,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 2,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 3,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 4,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 5,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 6,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 7,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 8,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 9,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 10,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 11,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 12,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 13,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "create_project",
+ "runIndex": 14,
+ "enginePrompt": "Create a minimal Hello World project with one file Main.java printing Hello",
+ "initialFiles": {},
+ "calls": [
+ {
+ "requestHash": "4508dfa643243496f170abe59fee1b9679a7ad1ad6d5d4efd62a0429a56b861b",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Create a minimal Hello World project with one file Main.java printing Hello), ChatMessage(role=User, content=You have no files in the context.\nIf you saw files they are only part of the prompt and dont exists yet!\nYou may create new files (keep in mind that searched text needs to be empty in this case!)\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"Main.java\",\"search\":\"\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 0,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\" System.out.println(\\\"Hello\\\");\",\"replace\":\" System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 1,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\" System.out.println(\\\"Hello\\\");\",\"replace\":\" System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 2,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"Alice\\\"));\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 3,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello \\\" + name;\\n }\\n}\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\\n\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n String name = args.length > 0 ? args[0] : \\\"World\\\";\\n System.out.println(Utils.greet(name));\\n }\\n}\\n\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 4,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"World\\\"));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 5,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name;\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\" System.out.println(\\\"Hello\\\");\",\"replace\":\" System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 6,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\"System.out.println(\\\"Hello\\\");\",\"replace\":\"System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 7,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\" System.out.println(\\\"Hello\\\");\",\"replace\":\" System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 8,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name;\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"World\\\"));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 9,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"World\\\"));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 10,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"World\\\"));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 11,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\" System.out.println(\\\"Hello\\\");\",\"replace\":\" System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 12,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello \\\" + name;\\n }\\n}\\n\"},{\"filePath\":\"src/Main.java\",\"search\":\" System.out.println(\\\"Hello\\\");\",\"replace\":\" System.out.println(Utils.greet(\\\"World\\\"));\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 13,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello \\\" + name;\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"Alice\\\"));\\n }\\n}\"}]}"
+ }
+ ]
+ },
+ {
+ "modelName": "ollama:gpt-oss:20b",
+ "promptKind": "edit_project",
+ "runIndex": 14,
+ "enginePrompt": "Modify the project to add a Utils.java with a function greet(name) and use it in Main.java",
+ "initialFiles": {
+ "src/Main.java": "public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}"
+ },
+ "calls": [
+ {
+ "requestHash": "720d4441caf38ea977c388a727df96d22d275e6426d8b54676cd3ae4c587cd66",
+ "request": "[ChatMessage(role=System, content=You are a Security Engineering Agent mainly for writing secure code\n\nYour task it is to produce code. The agent will just parse the code you produce. So dont do a extensive review in your final answer!\n\nIt's acceptable to add multiple *search/REPLACE* sections if you need to change multiple parts of the file.\nTo create a file: search must be empty and replace must contain the entire file content\nEach *search* pattern must match the existing source code exactly once, line for line, character for character, including all comments, docstrings, etc.\nDo not use a part of the line as *search* pattern. You must use full lines.\nInclude enough lines to make code inside *search* pattern uniquely identifiable. A *search* pattern that produces multiple matches in the source code will be rejected as an error.\nDo not add backslashes to escape special characters. Write the code exactly as it should appear in the intended programming language.\nDo not use git diff style (+ and - at the beginning of the line) for *search/REPLACE* blocks.\nDo not use line numbers in *search/REPLACE* blocks. Do not enclose the *search/REPLACE* block or any of its components in triple quotes. Use only tags to separate the parameters.\nDo not use the same value for *search* and *REPLACE* parameters, as this will make no changes.\n\nIf you need to edit a file again after making changes, use the latest version of the code that includes all your modifications applied during **current session**.\n\nRespond ONLY with a JSON object that matches the provided schema. Do not include explanations.), ChatMessage(role=User, content=Modify the project to add a Utils.java with a function greet(name) and use it in Main.java), ChatMessage(role=User, content=The following files are in the context:\n<<>>public class Main {\n public static void main(String[] args) {\n System.out.println(\"Hello\");\n }\n}<<>>\n)]",
+ "params": "GenerationParams(temperature=null, maxTokens=null)",
+ "response": "{\"edits\":[{\"filePath\":\"src/Utils.java\",\"search\":\"\",\"replace\":\"public class Utils {\\n public static String greet(String name) {\\n return \\\"Hello, \\\" + name + \\\"!\\\";\\n }\\n}\"},{\"filePath\":\"src/Main.java\",\"search\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(\\\"Hello\\\");\\n }\\n}\",\"replace\":\"public class Main {\\n public static void main(String[] args) {\\n System.out.println(Utils.greet(\\\"World\\\"));\\n }\\n}\"}]}"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/guardian/api/build.gradle.kts b/guardian/api/build.gradle.kts
index 354fec4..9a22906 100644
--- a/guardian/api/build.gradle.kts
+++ b/guardian/api/build.gradle.kts
@@ -10,4 +10,5 @@ base {
dependencies {
api(libs.kotlinx.serialization.json)
api(project(":filesystem"))
+ implementation(libs.kotlinx.coroutines.core)
}
diff --git a/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/DummyGuardian.kt b/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/DummyGuardian.kt
index 5d89ec2..7eac575 100644
--- a/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/DummyGuardian.kt
+++ b/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/DummyGuardian.kt
@@ -1,13 +1,18 @@
package de.tuda.stg.securecoder.guardian
import kotlin.random.Random
+import kotlinx.coroutines.delay
class DummyGuardian(
private val flagProbabilityPerFile: Double = 0.8,
private val hardRejet: Boolean = false,
private val rng: Random = Random,
+ private val sleepMillis: Long = 0,
) : Guardian {
override suspend fun run(req: AnalyzeRequest): AnalyzeResponse {
+ if (sleepMillis > 0) {
+ delay(sleepMillis)
+ }
val violations = req.files
.filter { rng.nextDouble() < flagProbabilityPerFile }
.map { randomViolationFor(it) }
diff --git a/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/Models.kt b/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/Models.kt
index 780082e..01ac990 100644
--- a/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/Models.kt
+++ b/guardian/api/src/main/java/de/tuda/stg/securecoder/guardian/Models.kt
@@ -24,6 +24,7 @@ data class Violation(
val location: Location,
val hardReject: Boolean,
val confidence: String? = null,
+ val raw: String? = null,
)
@Serializable
diff --git a/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/CodeQLGuardian.kt b/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/CodeQLGuardian.kt
index 2657143..e87f69e 100644
--- a/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/CodeQLGuardian.kt
+++ b/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/CodeQLGuardian.kt
@@ -6,7 +6,7 @@ import java.nio.file.Path
import kotlin.io.path.exists
class CodeQLGuardian(
- private val codeqlBinary: String = "codeql",
+ private val codeQlBinary: String = "codeql",
private val defaultQueryPacksByLanguage: Map = mapOf(
"javascript" to "codeql/javascript-queries",
"python" to "codeql/python-queries",
@@ -28,7 +28,7 @@ class CodeQLGuardian(
val sarifPaths = mutableListOf()
println("detected languages $languages for files ${req.files.joinToString(",")}")
- val runner = CodeQLRunner(codeqlBinary)
+ val runner = CodeQLRunner(codeQlBinary)
for (language in languages) {
val dbDir = workRoot.resolve("db-$language")
val outSarif = workRoot.resolve("results-$language.sarif")
@@ -48,6 +48,7 @@ class CodeQLGuardian(
}
return AnalyzeResponse(violations)
} finally {
+ // todo
// workRoot.toFile().deleteRecursively()
}
}
diff --git a/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/SarifParser.kt b/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/SarifParser.kt
index 0724558..7a3bdce 100644
--- a/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/SarifParser.kt
+++ b/guardian/codeql/src/main/java/de/tuda/stg/securecoder/guardian/SarifParser.kt
@@ -54,6 +54,7 @@ private fun mapResultToViolation(res: JsonElement): Violation {
),
hardReject = false,
confidence = confidence,
+ raw = res.toString(),
)
}
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 4870f80..f7c48ea 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -19,4 +19,4 @@ include("app:benchmark-securityeval")
include("guardian:api")
include("guardian:codeql")
include("filesystem")
-include("app:openapi-bridge")
\ No newline at end of file
+include("app:openai-bridge")
\ No newline at end of file