Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ jobs:
- run: ./tests/deployment-package.sh
- uses: actions/upload-artifact@v4
with:
name: farhelm-V0.9.0-linux-x86_64
name: farhelm-V0.10.0-linux-x86_64
path: |
dist/release/farhelm-*
dist/release/SHA256SUMS
Expand Down
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ members = [
]

[workspace.package]
version = "0.9.0"
version = "0.10.0"
edition = "2024"
rust-version = "1.98"
license = "Apache-2.0"
Expand Down
12 changes: 8 additions & 4 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
<p><strong>A remote control plane for personal research and GPU training environments</strong></p>
<p>See training-host status from your phone and safely extend remote control without exposing inbound ports on training machines.</p>
<p>
<a href="https://github.com/Xiiiing/FarHelm/releases/tag/V0.9.0">V0.9.0</a> ·
<a href="https://github.com/Xiiiing/FarHelm/releases/tag/V0.10.0">V0.10.0</a> ·
<a href="./deploy/README.en.md">Deployment guide</a> ·
<a href="./README.md">简体中文</a>
</p>
</div>

> [!IMPORTANT]
> `V0.9.0` completes the project workspace, native Codex model and permission details, light/dark appearance, and custom accent colors. It fixes cached long-history switching, notification/experiment/audit pagination, and schedule synchronization. The Rust Agent, persistent local Codex, outbound WSS, experiment reports, and browser notifications remain in place.
> `V0.10.0` adds native Codex model and reasoning-effort selection, session renaming and native identity checks, and improves chat typography, reading layout, and the composer. The Rust Agent, persistent local Codex, outbound WSS, native permissions, experiment reports, schedules, and browser notifications remain in place.

## Quick install

Expand Down Expand Up @@ -131,7 +131,7 @@ Desktop global navigation and mobile bottom navigation remain visible in Codex.

Assistant replies support Markdown tables, code copying, math, and safe HTTPS links. Execution details in each turn form a collapsed group with visible failures. The composer stays visible, and reading older content does not jump to the bottom on new messages. Large-message continuation is separate from loading earlier conversations. Switching sessions immediately displays cached history and retains each draft; failed refreshes preserve visible content. Inactive body and parsing caches total at most 32 MiB, with at most 20 inactive histories, and are cleared on logout. Steer and interrupt target the visible active turn.

The system uses black and white base colors with one customizable theme color; the logo retains its original brand colors. Settings offer separate light/dark mode and theme color choices (graphite, blue, green, violet, rose, orange, or a custom color) for primary buttons, selected states, links, and focus, applied immediately and saved in the current browser. The rounded composer stays visible; locally served Manrope and Noto Sans SC fonts share a consistent reading column. Submission and expanding execution details use brief animations that respect the system’s reduced-motion preference; cached session switches do not replay the entry animation.
The system uses black and white base colors with one customizable theme color; the logo retains its original brand colors. Settings offer separate light/dark mode and theme color choices (graphite, blue, green, violet, rose, orange, or a custom color) for primary buttons, selected states, links, and focus, applied immediately and saved in the current browser. The rounded composer stays visible, with its input and tools sharing one surface. Platform fonts take priority, with locally served Noto Sans SC for Chinese, a consistent reading column, and a clear type hierarchy. Submission and expanding execution details use brief animations that respect the system’s reduced-motion preference; cached session switches do not replay the entry animation.

Upgrade Hub before Agent when moving from V0.7.1. SQLite schema remains 7. Older Agents retain HTTP compatibility; upgraded Agents use WSS without also claiming work over HTTP. Existing Python directories remain on installed machines for rollback validation and are never invoked by the new version.

Expand All @@ -154,7 +154,11 @@ flowchart LR

FarHelm is one monorepo, but Hub and Agent are compiled separately and retain distinct privileges and attack surfaces. Codex communicates only over local stdio. Authentication remains local; Hub relays bodies only in bounded memory for at most 20 seconds.

