Skip to content

feat(ai,remote,media): P0-P2 features - AI assistant, Tailscale remote access, agent/media templates - #20

Merged
JusterZhu merged 2 commits into
mainfrom
feat/p0-p2-ai-remote-media
Aug 29, 2026
Merged

feat(ai,remote,media): P0-P2 features - AI assistant, Tailscale remote access, agent/media templates#20
JusterZhu merged 2 commits into
mainfrom
feat/p0-p2-ai-remote-media

Conversation

@JusterZhu

Copy link
Copy Markdown
Contributor

P0-P2 全部需求落地:

  • P0-1: AI 对话 API + fortlink AI 助手页
  • P0-2: opencode/hermes AI 宿主模板
  • P0-3: Tailscale 免穿透远程访问
  • P1-4: Debian 一键安装脚本
  • P1-5: jellyfin 影音 + /dev/dri 直通
  • P1-6: docker 镜像源配置 + compose 查看
  • P2-7: kodi 垂直模板
  • 修复 AlertEngine.Dispose 崩溃
  • 新增 ai/remote/docker 配置分类

…P0-3)

- AiAssistantService + /api/ai/chat: OpenAI-compatible chat proxy (default
  local Ollama, configurable endpoint/model/key), SSE streaming + non-streaming
- RemoteAccessService + /api/remote: Tailscale-based zero-config remote access
  (status/enable/disable), no public IP needed
- Agent Catalog: opencode/hermes 24h AI host templates (P0-2), jellyfin media
  center with /dev/dri GPU passthrough (P1-5), kodi vertical template (P2-7)
- ComposeGenerator: devices whitelist restricted to /dev/dri
- ConfigMetaRegistry: ai/remote/docker categories with whitelisted entries
- AlertEngine.Dispose: tolerate repeated CTS disposal (crash fix)
- eng/install: one-click Debian/Ubuntu install + deb packaging (P1-4)
- NAbilityConstants: AiChat, RemoteAccess capabilities
…talog

- AiAssistantServiceTests: streaming/non-streaming/error/config contract
- RemoteAccessServiceTests: status parsing, enable/disable command construction
- AgentCatalogTests: opencode/hermes/jellyfin/kodi templates + devices whitelist
- ComposeGeneratorTests: /dev/dri allowed, non-dri rejected
- ConfigApiTests/ConfigMetaRegistryTests: new categories and sensitive-key rules
Copilot AI lite review requested due to automatic review settings August 29, 2026 04:52
@JusterZhu
JusterZhu merged commit 1a8595b into main Aug 29, 2026
2 checks passed
@JusterZhu
JusterZhu deleted the feat/p0-p2-ai-remote-media branch August 29, 2026 04:56

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR implements the P0–P2 feature set around AI assistant chat, Tailscale-based remote access, and expanded agent/media templates, along with new configuration categories/keys and an observability crash fix. It also adds Debian/Ubuntu installation packaging/scripts and extends the agent management surface (compose viewing).

Changes:

  • Add AI assistant service + /api/ai/chat endpoint (including streaming SSE support) and related config metadata.
  • Add Tailscale remote access service + /api/remote endpoints and related config metadata.
  • Expand agent catalog/templates (opencode/hermes/jellyfin/kodi) and tighten compose safety rules (device whitelist), plus add Debian install tooling and fix AlertEngine.Dispose crash.

Reviewed changes

