diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml
index b2e472e59f..989cd46925 100644
--- a/gradle/verification-metadata.xml
+++ b/gradle/verification-metadata.xml
@@ -13425,6 +13425,11 @@
+
+
+
+
+
diff --git a/library/build.gradle b/library/build.gradle
index d27ae8ed2c..9497a786a3 100644
--- a/library/build.gradle
+++ b/library/build.gradle
@@ -30,6 +30,7 @@ buildscript {
plugins {
id "com.diffplug.spotless" version "8.1.0"
+ id 'org.jetbrains.kotlin.plugin.serialization' version '2.3.0'
}
apply plugin: 'com.android.library'
@@ -59,6 +60,8 @@ configurations {
}
dependencies {
+ implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.9.0"
+
implementation 'org.apache.jackrabbit:jackrabbit-webdav:2.13.5'
api 'com.squareup.okhttp3:okhttp:5.3.2'
implementation 'com.github.bitfireAT:dav4jvm:2.2.1'
diff --git a/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/v2/AssistantV2Tests.kt b/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/v2/AssistantV2Tests.kt
index eb75f9d751..67921f7695 100644
--- a/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/v2/AssistantV2Tests.kt
+++ b/library/src/androidTest/java/com/owncloud/android/lib/resources/assistant/v2/AssistantV2Tests.kt
@@ -83,7 +83,9 @@ class AssistantV2Tests : AbstractIT() {
val taskType = getTaskType()
val selectedTaskType = getSelectedTaskType()
- assertTrue(CreateTaskRemoteOperationV2(input, taskType).execute(nextcloudClient).isSuccess)
+ val createTaskOperation = CreateTaskRemoteOperationV2(input, taskType)
+ val createTaskOperationResult = createTaskOperation.execute(nextcloudClient)
+ assertTrue(createTaskOperationResult.isSuccess)
var result = GetTaskListRemoteOperationV2(selectedTaskType).execute(nextcloudClient)
assertTrue(result.isSuccess)
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTaskRemoteOperationV2.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTaskRemoteOperationV2.kt
index 7974ce4f7e..944cf8df56 100644
--- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTaskRemoteOperationV2.kt
+++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTaskRemoteOperationV2.kt
@@ -13,37 +13,42 @@ import com.nextcloud.operations.PostMethod
import com.owncloud.android.lib.common.operations.RemoteOperation
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.encodeToJsonElement
+import kotlinx.serialization.json.put
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.RequestBody.Companion.toRequestBody
import org.apache.commons.httpclient.HttpStatus
-class CreateTaskRemoteOperationV2(
+open class CreateTaskRemoteOperationV2(
private val input: String,
private val taskType: TaskTypeData
) : RemoteOperation() {
- override fun run(client: NextcloudClient): RemoteOperationResult {
+ protected open fun buildRequestBody(): String {
val inputField = hashMapOf("input" to input)
- val requestBody =
- hashMapOf(
- "input" to inputField,
- "type" to taskType.id,
- "appId" to "assistant",
- "customId" to ""
- )
+ val jsonObject =
+ buildJsonObject {
+ put("input", Json.encodeToJsonElement(inputField))
+ put("type", taskType.id)
+ put("appId", "assistant")
+ put("customId", "")
+ }
- val json = gson.toJson(requestBody)
+ return Json.encodeToString(jsonObject)
+ }
+ override fun run(client: NextcloudClient): RemoteOperationResult {
+ val json = buildRequestBody()
val request = json.toRequestBody("application/json".toMediaTypeOrNull())
-
val postMethod = PostMethod(client.baseUri.toString() + TAG_URL, true, request)
-
val status = postMethod.execute(client)
return if (status == HttpStatus.SC_OK) {
- RemoteOperationResult(true, postMethod)
+ RemoteOperationResult(true, postMethod)
} else {
- RemoteOperationResult(false, postMethod)
+ RemoteOperationResult(false, postMethod)
}
}
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTranslationTaskRemoteOperation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTranslationTaskRemoteOperation.kt
new file mode 100644
index 0000000000..9e98a8138e
--- /dev/null
+++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/CreateTranslationTaskRemoteOperation.kt
@@ -0,0 +1,35 @@
+/*
+ * Nextcloud Android Library
+ *
+ * SPDX-FileCopyrightText: 2026 Alper Ozturk
+ * SPDX-License-Identifier: MIT
+ */
+
+package com.owncloud.android.lib.resources.assistant.v2
+
+import com.owncloud.android.lib.resources.assistant.v2.model.TaskTypeData
+import com.owncloud.android.lib.resources.assistant.v2.model.TranslationRequest
+import kotlinx.serialization.json.Json
+import kotlinx.serialization.json.buildJsonObject
+import kotlinx.serialization.json.encodeToJsonElement
+import kotlinx.serialization.json.put
+
+class CreateTranslationTaskRemoteOperation(
+ private val input: TranslationRequest,
+ private val taskType: TaskTypeData
+) : CreateTaskRemoteOperationV2(
+ input = "",
+ taskType = taskType
+ ) {
+ override fun buildRequestBody(): String {
+ val jsonObject =
+ buildJsonObject {
+ put("input", Json.encodeToJsonElement(input))
+ put("type", taskType.id)
+ put("appId", "assistant")
+ put("customId", "")
+ }
+
+ return Json.encodeToString(jsonObject)
+ }
+}
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt
index a783f41c98..96a7372f21 100644
--- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt
+++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/GetTaskTypesRemoteOperationV2.kt
@@ -71,7 +71,7 @@ class GetTaskTypesRemoteOperationV2 : OCSRemoteOperation>() {
?.types
?.map { (key, value) -> value.copy(id = value.id ?: key) }
?.filter { taskType ->
- isSingleTextInputOutput(taskType) || taskType.isChat()
+ isSingleTextInputOutput(taskType) || taskType.isChat() || taskType.isTranslate()
}?.sortedByDescending { it.isChat() }
result = RemoteOperationResult(true, getMethod)
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt
index a33dae69c1..0660dcfe01 100644
--- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt
+++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskList.kt
@@ -25,7 +25,9 @@ data class Task(
val lastUpdated: Int? = null,
val scheduledAt: Int? = null,
val endedAt: Int? = null
-)
+) {
+ fun isTranslate(): Boolean = (type == "core:text2text:translate")
+}
data class TaskInput(
var input: String? = null
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt
index 6ce58e21e8..20340fe2f5 100644
--- a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt
+++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/TaskTypes.kt
@@ -17,12 +17,20 @@ data class TaskTypeData(
val name: String,
val description: String?,
val inputShape: Map,
- val outputShape: Map
+ val outputShape: Map,
+ val optionalInputShapeDefaults: Map? = null,
+ val optionalInputShapeEnumValues: Map>? = null,
+ val inputShapeEnumValues: Map>? = null,
+ val outputShapeEnumValues: Map>? = null,
+ val optionalOutputShapeEnumValues: Map>? = null
) {
private val chatTaskName = "Chat"
+ private val translateTaskName = "Translate"
fun isChat(): Boolean = (name == chatTaskName)
+ fun isTranslate(): Boolean = (name == translateTaskName)
+
companion object {
private const val CONVERSATION_LIST_ID = "ConversationList"
val conversationList =
@@ -36,6 +44,11 @@ data class TaskTypeData(
}
}
+data class EnumValue(
+ val name: String,
+ val value: String
+)
+
data class Shape(
val name: String,
val description: String,
diff --git a/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt
new file mode 100644
index 0000000000..ab0ad8c870
--- /dev/null
+++ b/library/src/main/java/com/owncloud/android/lib/resources/assistant/v2/model/Translation.kt
@@ -0,0 +1,57 @@
+/*
+ * Nextcloud Android Library
+ *
+ * SPDX-FileCopyrightText: 2026 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2026 Alper Ozturk
+ * SPDX-License-Identifier: MIT
+ */
+
+package com.owncloud.android.lib.resources.assistant.v2.model
+
+import kotlinx.serialization.SerialName
+import kotlinx.serialization.Serializable
+
+data class TranslationLanguage(
+ val name: String,
+ val code: String
+)
+
+@Serializable
+data class TranslationRequest(
+ @SerialName("origin_language")
+ val originLanguage: String,
+ @SerialName("max_tokens")
+ val maxTokens: Double,
+ val model: String,
+ @SerialName("target_language")
+ val targetLanguage: String,
+ val input: String
+)
+
+data class TranslationModel(
+ val model: String,
+ val maxTokens: Double
+)
+
+data class TranslationLanguages(
+ val originLanguages: List,
+ val targetLanguages: List
+)
+
+fun TaskTypeData.toTranslationLanguages(): TranslationLanguages {
+ fun List?.toTranslationLanguageList() =
+ this
+ .orEmpty()
+ .map { TranslationLanguage(it.name, it.value) }
+
+ return TranslationLanguages(
+ originLanguages = inputShapeEnumValues?.get("origin_language").toTranslationLanguageList(),
+ targetLanguages = inputShapeEnumValues?.get("target_language").toTranslationLanguageList()
+ )
+}
+
+fun TaskTypeData.toTranslationModel(): TranslationModel? {
+ val model = optionalInputShapeDefaults?.get("model") as? String
+ val maxTokens = optionalInputShapeDefaults?.get("max_tokens") as? Double
+ return if (model != null && maxTokens != null) TranslationModel(model, maxTokens) else null
+}