chore: refresh chat UI cleanup against dev
This commit is contained in:
@@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/), and this
|
||||
|
||||
- Android shows standalone response cards without an outer bubble, uses subtler assistant surfaces, and places delivery status beside message timestamps.
|
||||
- Android answers upstream Clarify batches one question at a time, with independent choices, custom answers, and confirmed progress preserved across reconnects. (#474)
|
||||
- Android context previews mark phone status and turn context as unavailable in Gateway chats instead of claiming they are sent. Settings clarify that automatic phone-status sharing applies to API-only chats. (#556)
|
||||
- Relay Dashboard WebSockets work with current Hermes authentication helpers while preserving older-host compatibility, single-use tickets, Host/Origin/IP checks, and Relay session authentication.
|
||||
- Android shows Hermes profile display names and groups the resolved server default under its agent identity, while preserving explicit profile selection and saved conversations.
|
||||
|
||||
|
||||
@@ -23,14 +23,9 @@ import com.hermesandroid.relay.R
|
||||
import com.hermesandroid.relay.viewmodel.ChatViewModel
|
||||
|
||||
/**
|
||||
* Bottom-sheet audit of the exact extra context the agent is injected with on
|
||||
* the next turn — opened by tapping the chat [ContextMeterBar].
|
||||
*
|
||||
* Renders the SAME [ChatViewModel.InjectedContext] the send path builds (via
|
||||
* [ChatViewModel.previewInjectedContext] → `composeInjectedContext`), so it is
|
||||
* a faithful audit, not a re-derivation that could drift. Empty blocks show a
|
||||
* labeled note instead of vanishing, and the gateway's server-side persona is
|
||||
* explicitly called out as not-sent-from-this-device.
|
||||
* Transport-aware context preview, opened from the chat [ContextMeterBar].
|
||||
* Unsupported blocks are labeled rather than represented as delivered.
|
||||
* Server-reported configuration is separate from device-supplied context.
|
||||
*/
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
@@ -53,7 +48,7 @@ fun InjectedContextSheet(
|
||||
)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Text(
|
||||
text = stringResource(R.string.injected_context_subtitle, context.transport),
|
||||
text = stringResource(R.string.injected_context_subtitle),
|
||||
style = MaterialTheme.typography.bodySmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
@@ -71,6 +66,7 @@ fun InjectedContextSheet(
|
||||
val mediaNoRelay = stringResource(R.string.injected_context_media_no_relay)
|
||||
val relayNotSet = stringResource(R.string.injected_context_relay_not_set)
|
||||
val turnNotSet = stringResource(R.string.injected_context_turn_not_set)
|
||||
val unsupported = stringResource(R.string.injected_context_gateway_unsupported)
|
||||
|
||||
ContextSection(
|
||||
title = personaTitle,
|
||||
@@ -84,7 +80,7 @@ fun InjectedContextSheet(
|
||||
ContextSection(
|
||||
title = phoneStatusTitle,
|
||||
body = context.appContext,
|
||||
emptyNote = phoneStatusNotSet,
|
||||
emptyNote = if (context.perTurnContextSupported) phoneStatusNotSet else unsupported,
|
||||
)
|
||||
ContextSection(
|
||||
title = mediaTitle,
|
||||
@@ -107,7 +103,7 @@ fun InjectedContextSheet(
|
||||
ContextSection(
|
||||
title = turnTitle,
|
||||
body = context.interfaceContext,
|
||||
emptyNote = turnNotSet,
|
||||
emptyNote = if (context.perTurnContextSupported) turnNotSet else unsupported,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3215,8 +3215,8 @@ fun ChatScreen(
|
||||
)
|
||||
}
|
||||
if (!supervised && showContextSheet) {
|
||||
// Live audit of the exact extra context the agent will be
|
||||
// injected with on the next turn (transparency / auditability).
|
||||
// Snapshot of supported client context and separately reported
|
||||
// server configuration, not a delivery receipt.
|
||||
InjectedContextSheet(
|
||||
context = remember(showContextSheet) {
|
||||
chatViewModel.previewInjectedContext()
|
||||
|
||||
@@ -9770,8 +9770,8 @@ class ChatViewModel : ViewModel() {
|
||||
* 0. **Gateway transport** — the server owns the persona end-to-end: the
|
||||
* session is bound to the selected profile (SOUL applied server-side) and
|
||||
* the personality overlay rides `config.set`/`ephemeral_system_prompt`.
|
||||
* The phone sends NO persona/profile prompt (only the phone-status block)
|
||||
* so it can't double-apply. Cases 1–3 are the SSE-fallback rules.
|
||||
* The phone sends no per-turn system context on Gateway.
|
||||
* Cases 1–3 are the explicit API-only transport rules.
|
||||
* 1. **Selected profile with a non-blank [Profile.systemMessage]** —
|
||||
* profile wins outright. Profile is a richer, newer concept than
|
||||
* personality: it bundles model + persona (from the profile's
|
||||
@@ -9786,15 +9786,12 @@ class ChatViewModel : ViewModel() {
|
||||
* configured default.
|
||||
*
|
||||
* The phone-status [appContextSettings] block is appended to whichever
|
||||
* of the above wins (or sent alone in case 3), so the LLM always sees
|
||||
* phone state regardless of persona source.
|
||||
* of the API-only cases above wins (or sent alone in case 3).
|
||||
*/
|
||||
/**
|
||||
* The exact `system_message` (`ephemeral_system_prompt`) injected for a
|
||||
* turn, split into labeled blocks. Single source of truth shared by
|
||||
* [startStream] (which sends [combinedSystemMessage]) and
|
||||
* [previewInjectedContext] (which renders it in the chat audit sheet) so
|
||||
* the preview can never drift from what is actually sent.
|
||||
* Context prepared for the selected transport, split into labeled blocks.
|
||||
* This is a preview, not a delivery receipt or the complete agent prompt.
|
||||
* Gateway has no general per-turn system-context slot.
|
||||
*/
|
||||
data class InjectedContext(
|
||||
val personaPrompt: String?,
|
||||
@@ -9825,6 +9822,8 @@ class ChatViewModel : ViewModel() {
|
||||
* audit UI labels that block "added server-side".
|
||||
*/
|
||||
val personaOwnedServerSide: Boolean,
|
||||
/** False on Gateway; unsupported blocks are excluded from the payload and preview. */
|
||||
val perTurnContextSupported: Boolean,
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -9860,11 +9859,14 @@ class ChatViewModel : ViewModel() {
|
||||
} else {
|
||||
_sseToolNames.value
|
||||
}
|
||||
val appContextRaw = buildPromptBlock(
|
||||
settings = appContextSettings,
|
||||
snapshot = capturePhoneSnapshot(),
|
||||
availableTools = availableTools,
|
||||
)
|
||||
val appContextRaw = if (!gateway && appContextSettings.master) {
|
||||
buildPromptBlock(
|
||||
settings = appContextSettings,
|
||||
snapshot = capturePhoneSnapshot(),
|
||||
availableTools = availableTools,
|
||||
)
|
||||
} else null
|
||||
val interfaceContext = interfaceContextPrompt?.takeIf { !gateway && it.isNotBlank() }
|
||||
// Gateway has no per-turn system slot. SSE carries the standard
|
||||
// Dashboard route first, then the optional Relay enhancement.
|
||||
val upstreamMediaAvailable = dashboardMediaClientProvider?.invoke() != null
|
||||
@@ -9876,25 +9878,26 @@ class ChatViewModel : ViewModel() {
|
||||
// block (a stable environment fact, like phone status) and before the
|
||||
// per-turn interface context. The per-block fields below null out blanks
|
||||
// only for display.
|
||||
val combined = listOfNotNull(personaPrompt, appContextRaw, mediaCapability, interfaceContextPrompt)
|
||||
val combined = listOfNotNull(personaPrompt, appContextRaw, mediaCapability, interfaceContext)
|
||||
.joinToString("\n\n")
|
||||
.ifBlank { null }
|
||||
return InjectedContext(
|
||||
personaPrompt = personaPrompt,
|
||||
appContext = appContextRaw?.takeIf { it.isNotBlank() },
|
||||
interfaceContext = interfaceContextPrompt?.takeIf { it.isNotBlank() },
|
||||
interfaceContext = interfaceContext,
|
||||
mediaCapability = mediaCapability,
|
||||
relayServerBlocks = relayServerBlocks,
|
||||
relayMediaAvailable = relayMediaAvailable,
|
||||
combinedSystemMessage = combined,
|
||||
transport = streamingEndpoint,
|
||||
personaOwnedServerSide = gateway,
|
||||
perTurnContextSupported = !gateway,
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Live audit snapshot of what the agent will be injected with on the next
|
||||
* turn — rendered by the chat context sheet. Per-turn voice context is null
|
||||
* Preview of context supported by the selected transport, plus separately
|
||||
* reported Relay configuration. Per-turn voice context is null
|
||||
* here (it's set only on a spoken turn); the UI notes that.
|
||||
*/
|
||||
fun previewInjectedContext(): InjectedContext {
|
||||
|
||||
@@ -762,7 +762,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">Alertas de chat em segundo plano</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">Notifique quando o Hermes precisar de uma resposta ou terminar em segundo plano</string>
|
||||
<string name="chat_settings_share_phone_status">Compartilhar o status do celular com o agente</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Inclua uma breve mensagem do sistema sobre o app e o celular em cada turno do chat</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Incluir contexto do app e do telefone em chats apenas por API. Não é enviado nos chats padrão do Gateway.</string>
|
||||
<string name="chat_settings_bridge_permissions">Bridge + permissões</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">Se acessibilidade, captura de tela, sobreposição e notificações foram concedidas</string>
|
||||
<string name="chat_settings_foreground_app">App em primeiro plano</string>
|
||||
@@ -771,7 +771,7 @@
|
||||
<string name="chat_settings_battery_level_desc">Porcentagem atual da bateria. Desativado por padrão.</string>
|
||||
<string name="chat_settings_safety_rails">Proteções de segurança</string>
|
||||
<string name="chat_settings_safety_rails_desc">Quantidade de itens bloqueados, quantidade de verbos destrutivos e temporizador de desativação automática</string>
|
||||
<string name="chat_settings_preview">Prévia</string>
|
||||
<string name="chat_settings_preview">Exemplo de chat apenas por API</string>
|
||||
<string name="chat_settings_no_system_message">(nenhuma mensagem do sistema será enviada)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">Analisar anotações de ferramentas</string>
|
||||
<string name="chat_settings_experimental">Experimental</string>
|
||||
@@ -3201,10 +3201,10 @@
|
||||
<string name="injected_context_phone_status_title">Status do celular</string>
|
||||
<string name="injected_context_relay_not_set">Nenhum relay configurado</string>
|
||||
<string name="injected_context_relay_title">Relay</string>
|
||||
<string name="injected_context_subtitle">Contexto enviado com a próxima mensagem</string>
|
||||
<string name="injected_context_subtitle">Prévia deste chat. O contexto do servidor é configurado separadamente.</string>
|
||||
<string name="injected_context_title">Contexto injetado</string>
|
||||
<string name="injected_context_turn_not_set">Não definido</string>
|
||||
<string name="injected_context_turn_title">Modo de detecção de turno</string>
|
||||
<string name="injected_context_turn_title">Contexto do turno</string>
|
||||
<string name="model_picker_cd_clear">Limpar</string>
|
||||
<string name="model_picker_count">%d modelos</string>
|
||||
<string name="power_feature_back_desc">Voltar</string>
|
||||
@@ -4452,4 +4452,5 @@
|
||||
<string name="voice_overlay_setup_start">Iniciar sobreposição de voz</string>
|
||||
<string name="voice_overlay_settings_hint">Opcional nas duas versões. Abra o foco de voz no Chat e escolha Sobreposição. As permissões sozinhas nunca iniciam a escuta.</string>
|
||||
<string name="voice_overlay_reset_position">Redefinir posição</string>
|
||||
<string name="injected_context_gateway_unsupported">Não é enviado no chat do Gateway. Esta conexão não oferece suporte a contexto adicional por turno.</string>
|
||||
</resources>
|
||||
|
||||
@@ -801,7 +801,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">后台聊天提醒</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">Hermes 在后台需要输入或完成回复时通知</string>
|
||||
<string name="chat_settings_share_phone_status">与代理分享手机状态</string>
|
||||
<string name="chat_settings_share_phone_status_desc">每轮聊天附带一条关于应用和手机的简短系统消息</string>
|
||||
<string name="chat_settings_share_phone_status_desc">在仅使用 API 的聊天中包含应用和手机上下文。标准 Gateway 聊天不会发送此内容。</string>
|
||||
<string name="chat_settings_bridge_permissions">Bridge + 权限</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">无障碍、屏幕捕获、悬浮窗、通知是否已授权</string>
|
||||
<string name="chat_settings_foreground_app">前台应用</string>
|
||||
@@ -810,7 +810,7 @@
|
||||
<string name="chat_settings_battery_level_desc">当前电池百分比。默认关闭。</string>
|
||||
<string name="chat_settings_safety_rails">安全护栏</string>
|
||||
<string name="chat_settings_safety_rails_desc">黑名单数量、破坏性动词数量和自动禁用计时器</string>
|
||||
<string name="chat_settings_preview">预览</string>
|
||||
<string name="chat_settings_preview">仅使用 API 的聊天示例</string>
|
||||
<string name="chat_settings_no_system_message">(不会发送系统消息)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">解析工具标注</string>
|
||||
<string name="chat_settings_experimental">实验性</string>
|
||||
@@ -3300,10 +3300,10 @@
|
||||
<string name="injected_context_phone_status_title">手机状态</string>
|
||||
<string name="injected_context_relay_not_set">未配置 Relay</string>
|
||||
<string name="injected_context_relay_title">Relay</string>
|
||||
<string name="injected_context_subtitle">随下一条消息发送的上下文</string>
|
||||
<string name="injected_context_subtitle">此聊天的预览。服务器端上下文单独配置。</string>
|
||||
<string name="injected_context_title">注入上下文</string>
|
||||
<string name="injected_context_turn_not_set">未设置</string>
|
||||
<string name="injected_context_turn_title">轮换检测模式</string>
|
||||
<string name="injected_context_turn_title">本轮上下文</string>
|
||||
<string name="model_picker_cd_clear">清空</string>
|
||||
<string name="model_picker_count">%d 个模型</string>
|
||||
<string name="power_feature_back_desc">返回</string>
|
||||
@@ -4533,4 +4533,5 @@
|
||||
<string name="voice_overlay_setup_start">启动语音悬浮窗</string>
|
||||
<string name="voice_overlay_settings_hint">两个版本均可选择使用。在聊天的语音专注模式中选择悬浮窗。仅授予权限不会开始监听。</string>
|
||||
<string name="voice_overlay_reset_position">重置位置</string>
|
||||
<string name="injected_context_gateway_unsupported">Gateway 聊天不会发送此内容。此连接不支持每轮附加上下文。</string>
|
||||
</resources>
|
||||
|
||||
@@ -804,7 +804,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">Chat-Benachrichtigungen im Hintergrund</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">Benachrichtigen, wenn Hermes Eingaben benötigt oder im Hintergrund fertig wird</string>
|
||||
<string name="chat_settings_share_phone_status">Smartphone-Status mit Agent teilen</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Bei jedem Chatdurchlauf eine kurze Systemnachricht über App und Smartphone einfügen</string>
|
||||
<string name="chat_settings_share_phone_status_desc">App- und Smartphone-Kontext in reinen API-Chats mitsenden. Wird in Standard-Gateway-Chats nicht gesendet.</string>
|
||||
<string name="chat_settings_bridge_permissions">Bridge + Berechtigungen</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">Ob Bedienungshilfe, Bildschirmaufnahme, Overlay und Benachrichtigungen erlaubt sind</string>
|
||||
<string name="chat_settings_foreground_app">App im Vordergrund</string>
|
||||
@@ -813,7 +813,7 @@
|
||||
<string name="chat_settings_battery_level_desc">Aktueller Akkustand in Prozent. Standardmäßig aus.</string>
|
||||
<string name="chat_settings_safety_rails">Schutzmechanismen</string>
|
||||
<string name="chat_settings_safety_rails_desc">Anzahl gesperrter Einträge und destruktiver Verben sowie Timer zur automatischen Deaktivierung</string>
|
||||
<string name="chat_settings_preview">Vorschau</string>
|
||||
<string name="chat_settings_preview">Beispiel für einen reinen API-Chat</string>
|
||||
<string name="chat_settings_no_system_message">(es wird keine Systemnachricht gesendet)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">Werkzeughinweise auswerten</string>
|
||||
<string name="chat_settings_experimental">Experimentell</string>
|
||||
@@ -3369,10 +3369,10 @@
|
||||
<string name="injected_context_phone_status_title">Smartphone-Status</string>
|
||||
<string name="injected_context_relay_not_set">Kein Relay konfiguriert</string>
|
||||
<string name="injected_context_relay_title">Relay</string>
|
||||
<string name="injected_context_subtitle">Kontext, der mit der nächsten Nachricht gesendet wird</string>
|
||||
<string name="injected_context_subtitle">Vorschau für diesen Chat. Serverseitiger Kontext wird separat konfiguriert.</string>
|
||||
<string name="injected_context_title">Eingefügter Kontext</string>
|
||||
<string name="injected_context_turn_not_set">Nicht festgelegt</string>
|
||||
<string name="injected_context_turn_title">Modus zur Durchlauferkennung</string>
|
||||
<string name="injected_context_turn_title">Nachrichtenkontext</string>
|
||||
<string name="model_picker_cd_clear">Leeren</string>
|
||||
<string name="model_picker_count">%d Modelle</string>
|
||||
<string name="power_feature_back_desc">Zurück</string>
|
||||
@@ -4609,4 +4609,5 @@
|
||||
<string name="voice_overlay_setup_start">Sprach-Overlay starten</string>
|
||||
<string name="voice_overlay_settings_hint">In beiden Versionen optional. Öffne den Sprachfokus im Chat und wähle Overlay. Berechtigungen allein starten kein Zuhören.</string>
|
||||
<string name="voice_overlay_reset_position">Position zurücksetzen</string>
|
||||
<string name="injected_context_gateway_unsupported">Wird im Gateway-Chat nicht gesendet. Diese Verbindung unterstützt keinen zusätzlichen Kontext pro Nachricht.</string>
|
||||
</resources>
|
||||
|
||||
@@ -729,7 +729,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">Alertas de chat en segundo plano</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">Notificar cuando Hermes necesite información o termine en segundo plano</string>
|
||||
<string name="chat_settings_share_phone_status">Compartir el estado del teléfono con el agente</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Incluya un breve mensaje del sistema sobre la aplicación y el teléfono en cada turno de chat.</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Incluir contexto de la app y el teléfono en chats solo por API. No se envía en los chats estándar de Gateway.</string>
|
||||
<string name="chat_settings_bridge_permissions">Bridge + permisos</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">Si se concede accesibilidad, captura de pantalla, superposición o notificaciones</string>
|
||||
<string name="chat_settings_foreground_app">Aplicación en primer plano</string>
|
||||
@@ -738,7 +738,7 @@
|
||||
<string name="chat_settings_battery_level_desc">Porcentaje de batería actual. Desactivado de forma predeterminada.</string>
|
||||
<string name="chat_settings_safety_rails">Barandillas de seguridad</string>
|
||||
<string name="chat_settings_safety_rails_desc">Recuento de listas de bloqueo, recuento de verbos destructivos y temporizador de desactivación automática</string>
|
||||
<string name="chat_settings_preview">Avance</string>
|
||||
<string name="chat_settings_preview">Ejemplo de chat solo por API</string>
|
||||
<string name="chat_settings_no_system_message">(no se enviará ningún mensaje del sistema)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">Anotaciones de la herramienta de análisis</string>
|
||||
<string name="chat_settings_experimental">Experimental</string>
|
||||
@@ -3033,10 +3033,10 @@
|
||||
<string name="injected_context_phone_status_title">Estado del teléfono</string>
|
||||
<string name="injected_context_relay_not_set">Ningún relay configurado</string>
|
||||
<string name="injected_context_relay_title">Relay</string>
|
||||
<string name="injected_context_subtitle">Contexto enviado con el siguiente mensaje.</string>
|
||||
<string name="injected_context_subtitle">Vista previa de este chat. El contexto del servidor se configura por separado.</string>
|
||||
<string name="injected_context_title">Contexto inyectado</string>
|
||||
<string name="injected_context_turn_not_set">No establecido</string>
|
||||
<string name="injected_context_turn_title">Modo de detección de giro</string>
|
||||
<string name="injected_context_turn_title">Contexto del turno</string>
|
||||
<string name="model_picker_cd_clear">Borrar</string>
|
||||
<string name="model_picker_count">Modelos %d</string>
|
||||
<string name="power_feature_back_desc">Atrás</string>
|
||||
@@ -4300,4 +4300,5 @@
|
||||
<string name="voice_overlay_setup_start">Iniciar ventana de voz</string>
|
||||
<string name="voice_overlay_settings_hint">Opcional en ambas versiones. Abre el enfoque de voz en Chat y elige Superposición. Los permisos por sí solos nunca inician la escucha.</string>
|
||||
<string name="voice_overlay_reset_position">Restablecer posición</string>
|
||||
<string name="injected_context_gateway_unsupported">No se envía en el chat de Gateway. Esta conexión no admite contexto adicional por turno.</string>
|
||||
</resources>
|
||||
|
||||
@@ -801,7 +801,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">バックグラウンドのチャット通知</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">バックグラウンドで Hermes が入力を必要としたとき、または完了したときに通知します</string>
|
||||
<string name="chat_settings_share_phone_status">電話のステータスをエージェントと共有する</string>
|
||||
<string name="chat_settings_share_phone_status_desc">すべてのチャット ターンにアプリと電話に関する短いシステム メッセージを含めます</string>
|
||||
<string name="chat_settings_share_phone_status_desc">API のみのチャットにアプリと端末のコンテキストを含めます。標準の Gateway チャットでは送信されません。</string>
|
||||
<string name="chat_settings_bridge_permissions">Bridge + 権限</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">アクセシビリティ、画面キャプチャ、オーバーレイ、通知が許可されているかどうか</string>
|
||||
<string name="chat_settings_foreground_app">フォアグラウンドアプリ</string>
|
||||
@@ -810,7 +810,7 @@
|
||||
<string name="chat_settings_battery_level_desc">現在のバッテリーのパーセント。デフォルトではオフです。</string>
|
||||
<string name="chat_settings_safety_rails">安全レール</string>
|
||||
<string name="chat_settings_safety_rails_desc">ブロックリストの数、破壊的な動詞の数、および自動無効化タイマー</string>
|
||||
<string name="chat_settings_preview">プレビュー</string>
|
||||
<string name="chat_settings_preview">API のみのチャットの例</string>
|
||||
<string name="chat_settings_no_system_message">(システムメッセージは送信されません)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">解析ツールの注釈</string>
|
||||
<string name="chat_settings_experimental">実験的</string>
|
||||
@@ -3376,10 +3376,10 @@
|
||||
<string name="injected_context_phone_status_title">電話のステータス</string>
|
||||
<string name="injected_context_relay_not_set">Relayが設定されていません</string>
|
||||
<string name="injected_context_relay_title">Relay</string>
|
||||
<string name="injected_context_subtitle">次のメッセージで送信されるコンテキスト</string>
|
||||
<string name="injected_context_subtitle">このチャットのプレビューです。サーバー側のコンテキストは別途設定されます。</string>
|
||||
<string name="injected_context_title">挿入されたコンテキスト</string>
|
||||
<string name="injected_context_turn_not_set">未設定</string>
|
||||
<string name="injected_context_turn_title">回転検出モード</string>
|
||||
<string name="injected_context_turn_title">ターンのコンテキスト</string>
|
||||
<string name="model_picker_cd_clear">クリア</string>
|
||||
<string name="model_picker_count">%d モデル</string>
|
||||
<string name="power_feature_back_desc">戻る</string>
|
||||
@@ -4604,4 +4604,5 @@
|
||||
<string name="voice_overlay_setup_start">音声オーバーレイを開始</string>
|
||||
<string name="voice_overlay_settings_hint">両方のビルドで任意に利用できます。チャットの音声フォーカスでオーバーレイを選択します。権限の付与だけで録音は始まりません。</string>
|
||||
<string name="voice_overlay_reset_position">位置をリセット</string>
|
||||
<string name="injected_context_gateway_unsupported">Gateway チャットでは送信されません。この接続はターンごとの追加コンテキストに対応していません。</string>
|
||||
</resources>
|
||||
|
||||
@@ -778,7 +778,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">Уведомления о фоновом чате</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">Уведомлять, когда Гермес требует ввода или заканчивает работу, когда приложение находится в фоновом режиме</string>
|
||||
<string name="chat_settings_share_phone_status">Поделиться статусом телефона с агентом</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Включите короткое системное сообщение о приложении и телефоне в каждом обороте чата</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Добавлять контекст приложения и телефона в чаты только через API. В стандартных чатах Gateway он не отправляется.</string>
|
||||
<string name="chat_settings_bridge_permissions">Мост + разрешения</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">Разрешения на доступность, захват экрана, наложение, уведомления</string>
|
||||
<string name="chat_settings_foreground_app">Приложение на переднем плане</string>
|
||||
@@ -787,7 +787,7 @@
|
||||
<string name="chat_settings_battery_level_desc">Текущий процент заряда батареи. По умолчанию выключено.</string>
|
||||
<string name="chat_settings_safety_rails">Ограждения безопасности</string>
|
||||
<string name="chat_settings_safety_rails_desc">Количество в черном списке, количество деструктивных глаголов и таймер автоматического отключения</string>
|
||||
<string name="chat_settings_preview">Предпросмотр</string>
|
||||
<string name="chat_settings_preview">Пример чата только через API</string>
|
||||
<string name="chat_settings_no_system_message">(системное сообщение не будет отправлено)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">Анализ аннотаций инструментов</string>
|
||||
<string name="chat_settings_experimental">Экспериментальные</string>
|
||||
@@ -3239,10 +3239,10 @@
|
||||
<string name="injected_context_phone_status_title">Статус телефона</string>
|
||||
<string name="injected_context_relay_not_set">плагин Relay не настроен</string>
|
||||
<string name="injected_context_relay_title">плагин Relay</string>
|
||||
<string name="injected_context_subtitle">Контекст отправляется с следующим сообщением</string>
|
||||
<string name="injected_context_subtitle">Предпросмотр для этого чата. Контекст на стороне сервера настраивается отдельно.</string>
|
||||
<string name="injected_context_title">Внедренный контекст</string>
|
||||
<string name="injected_context_turn_not_set">Не установлено</string>
|
||||
<string name="injected_context_turn_title">Режим обнаружения Turn</string>
|
||||
<string name="injected_context_turn_title">Контекст хода</string>
|
||||
<string name="model_picker_cd_clear">Очистить</string>
|
||||
<string name="model_picker_count">%d моделей</string>
|
||||
<string name="power_feature_back_desc">Назад</string>
|
||||
@@ -4348,4 +4348,5 @@
|
||||
<string name="voice_overlay_setup_start">Начать голосовой оверлей</string>
|
||||
<string name="voice_overlay_settings_hint">Необязательно в обеих сборках. Откройте голосовой фокус в чате и выберите оверлей. Одни разрешения никогда не включают прослушивание.</string>
|
||||
<string name="voice_overlay_reset_position">Сбросить положение</string>
|
||||
<string name="injected_context_gateway_unsupported">Не отправляется в чате Gateway. Это подключение не поддерживает дополнительный контекст для каждого хода.</string>
|
||||
</resources>
|
||||
|
||||
@@ -887,7 +887,7 @@
|
||||
<string name="chat_settings_notify_when_finishes">Background chat alerts</string>
|
||||
<string name="chat_settings_notify_when_finishes_desc">Notify when Hermes needs input or finishes while the app is in the background</string>
|
||||
<string name="chat_settings_share_phone_status">Share phone status with agent</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Include a short system message about the app and phone on every chat turn</string>
|
||||
<string name="chat_settings_share_phone_status_desc">Include app and phone context in API-only chats. Not sent in standard Gateway chats.</string>
|
||||
<string name="chat_settings_bridge_permissions">Bridge + permissions</string>
|
||||
<string name="chat_settings_bridge_permissions_desc">Whether accessibility, screen capture, overlay, notifications are granted</string>
|
||||
<string name="chat_settings_foreground_app">Foreground app</string>
|
||||
@@ -896,7 +896,7 @@
|
||||
<string name="chat_settings_battery_level_desc">Current battery percent. Off by default.</string>
|
||||
<string name="chat_settings_safety_rails">Safety rails</string>
|
||||
<string name="chat_settings_safety_rails_desc">Blocklist count, destructive-verb count, and auto-disable timer</string>
|
||||
<string name="chat_settings_preview">Preview</string>
|
||||
<string name="chat_settings_preview">Example for API-only chat</string>
|
||||
<string name="chat_settings_no_system_message">(no system message will be sent)</string>
|
||||
<string name="chat_settings_parse_tool_annotations">Parse tool annotations</string>
|
||||
<string name="chat_settings_experimental">Experimental</string>
|
||||
@@ -3769,10 +3769,10 @@
|
||||
<string name="injected_context_phone_status_title">Phone status</string>
|
||||
<string name="injected_context_relay_not_set">No relay configured</string>
|
||||
<string name="injected_context_relay_title">Relay</string>
|
||||
<string name="injected_context_subtitle">Context sent with next message</string>
|
||||
<string name="injected_context_subtitle">Preview for this chat. Server-side context is configured separately.</string>
|
||||
<string name="injected_context_title">Injected context</string>
|
||||
<string name="injected_context_turn_not_set">Not set</string>
|
||||
<string name="injected_context_turn_title">Turn detection mode</string>
|
||||
<string name="injected_context_turn_title">Turn context</string>
|
||||
<string name="model_picker_cd_clear">Clear</string>
|
||||
<string name="model_picker_count">%d models</string>
|
||||
<string name="power_feature_back_desc">Back</string>
|
||||
@@ -4667,4 +4667,5 @@
|
||||
<string name="voice_overlay_setup_start">Start voice overlay</string>
|
||||
<string name="voice_overlay_settings_hint">Optional in both builds. Open Voice Focus in Chat and choose Overlay to start. Permissions alone never start listening.</string>
|
||||
<string name="voice_overlay_reset_position">Reset position</string>
|
||||
<string name="injected_context_gateway_unsupported">Not sent in Gateway chat. This connection does not support extra per-turn context.</string>
|
||||
</resources>
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
package com.hermesandroid.relay.screenshots
|
||||
|
||||
import androidx.compose.ui.test.junit4.createComposeRule
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.assertCountEquals
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
import androidx.compose.ui.test.onRoot
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.github.takahirom.roborazzi.captureRoboImage
|
||||
import com.hermesandroid.relay.ui.components.InjectedContextSheet
|
||||
import com.hermesandroid.relay.ui.theme.HermesRelayTheme
|
||||
import com.hermesandroid.relay.viewmodel.ChatViewModel
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.annotation.Config
|
||||
import org.robolectric.annotation.GraphicsMode
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
@GraphicsMode(GraphicsMode.Mode.NATIVE)
|
||||
@Config(sdk = [34], qualifiers = "w360dp-h720dp-xhdpi")
|
||||
class InjectedContextSheetTest {
|
||||
@get:Rule val compose = createComposeRule()
|
||||
|
||||
@Test
|
||||
fun gatewayPreviewLabelsUnsupportedContextWithoutShowingPhonePreamble() {
|
||||
showPreview("gateway")
|
||||
compose.onAllNodesWithText(
|
||||
"Not sent in Gateway chat. This connection does not support extra per-turn context.",
|
||||
).assertCountEquals(2)
|
||||
compose.onNodeWithText("Hermes-Relay Android app", substring = true).assertDoesNotExist()
|
||||
compose.onNodeWithText("Server-side persona").assertExists()
|
||||
compose.onRoot().captureRoboImage("build/ui-regression/injected-context-gateway.png")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun apiOnlyPreviewShowsThePreparedMobileContext() {
|
||||
showPreview("sessions")
|
||||
compose.onNodeWithText("Hermes-Relay Android app", substring = true).assertExists()
|
||||
compose.onNodeWithText("Not sent in Gateway chat", substring = true).assertDoesNotExist()
|
||||
compose.onRoot().captureRoboImage("build/ui-regression/injected-context-api.png")
|
||||
}
|
||||
|
||||
private fun showPreview(endpoint: String) {
|
||||
val preview = ChatViewModel().apply { streamingEndpoint = endpoint }.previewInjectedContext()
|
||||
compose.setContent {
|
||||
HermesRelayTheme(appThemeId = "hermes-relay", themePreference = "dark") {
|
||||
InjectedContextSheet(context = preview, onDismiss = {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
@@ -1736,6 +1736,24 @@ class ChatViewModelGatewayInboundTurnTest {
|
||||
assertEquals(false, gatewayClient.sessionModelProvider()?.fast)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun injectedContextPreviewMatchesBareGatewayPayload() {
|
||||
viewModel.appContextSettings = com.hermesandroid.relay.util.AppContextSettings(
|
||||
master = true, battery = true, currentApp = true,
|
||||
)
|
||||
val preview = viewModel.previewInjectedContext()
|
||||
assertFalse(preview.perTurnContextSupported)
|
||||
assertNull(preview.combinedSystemMessage)
|
||||
|
||||
viewModel.sendMessage("Keep this message unchanged")
|
||||
gatewayHarness.awaitRpc("prompt.submit")
|
||||
val submitted = gatewayHarness.rpcLog.last { it.first == "prompt.submit" }.second
|
||||
assertEquals(JsonPrimitive("Keep this message unchanged"), submitted["text"])
|
||||
assertFalse(submitted.containsKey("system_message"))
|
||||
assertFalse(submitted.containsKey("surface"))
|
||||
assertEquals(0, apiCompletionsRequestCount.get())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun dashboardOnlyConnectionCanSendWithoutApiClient() {
|
||||
viewModel.updateGatewayClient(null)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.hermesandroid.relay.viewmodel
|
||||
|
||||
import com.hermesandroid.relay.data.Profile
|
||||
import com.hermesandroid.relay.util.AppContextSettings
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertNull
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(sdk = [34])
|
||||
class InjectedContextTest {
|
||||
@Test
|
||||
fun gatewayPreviewExcludesPhoneContextEvenWhenSharingIsEnabled() {
|
||||
val viewModel = ChatViewModel().apply {
|
||||
streamingEndpoint = "gateway"
|
||||
appContextSettings = AppContextSettings(master = true, battery = true, currentApp = true)
|
||||
setSelectedProfileProvider { Profile(name = "writer", model = "test-model", systemMessage = "Profile persona") }
|
||||
}
|
||||
|
||||
val preview = viewModel.previewInjectedContext()
|
||||
|
||||
assertFalse(preview.perTurnContextSupported)
|
||||
assertTrue(preview.personaOwnedServerSide)
|
||||
assertNull(preview.personaPrompt)
|
||||
assertNull(preview.appContext)
|
||||
assertNull(preview.interfaceContext)
|
||||
assertNull(preview.mediaCapability)
|
||||
assertNull(preview.combinedSystemMessage)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun apiOnlyTransportsRetainOptedInPhoneContextAndMasterOffRemovesIt() {
|
||||
for (endpoint in listOf("sessions", "runs", "completions")) {
|
||||
val viewModel = ChatViewModel().apply { streamingEndpoint = endpoint }
|
||||
val enabled = viewModel.previewInjectedContext()
|
||||
assertTrue(enabled.perTurnContextSupported)
|
||||
assertFalse(enabled.personaOwnedServerSide)
|
||||
assertTrue(enabled.appContext!!.contains("Hermes-Relay Android app"))
|
||||
assertEquals(enabled.appContext, enabled.combinedSystemMessage)
|
||||
|
||||
viewModel.appContextSettings = AppContextSettings(master = false, battery = true, currentApp = true)
|
||||
val disabled = viewModel.previewInjectedContext()
|
||||
assertNull(disabled.appContext)
|
||||
assertNull(disabled.combinedSystemMessage)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun changingTransportRebuildsPreviewWithoutChangingSharingPreference() {
|
||||
val viewModel = ChatViewModel().apply { streamingEndpoint = "sessions" }
|
||||
val apiPreview = viewModel.previewInjectedContext()
|
||||
viewModel.streamingEndpoint = "gateway"
|
||||
assertNull(viewModel.previewInjectedContext().appContext)
|
||||
assertTrue(viewModel.appContextSettings.master)
|
||||
viewModel.streamingEndpoint = "sessions"
|
||||
assertEquals(apiPreview.appContext, viewModel.previewInjectedContext().appContext)
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
"verification": "ai-translated",
|
||||
"review_refs": [],
|
||||
"source_sha256": {
|
||||
"main": "1059097e479afcdc8414c3f2df2ccffa9447c2a601dc408ba87cbce661e1e5a6",
|
||||
"main": "8588c42385e783a2ddf888b515ca6b97a5df44a30d3619c048d3d03d91dd5278",
|
||||
"sideload": "4abff4f1069091ec2de735c3037a7ec7d77699cb4321e8511a622437bceaf7c2"
|
||||
},
|
||||
"surfaces": {
|
||||
@@ -48,7 +48,7 @@
|
||||
"verification": "ai-translated",
|
||||
"review_refs": [],
|
||||
"source_sha256": {
|
||||
"main": "1059097e479afcdc8414c3f2df2ccffa9447c2a601dc408ba87cbce661e1e5a6",
|
||||
"main": "8588c42385e783a2ddf888b515ca6b97a5df44a30d3619c048d3d03d91dd5278",
|
||||
"sideload": "4abff4f1069091ec2de735c3037a7ec7d77699cb4321e8511a622437bceaf7c2"
|
||||
},
|
||||
"surfaces": {
|
||||
@@ -72,7 +72,7 @@
|
||||
"verification": "ai-translated",
|
||||
"review_refs": [],
|
||||
"source_sha256": {
|
||||
"main": "1059097e479afcdc8414c3f2df2ccffa9447c2a601dc408ba87cbce661e1e5a6",
|
||||
"main": "8588c42385e783a2ddf888b515ca6b97a5df44a30d3619c048d3d03d91dd5278",
|
||||
"sideload": "4abff4f1069091ec2de735c3037a7ec7d77699cb4321e8511a622437bceaf7c2"
|
||||
},
|
||||
"surfaces": {
|
||||
@@ -96,7 +96,7 @@
|
||||
"verification": "ai-translated",
|
||||
"review_refs": [],
|
||||
"source_sha256": {
|
||||
"main": "1059097e479afcdc8414c3f2df2ccffa9447c2a601dc408ba87cbce661e1e5a6",
|
||||
"main": "8588c42385e783a2ddf888b515ca6b97a5df44a30d3619c048d3d03d91dd5278",
|
||||
"sideload": "4abff4f1069091ec2de735c3037a7ec7d77699cb4321e8511a622437bceaf7c2"
|
||||
},
|
||||
"surfaces": {
|
||||
@@ -120,7 +120,7 @@
|
||||
"verification": "ai-translated",
|
||||
"review_refs": [],
|
||||
"source_sha256": {
|
||||
"main": "1059097e479afcdc8414c3f2df2ccffa9447c2a601dc408ba87cbce661e1e5a6",
|
||||
"main": "8588c42385e783a2ddf888b515ca6b97a5df44a30d3619c048d3d03d91dd5278",
|
||||
"sideload": "4abff4f1069091ec2de735c3037a7ec7d77699cb4321e8511a622437bceaf7c2"
|
||||
},
|
||||
"surfaces": {
|
||||
@@ -135,7 +135,7 @@
|
||||
"verification": "ai-translated",
|
||||
"review_refs": [],
|
||||
"source_sha256": {
|
||||
"main": "1059097e479afcdc8414c3f2df2ccffa9447c2a601dc408ba87cbce661e1e5a6",
|
||||
"main": "8588c42385e783a2ddf888b515ca6b97a5df44a30d3619c048d3d03d91dd5278",
|
||||
"sideload": "4abff4f1069091ec2de735c3037a7ec7d77699cb4321e8511a622437bceaf7c2"
|
||||
},
|
||||
"surfaces": {
|
||||
|
||||
@@ -58,6 +58,33 @@ standard upstream media/file delivery, and concise-response expectations. Once
|
||||
that contract is available in the supported Hermes baseline, adopt it and add
|
||||
Gateway conformance coverage proving the exact prompt bytes and session source.
|
||||
|
||||
Issues [#556](https://github.com/Codename-11/hermes-relay/issues/556) and
|
||||
[#557](https://github.com/Codename-11/hermes-relay/issues/557) share this contract
|
||||
gap. The Android audit fix labels unsupported context; automatic Android
|
||||
identification and Gateway phone-status delivery still require upstream work.
|
||||
Rechecked against upstream `5dea46d13deec9549bdc2ea703ae9201d733c28d`:
|
||||
|
||||
- [`methods_prompt.py`](https://github.com/NousResearch/hermes-agent/blob/5dea46d13deec9549bdc2ea703ae9201d733c28d/tui_gateway/methods_prompt.py)
|
||||
accepts `surface` only for `hud` and `voice-live`; it has no general
|
||||
per-turn system-context parameter. Neither surface means Android.
|
||||
- [`session_notifications.py`](https://github.com/NousResearch/hermes-agent/blob/5dea46d13deec9549bdc2ea703ae9201d733c28d/tui_gateway/session_notifications.py)
|
||||
adds those built-in surface notes to model input without changing the
|
||||
persisted user row. This is the existing upstream seam to extend, with
|
||||
explicit client capability negotiation, bounded opted-in context, and
|
||||
turn-owned snapshots through queueing, retries, and client switches.
|
||||
- [`server.py`](https://github.com/NousResearch/hermes-agent/blob/5dea46d13deec9549bdc2ea703ae9201d733c28d/tui_gateway/server.py)
|
||||
accepts a caller-supplied session `source`, but
|
||||
[`prompt_builder.py`](https://github.com/NousResearch/hermes-agent/blob/5dea46d13deec9549bdc2ea703ae9201d733c28d/agent/prompt_builder.py)
|
||||
has no Android platform hint. A session-origin label is not verified
|
||||
current-turn sender identity. Do not invent a platform or use a client hint
|
||||
as authorization for phone tools.
|
||||
- The API server's `POST /api/sessions` source field belongs to the explicit
|
||||
API-only surface. Android standard chat creates/resumes sessions through
|
||||
Gateway RPC; that REST field does not add per-turn context to `prompt.submit`.
|
||||
|
||||
Keep unknown/older hosts supported without sending private parameters,
|
||||
rewriting the user transcript, overriding persona, or requiring Relay.
|
||||
|
||||
---
|
||||
|
||||
## Scope sensitive-media prompt guidance to capable clients
|
||||
|
||||
@@ -597,6 +597,8 @@ Bottom navigation bar with 4 tabs:
|
||||
```
|
||||
|
||||
### Chat Tab
|
||||
|
||||
- **Context preview** — the Injected context sheet describes the bound chat transport, not a delivery receipt. Standard Gateway chat has no general per-turn system-context slot: phone status, the Android client preamble, media hints, and interface-context blocks are omitted. Phone status and turn context show an explicit unsupported note. API-only chats retain the opted-in context and sharing controls; the Settings example is labeled API-only. Gateway persona and optional Relay-reported configuration remain separately server-owned. No context is prepended to user text or written into the personality slot to bypass this boundary.
|
||||
- **Top bar and Profile Shelf (three-layer agent model).** Layout from left to right:
|
||||
1. **Connection chip** — tap to open `ConnectionSwitcherSheet` (all paired servers + health indicator). Auto-hidden when you only have one Connection. See `docs/decisions.md` §19.
|
||||
2. **Agent avatar/name region** — tap to expand or collapse the Profile Shelf immediately below the app bar. With only one visible effective identity, the shelf stays hidden and the same tap opens Agent Passport.
|
||||
|
||||
@@ -21,6 +21,9 @@ import sys
|
||||
|
||||
REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||
FOCUSED_TESTS = (
|
||||
"com.hermesandroid.relay.viewmodel.InjectedContextTest",
|
||||
"com.hermesandroid.relay.screenshots.InjectedContextSheetTest",
|
||||
"com.hermesandroid.relay.viewmodel.ChatViewModelGatewayInboundTurnTest.injectedContextPreviewMatchesBareGatewayPayload",
|
||||
"com.hermesandroid.relay.voice.VoiceOverlayLifecycleTest",
|
||||
"com.hermesandroid.relay.voice.VoiceOverlayForegroundServiceTest",
|
||||
"com.hermesandroid.relay.voice.VoiceOverlayPresentationTest",
|
||||
|
||||
@@ -121,7 +121,7 @@ Google Play builds do not include AccessibilityService-backed screen reading or
|
||||
| Chat empty state | Logo + suggestion chips |
|
||||
| Animated streaming dots | Pulsing 3-dot indicator during streaming |
|
||||
| Haptic feedback | On send, copy, stream complete, error |
|
||||
| App context prompt | Toggleable system message for mobile context |
|
||||
| App context prompt | Opt-in phone details and mobile context for API-only chats; Gateway limitations shown in the context preview |
|
||||
|
||||
## Security
|
||||
|
||||
|
||||
+16
-9
@@ -255,15 +255,22 @@ Each assistant message shows token usage below the timestamp:
|
||||
|
||||
## App context prompt
|
||||
|
||||
When enabled (**Settings → Chat → App context prompt**, on by default),
|
||||
Hermes-Relay tells the agent it's talking to a phone so replies stay
|
||||
mobile-friendly and concise, and can attach optional bridge/permission and
|
||||
safety-rail summaries. On the standard (API-server) connection this rides an
|
||||
invisible system message. The Gateway connection carries no app-context preamble
|
||||
— its protocol has no hidden per-turn slot, and adding one would leave the text
|
||||
in your saved chat history — so there the agent reads phone state on demand via
|
||||
the `android_phone_status` tool. Privacy-sensitive fields (foreground app,
|
||||
battery) default off and are only added when you opt in.
|
||||
**Settings → Chat → Share phone status with agent** controls an extra system
|
||||
message in API-only chats. It identifies Hermes-Relay Android to the agent and
|
||||
can include optional phone status. Foreground app and battery sharing default
|
||||
off and are included only when you opt in. Turning the master switch off also
|
||||
removes the Android preamble.
|
||||
|
||||
Standard Gateway chats do not send this block: upstream has no general
|
||||
per-turn context slot. The **Injected context** sheet marks phone status and
|
||||
turn context as unsupported on Gateway, and Settings labels its sample as an
|
||||
API-only example. The sheet is a preview, not proof of delivery or a complete
|
||||
view of the agent prompt; persona and Relay configuration are server-owned.
|
||||
|
||||
The optional Relay `android_phone_status` tool can provide phone state when
|
||||
enabled for the selected profile. Its presence does not identify who sent the
|
||||
current message. Automatic Android identification on Gateway still needs an
|
||||
upstream client-surface contract; pairing alone does not provide it.
|
||||
|
||||
## Persistent connection
|
||||
|
||||
|
||||
@@ -89,7 +89,7 @@ Available in **Settings > Chat**.
|
||||
|---------|---------|-------------|
|
||||
| Show reasoning | `true` | Display thinking/reasoning blocks above responses |
|
||||
| Show token usage | `true` | Display input/output token counts and estimated cost |
|
||||
| App context prompt | `true` | Send system message telling agent user is on mobile |
|
||||
| Share phone status with agent | `true` | Include mobile context in API-only chats; not sent in standard Gateway chats |
|
||||
| Tool call display | `Detailed` | How tool calls appear: Off, Compact, or Detailed |
|
||||
| Personality | Server default | Active personality from `config.agent.personalities` via `GET /api/config` |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user