Copilot reviewed 20 out of 20 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
tests/FortOS.Tests.Integration/ConfigMetaRegistryTests.cs Adds assertions for newly introduced config keys and sensitivity expectations.
tests/FortOS.Tests.Integration/Api/RemoteAccessServiceTests.cs Adds coverage for RemoteAccessService status parsing and enable/disable command behavior.
tests/FortOS.Tests.Integration/Api/ConfigApiTests.cs Updates expected config categories list to include ai/remote/docker.
tests/FortOS.Tests.Integration/Api/AiAssistantServiceTests.cs Adds coverage for AI assistant endpoint/model selection and streaming/non-streaming parsing.
tests/FortOS.Tests.Integration/Agent/ComposeGeneratorTests.cs Adds tests for /dev/dri device allowlist behavior.
tests/FortOS.Tests.Integration/Agent/AgentCatalogTests.cs Extends catalog expectations for new templates and parameter/access note checks.
src/FortOS.Security/Models/NAbilityConstants.cs Adds capability constants for AI chat and remote access management.
src/FortOS.Observability/Alerts/AlertEngine.cs Makes Dispose tolerant of repeated calls to avoid ObjectDisposedException crash.
src/FortOS.Modules.Agent/AgentModule.cs Adds GetComposeAsync to read deployed agent compose files.
src/FortOS.Api/Services/RemoteAccessService.cs Introduces Tailscale-based remote access service (status/enable/disable).
src/FortOS.Api/Services/AiAssistantService.cs Introduces OpenAI-compatible chat relay service with SSE streaming aggregation.
src/FortOS.Api/Program.cs Registers new AI/Remote services in DI.
src/FortOS.Api/Controllers/RemoteController.cs Adds remote access controller endpoints with capability checks.
src/FortOS.Api/Controllers/AiController.cs Adds AI chat controller with JSON + SSE streaming modes.
src/FortOS.Api/Controllers/AgentsController.cs Adds agent compose retrieval endpoint.
src/FortOS.Api/Configuration/ConfigMetaRegistry.cs Adds ai/remote/docker categories and whitelisted config entries.
src/FortOS.Agent/Compose/ComposeGenerator.cs Replaces blanket devices rejection with /dev/dri allowlist validation.
src/FortOS.Agent/Catalog/AgentCatalog.cs Adds built-in templates for opencode/hermes/jellyfin/kodi.
eng/install/install.sh Adds Debian/Ubuntu one-click installer script.
eng/install/build-deb.sh Adds .deb packaging script (systemd unit/env template included).

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +143 to +146
/// <summary>读取已部署 agent 的 Compose 配置(P1-6 Docker 管理:可视化查看)。</summary>
[HttpGet("{id}/compose")]
public async Task<object> Compose(string id, [FromServices] AgentModule agents, CancellationToken ct)
{
Comment on lines +48 to +61
// SSE 流式:每段 delta 以 data: 帧推送,结束时发送 [DONE]。
HttpContext.Response.Headers.ContentType = "text/event-stream";
await HttpContext.Response.WriteAsync("data: {\"start\":true}\n\n", ct).ConfigureAwait(false);
var streamed = await _ai.ChatAsync(
aiRequest,
// 复用请求取消令牌:客户端断开时停止推送,避免向已断开连接继续写。
delta => _ = HttpContext.Response.WriteAsync($"data: {JsonSerializer.Serialize(new { delta })}\n\n", ct),
ct).ConfigureAwait(false);
if (!string.IsNullOrEmpty(streamed.Error))
{
await HttpContext.Response.WriteAsync($"data: {JsonSerializer.Serialize(new { error = streamed.Error })}\n\n", ct).ConfigureAwait(false);
}

await HttpContext.Response.WriteAsync("data: [DONE]\n\n", ct).ConfigureAwait(false);
Comment on lines +47 to +59
using var doc = JsonDocument.Parse(status);
var root = doc.RootElement;
var loggedIn = root.TryGetProperty("BackendState", out var state)
&& string.Equals(state.GetString(), "Running", StringComparison.OrdinalIgnoreCase);
var self = root.TryGetProperty("Self", out var selfProp) ? selfProp : default;
var hostName = self.ValueKind == JsonValueKind.Object && self.TryGetProperty("HostName", out var hn)
? hn.GetString()
: configuration[HostNameKey];
var ip = self.ValueKind == JsonValueKind.Object && self.TryGetProperty("TailscaleIPs", out var ips)
&& ips.ValueKind == JsonValueKind.Array && ips.GetArrayLength() > 0
? ips[0].GetString()
: null;
return new RemoteStatus(true, true, loggedIn, hostName, ip, loggedIn ? "已连接。" : "Tailscale 已安装但未登录。");
Comment on lines +293 to +313
if (!service.Children.TryGetValue(new YamlScalarNode("devices"), out var devices)
|| devices is not YamlSequenceNode deviceList)
{
return;
}

foreach (var device in deviceList.Children)
{
var value = device is YamlScalarNode scalar ? scalar.Value : null;
if (string.IsNullOrWhiteSpace(value))
{
throw new InvalidDataException("Agent compose devices entries must be scalar paths.");
}

var hostPath = value.Split(':', 2)[0];
if (!hostPath.StartsWith("/dev/dri", StringComparison.Ordinal))
{
throw new InvalidDataException($"Agent compose may only mount GPU devices under /dev/dri (got '{hostPath}').");
}
}
}
Comment thread eng/install/install.sh
Comment on lines +22 to +24
FORTOS_DEST="${FORTOS_DEST:-/opt/fortos}"
FORTOS_DATA_ROOT="${FortOS_DATA_ROOT:-/srv/nas}"
FORTOS_ENV_FILE="${FORTOS_ENV_FILE:-/etc/fortos/fortos.env}"
Comment thread eng/install/install.sh
Comment on lines +72 to +80
# dotnet runtime: needed to run FortOS.Api. Prefer the runtime from the
# Microsoft feed; fall back to a distro package if unavailable.
if ! command -v dotnet >/dev/null 2>&1; then
log "安装 .NET Runtime…"
install_pkg dotnet-runtime-8.0 2>/dev/null \
|| curl -fsSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 8.0 --runtime aspnetcore --install-dir /usr/share/dotnet \
|| warn ".NET Runtime 安装失败,请手动安装后重试。"
export PATH="$PATH:/usr/share/dotnet"
fi
Comment thread eng/install/build-deb.sh
Comment on lines +62 to +74
# Control file
cat > "$STAGE/DEBIAN/control" <<EOF
Package: fortos
Version: $VERSION
Section: admin
Priority: optional
Architecture: amd64
Depends: dotnet-runtime-8.0 | dotnet-runtime-9.0 | dotnet-runtime-10.0, docker.io | docker-ce, smbclient, nfs-common
Maintainer: FortOS Team <dev@fortos.example>
Description: FortOS — security-first Linux NAS management service
Deploys the FortOS API (REST/gRPC) with container agent orchestration,
file sharing, backup, AI assistant and Tailscale remote access.
EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants