fix(#1215): show omitted process output count (#1232)

This commit is contained in:
m57 authored and GitHub committed 2026-09-23 11:26:45 +03:00
1 parent 62b865b7d1
commit e539d650cf
10 files changed
+57

No files matched your search

@@ -495,6 +495,13 @@ private fun ExpandedToolContent(
}
}
view.outputCut?.let { omitted ->
Text(
text = stringResource(R.string.chat_tool_output_omitted, omitted),
style = MaterialTheme.typography.labelSmall.copy(color = statusColors.warning),
)
}
// ── Duration footer ──
view.durationLabel?.let {
Text(
@@ -41,6 +41,8 @@ internal interface ToolRenderer {
*/
internal data class ToolViewExtras(
val detailLabel: String? = null,
/** Process output characters omitted by the backend. */
val outputCut: Long? = null,
val stdout: String? = null,
val stderr: String? = null,
val exitCode: Int? = null,
@@ -35,6 +35,8 @@ data class ToolView(
val detail: String = "",
/** Optional section label above [detail] (e.g. "Search results"). */
val detailLabel: String? = null,
/** Process output characters omitted by the backend. */
val outputCut: Long? = null,
/** Compact count, e.g. "3 results". */
val countLabel: String? = null,
/** Human duration, e.g. "1.2s". */
@@ -106,6 +106,7 @@ object ToolViewBuilder {
subtitle = subtitle,
detail = clampedDetail,
detailLabel = extras.detailLabel,
outputCut = extras.outputCut,
countLabel = countLabel?.let { (count, noun) -> "$count ${ToolCounts.pluralizeNoun(noun, count)}" },
durationLabel = ToolJson.durationLabel(call.result),
stdout = clampedStdout,
@@ -3,9 +3,12 @@ package com.m57.hermescontrol.ui.chat.tool.render
import com.m57.hermescontrol.ui.chat.tool.ToolCall
import com.m57.hermescontrol.ui.chat.tool.ToolJson
import com.m57.hermescontrol.ui.chat.tool.ToolRenderer
import com.m57.hermescontrol.ui.chat.tool.ToolViewExtras
import com.m57.hermescontrol.ui.chat.tool.ToolViewStatus
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.longOrNull
/** `cronjob`: job listings with schedules, or the mutated job's key fields. */
internal object CronjobRenderer : ToolRenderer {
@@ -214,6 +217,15 @@ internal object SessionSearchRenderer : ToolRenderer {
/** `process`: background session listings and lifecycle acks. */
internal object ProcessRenderer : ToolRenderer {
override fun extras(
call: ToolCall,
status: ToolViewStatus,
): ToolViewExtras {
if (status == ToolViewStatus.RUNNING) return ToolViewExtras.NONE
val count = (call.result?.get("output_cut") as? JsonPrimitive)?.takeUnless { it.isString }?.longOrNull
return ToolViewExtras(outputCut = count?.takeIf { it > 0 })
}
override fun subtitle(call: ToolCall): String {
val action = ToolJson.firstString(call.args, listOf("action"))
val procId = ToolJson.firstString(call.args, listOf("session_id"))
+1
View File
@@ -165,6 +165,7 @@
<string name="chat_input_placeholder_type_message">اكتب رسالة\u2026</string>
<string name="chat_tool_execution_error">خطأ في التنفيذ: %1$s</string>
<string name="chat_tool_exit_code">رمز الخروج: %1$d</string>
<string name="chat_tool_output_omitted">تم حذف %1$d حرف من مخرجات العملية</string>
<string name="chat_tool_fallback">أداة</string>
<string name="chat_tool_show_raw">عرض ملف JSON الأولي</string>
<string name="chat_tool_show_parsed">عرض المخرجات المعالجة</string>
+1
View File
@@ -162,6 +162,7 @@
<string name="chat_input_placeholder_type_message">메시지 입력…</string>
<string name="chat_tool_execution_error">실행 오류: %1$s</string>
<string name="chat_tool_exit_code">종료 코드: %1$d</string>
<string name="chat_tool_output_omitted">프로세스 출력에서 %1$d자 생략됨</string>
<string name="chat_tool_fallback">도구</string>
<string name="chat_tool_show_raw">Raw JSON 보기</string>
<string name="chat_tool_show_parsed">파싱된 결과 보기</string>
+1
View File
@@ -165,6 +165,7 @@
<string name="chat_input_placeholder_type_message">输入消息…</string>
<string name="chat_tool_execution_error">执行错误:%1$s</string>
<string name="chat_tool_exit_code">退出码:%1$d</string>
<string name="chat_tool_output_omitted">进程输出省略了 %1$d 个字符</string>
<string name="chat_tool_fallback">工具</string>
<string name="chat_tool_show_raw">显示原始 JSON</string>
<string name="chat_tool_show_parsed">显示解析输出</string>
+1
View File
@@ -196,6 +196,7 @@
<string name="chat_input_placeholder_type_message">Type a message\u2026</string>
<string name="chat_tool_execution_error">Execution Error: %1$s</string>
<string name="chat_tool_exit_code">Exit Code: %1$d</string>
<string name="chat_tool_output_omitted">%1$d characters omitted from process output</string>
<string name="chat_tool_fallback">Tool</string>
<string name="chat_tool_show_raw">Show Raw JSON</string>
<string name="chat_tool_show_parsed">Show Parsed Output</string>
@@ -308,6 +308,35 @@ class ToolViewBuilderTest {
assertEquals("poll: proc-1", view.subtitle)
assertTrue(view.detail.contains("Status: running"))
assertTrue(view.detail.contains("listening on port 8080"))
assertEquals(null, view.outputCut)
}
@Test
fun `process output reports backend omitted character count for each action`() {
listOf("poll", "wait", "log", "kill").forEach { action ->
val outputKey = if (action == "poll") "output_preview" else "output"
val view =
build(
"process_manage",
"""{"action":"$action","session_id":"proc-1"}""",
"""{"status":"exited","$outputKey":"partial output","output_cut":42}""",
)
assertTrue(view.detail.contains("partial output"))
assertEquals(42L, view.outputCut)
}
}
@Test
fun `process output without positive numeric omission has no notice`() {
listOf("{}", """{"output_cut":0}""", """{"output_cut":"unknown"}""").forEach { metadata ->
val fields = metadata.removePrefix("{").removeSuffix("}")
val result = """{"output":"complete"${if (fields.isNotEmpty()) ",$fields" else ""}}"""
val view = build("process", """{"action":"wait"}""", result)
assertEquals("complete", view.detail)
assertEquals(null, view.outputCut)
}
}
@Test