The Codex composer displays the session model, reasoning effort, and permission details returned by the server. Resuming inherits native Codex settings; new browser sessions use project configuration, with an optional isolated Git worktree. Unconfirmed settings are marked unknown rather than inferred from legacy session modes. Adjust the model and permissions in Codex on the server. Browser approval prompts are not supported yet, so operations requiring user approval are declined. Upgrade Hub before Agent and verify that Agent advertises `codex.session_context`. Explicit inspect/edit creation through older APIs and the CLI remains compatible.
The Codex composer displays the session model, reasoning effort, and permission details returned by the server. Click the model to choose from the local Codex catalog, including supported reasoning efforts, for the next queued instruction and subsequent turns. Steering an active turn retains its running model. If persistence is unconfirmed, retries keep the original instruction and model to prevent duplicate execution or silently changing the request. Without a selection, native session settings are inherited; schedules inherit the session model when they execute. The browser never changes global model or permission settings. Resuming inherits native Codex settings; new browser sessions use project configuration, with an optional isolated Git worktree. Unconfirmed settings are marked unknown rather than inferred from legacy session modes. Browser approval prompts are not supported yet, so operations requiring user approval are declined. Upgrade Hub before Agent: model selection and native identity checks require `codex.model_choice` and `codex.native_identity`, respectively; permission display continues to use `codex.session_context`. Explicit inspect/edit creation through older APIs and the CLI remains compatible.

The browser and server Codex use the same native session ID, without assigning a generic name to new sessions. The session menu supports renaming and “Continue in native Codex,” which checks local persistence and the native name and copies `codex resume <session ID>`. An empty session might not be stored yet; send a message before checking. Other clients must use the same server, user, and Codex data directory. Existing desktop lists may need a refresh or reopening the project. Older sessions still named `Codex session` can be renamed for matching labels; temporary message summaries are never automatically saved as formal names.

Native Codex holds an exclusive session writer. If the dialog says FarHelm still holds the connection, choose “Release connection and continue” before resuming in a native client. Agent closes only its own Codex connection, after checking that all threads are idle, stored, and have no background terminals, with a 15-second bound. Other clients and local training programs are unaffected. Close the native client's session connection before returning to browser editing; browser submissions and schedules still attempt to resume sessions as planned.

## Local development

Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
<p><strong>面向个人科研与 GPU 训练环境的远程控制平面</strong></p>
<p>从手机查看训练服务器状态,并在不开放训练机入站端口的前提下安全扩展远程控制能力。</p>
<p>
<a href="https://github.com/Xiiiing/FarHelm/releases/tag/V0.9.0">V0.9.0</a> ·
<a href="https://github.com/Xiiiing/FarHelm/releases/tag/V0.10.0">V0.10.0</a> ·
<a href="./deploy/README.md">部署文档</a> ·
<a href="./README.en.md">English</a>
</p>
</div>

> [!IMPORTANT]
> `V0.9.0` 完善项目工作区、原生 Codex 模型与权限展示、浅深主题和自定义主题色,修复长会话缓存切换、通知/实验/审计分页刷新及定时任务同步。继续使用 Rust Agent、常驻本机 Codex 和出站 WSS,保留实验上报与页面通知。
> `V0.10.0` 支持选择原生 Codex 模型与推理强度、重命名和核对跨端会话,改善聊天字体、阅读布局和输入区。继续使用 Rust Agent、常驻本机 Codex 和出站 WSS,保留原生权限、实验上报、定时任务与页面通知。

## 快速安装

Expand Down Expand Up @@ -131,7 +131,7 @@ printf '训练失败,请登录查看详情' | farhelm-agent experiment report

助手回复支持 Markdown 表格、代码复制、公式及安全 HTTPS 链接。每轮执行过程默认合并折叠,失败可直接辨认。输入区固定可见,阅读旧内容时不会被新消息拉回底部;大消息的“继续加载此消息”与“加载更早对话”分别处理。切换会话立即显示已有缓存,并保留各自草稿;刷新失败不清空已显示内容。非活动正文缓存与解析缓存合计不超过 32 MiB,最多保留 20 个非活动历史,退出登录清空。补充与中断只针对可见的活动轮次。

系统外观使用黑白基础色和一个可自定义主题色,Logo 保留品牌原色。设置中可独立选择浅深模式及主题色(石墨、蓝、绿、紫、玫瑰、橙或自定义颜色),用于主要按钮、选中状态、链接与焦点,即时生效并保存在当前浏览器。圆润的输入框固定可见;界面使用本地加载的 Manrope 与 Noto Sans SC 字体和统一阅读列。提交与展开过程提供简短动效,遵循系统“减少动态效果”设置;已缓存会话切换不重播进入动画。
系统外观使用黑白基础色和一个可自定义主题色,Logo 保留品牌原色。设置中可独立选择浅深模式及主题色(石墨、蓝、绿、紫、玫瑰、橙或自定义颜色),用于主要按钮、选中状态、链接与焦点,即时生效并保存在当前浏览器。圆润的输入框固定可见,输入和工具共用一个表面;界面优先使用系统字体,以本地加载的 Noto Sans SC 补齐中文,并统一阅读列和字号层级。提交与展开过程提供简短动效,遵循系统“减少动态效果”设置;已缓存会话切换不重播进入动画。

从 V0.7.1 升级先更新 Hub,再更新 Agent。SQLite schema 保持 7,旧 Agent 的 HTTP 链路保留兼容;新 Agent 使用 WSS,连接期间不重复领取任务。旧 Python 目录保留在安装机供回退验证,新版本不再调用它。

Expand All @@ -154,7 +154,11 @@ flowchart LR

FarHelm 是一个 monorepo,但 Hub 与 Agent 分离编译并保持不同权限与攻击面。Codex 只通过本机 stdio 通信;登录凭据保留在本机,Hub 仅在最长 20 秒的有界内存中中转正文。

Codex 输入区显示服务器返回的会话模型、推理强度和权限详情。恢复会话沿用原生 Codex 设置;网页新建会话默认使用项目配置,隔离 Git 工作区为可选项。尚未确认的设置明确标为未知,不根据会话旧模式猜测权限。模型和权限在服务器上的 Codex 中调整;网页暂不支持人工审批,需要用户批准的操作会被拒绝。请先升级 Hub,再升级 Agent,确认 Agent 已提供 `codex.session_context` 能力。旧 API/CLI 显式创建的 inspect/edit 模式继续兼容。
Codex 输入区显示服务器返回的会话模型、推理强度和权限详情。点击模型可从本机 Codex 提供的目录选择模型与推理强度,用于下一条排队指令及后续对话;补充正在运行的轮次仍使用原模型。保存未确认时,重试沿用原指令和模型,避免重复执行或悄悄改变请求。未选择时继承会话设置,定时任务在执行时继承会话模型。网页不会修改全局模型或权限。恢复会话沿用原生 Codex 设置;网页新建会话默认使用项目配置,隔离 Git 工作区为可选项。尚未确认的设置明确标为未知,不根据会话旧模式猜测权限。网页暂不支持人工审批,需要用户批准的操作会被拒绝。请先升级 Hub,再升级 Agent,模型选择和原生会话核对分别要求 `codex.model_choice`、`codex.native_identity` 能力;权限显示沿用 `codex.session_context`。旧 API/CLI 显式创建的 inspect/edit 模式继续兼容。

网页与服务器 Codex 使用同一个原生会话 ID,不再为新会话强制设置通用名称。会话菜单支持重命名,以及“在原生 Codex 中继续”:核对本地保存状态、原生名称并复制 `codex resume <会话 ID>`。空会话可能尚未落盘,先发送一条消息再核对。其他客户端须连接同一服务器、同一用户及 Codex 数据目录;桌面端已有列表可能需要刷新或重新打开项目。旧会话如果仍叫 `Codex session`,可重命名以统一两端显示;网页不会把临时消息摘要自动写成正式名称。

原生 Codex 对会话有写入锁。若弹窗提示 FarHelm 仍持有连接,点击“释放连接后继续”再到原生客户端恢复;Agent 只在所有会话空闲、已落盘且没有后台终端时关闭自己的 Codex 连接,检查最多 15 秒,不影响其他客户端或本地训练程序。回到网页续写前关闭原生客户端的会话连接;网页发送和定时执行仍会按原计划尝试恢复会话。

## 本地开发

Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.9.0
0.10.0
71 changes: 70 additions & 1 deletion crates/farhelm-protocol/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ impl AgentHeartbeat {
"codex.item_offsets".to_owned(),
"codex.native".to_owned(),
"codex.session_context".to_owned(),
"codex.model_choice".to_owned(),
"codex.native_identity".to_owned(),
"agent.live".to_owned(),
],
protocol: FARHELM_PROTOCOL.to_owned(),
Expand Down Expand Up @@ -560,6 +562,65 @@ pub struct SendCodexMessageRequest {
pub turn_id: Option<String>,
#[serde(default = "default_prompt_delivery")]
pub delivery: PromptDelivery,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub model_choice: Option<CodexModelChoice>,
}

/// Explicit next-turn settings, persisted only with the Agent's prompt receipt.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct CodexModelChoice {
pub model: String,
pub reasoning_effort: String,
}

impl CodexModelChoice {
#[must_use]
pub fn is_valid(&self) -> bool {
valid_model_id(&self.model) && valid_reasoning_effort(&self.reasoning_effort)
}
}

#[must_use]
pub fn valid_model_id(value: &str) -> bool {
!value.is_empty()
&& value.len() <= 128
&& value
.bytes()
.all(|b| b.is_ascii_alphanumeric() || matches!(b, b'-' | b'_' | b'.' | b':'))
}

#[must_use]
pub fn valid_reasoning_effort(value: &str) -> bool {
matches!(
value,
"none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | "ultra"
)
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CodexModelOption {
pub model: String,
pub display_name: String,
pub reasoning_efforts: Vec<String>,
pub default_reasoning_effort: String,
pub is_default: bool,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CodexModelList {
pub models: Vec<CodexModelOption>,
}

#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct CodexNativeIdentity {
pub session_id: String,
pub persisted: bool,
#[serde(default)]
pub held_by_agent: bool,
pub native_name: Option<String>,
pub source: Option<String>,
pub history_mode: Option<String>,
}

const fn default_prompt_delivery() -> PromptDelivery {
Expand Down Expand Up @@ -604,6 +665,14 @@ pub fn valid_session_title(title: &str) -> bool {
)
}

#[must_use]
pub fn valid_session_name(name: &str) -> bool {
valid_session_title(name)
&& name.chars().count() <= 128
&& !name.chars().any(char::is_control)
&& !name.contains(['/', '\\'])
}

#[must_use]
pub fn public_event_payload(event_type: &str, payload: &serde_json::Value) -> serde_json::Value {
use serde_json::{Map, Value};
Expand Down Expand Up @@ -766,7 +835,7 @@ mod tests {
"agent_id": "gpu-a",
"hostname": "trainer-a",
"agent_version": "0.1.0",
"capabilities": ["codex.ephemeral_submit", "codex.session_display", "codex.item_offsets", "codex.native", "codex.session_context", "agent.live"]
"capabilities": ["codex.ephemeral_submit", "codex.session_display", "codex.item_offsets", "codex.native", "codex.session_context", "codex.model_choice", "codex.native_identity", "agent.live"]
})
);
}
Expand Down
Loading
Loading