feat: Remote-Execute für Linux/Bash – OS-basierte Tool-Descriptions und remote.sh Script

Remote-Verbindungen erkennen jetzt das OS des Clients und passen die Tool-Description
dynamisch an (PowerShell für Windows, Bash für Linux). Neues remote.sh Script für
Linux/macOS-Clients mit embedded Python WebSocket-Client.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
MelekiandClaude Opus 4.6 committed 2026-04-16 09:31:56 +02:00
1 parent 1035066a39
commit 53cee67bef
11 files changed
+381 -27

No files matched your search

+7 -4
View File
@@ -64,8 +64,10 @@ public partial class AnthropicService
try
{
// MCP-Config generieren (immer – für ask_user_choice, optional Memory-Tools + remote_execute)
var hasRemote = remoteMgr != null && !string.IsNullOrEmpty(sessionId) && remoteMgr.GetBySessionId(sessionId) != null;
mcpConfigPath = GenerateMcpConfig(sessionId, agentId, hasRemote, unityMcpUrl, unityMcpToken);
var remoteConn = remoteMgr != null && !string.IsNullOrEmpty(sessionId) ? remoteMgr.GetBySessionId(sessionId) : null;
var hasRemote = remoteConn != null;
var remoteOs = remoteConn?.OsVersion ?? "";
mcpConfigPath = GenerateMcpConfig(sessionId, agentId, hasRemote, unityMcpUrl, unityMcpToken, remoteOs);
// Python-Verfügbarkeit prüfen und ggf. warnen
if (FindPythonCommand() == null)
@@ -567,7 +569,7 @@ public partial class AnthropicService
/// Generiert eine temporäre MCP-Config-Datei für die Claude CLI.
/// Enthält den MCP-Server für remote_execute.
/// </summary>
private string GenerateMcpConfig(string sessionId, string agentId = null, bool hasRemote = false, string unityMcpUrl = null, string unityMcpToken = null)
private string GenerateMcpConfig(string sessionId, string agentId = null, bool hasRemote = false, string unityMcpUrl = null, string unityMcpToken = null, string remoteOs = null)
{
// Port aus Konfiguration oder Default
var port = 19000;
@@ -587,7 +589,8 @@ public partial class AnthropicService
["GOTT_SESSION_ID"] = sessionId ?? "",
["GOTT_AUTH_TOKEN"] = Endpoints.InternalEndpoint.InternalToken,
["GOTT_AGENT_ID"] = agentId ?? "",
["GOTT_HAS_REMOTE"] = hasRemote ? "true" : "false"
["GOTT_HAS_REMOTE"] = hasRemote ? "true" : "false",
["GOTT_REMOTE_OS"] = remoteOs ?? ""
};
var pythonCmd = FindPythonCommand();
+3 -1
View File
@@ -101,7 +101,8 @@ public partial class AnthropicService
if (systemPrompt != null && systemPrompt.Count > 0)
payload["system"] = systemPrompt;
var hasRemote = remoteMgr?.GetBySessionId(sessionId) != null;
var remoteConn = remoteMgr?.GetBySessionId(sessionId);
var hasRemote = remoteConn != null;
AddToolsToPayload(payload, new ToolPayloadOptions
{
Workspace = workspace,
@@ -113,6 +114,7 @@ public partial class AnthropicService
AllowUserChoice = allowUserChoice,
PlanMode = planMode,
IncludeRemote = hasRemote,
RemoteOs = remoteConn?.OsVersion,
IncludeGitHubSearch = useGitHubSearch && _toolService.HasGitHubToken,
IncludeSerperSearch = useSerperSearch && _toolService.HasSerperKey
});
+2 -1
View File
@@ -31,6 +31,7 @@ public partial class AnthropicService
public bool AllowUserChoice { get; init; }
public bool PlanMode { get; init; }
public bool IncludeRemote { get; init; }
public string RemoteOs { get; init; }
public bool IncludeGitHubSearch { get; init; }
public bool IncludeSerperSearch { get; init; }
}
@@ -337,7 +338,7 @@ public partial class AnthropicService
var allTools = _toolService.GetToolDefinitions(new ToolDefinitionOptions
{
IncludeFileTools = hasWorkspace, IncludeMemory = includeMemory,
IncludeUserChoice = opts.AllowUserChoice, IncludeRemote = opts.IncludeRemote,
IncludeUserChoice = opts.AllowUserChoice, IncludeRemote = opts.IncludeRemote, RemoteOs = opts.RemoteOs,
IncludeMemorySearch = includeMemorySearch, IncludeSendToSession = includeSendToSession,
IncludeGitHubSearch = opts.IncludeGitHubSearch, IncludeSerperSearch = opts.IncludeSerperSearch
});
+2 -2
View File
@@ -51,7 +51,7 @@ public class ChatService
/// <summary>
/// Baut den vollständigen ChatContext auf: Agent, Model, SystemPrompt, Chain, Workspace etc.
/// </summary>
public async Task<ChatContext> PrepareContext(string sessionId, string userId, int maxIterations = 100, bool planMode = false, bool hasRemoteConnection = false)
public async Task<ChatContext> PrepareContext(string sessionId, string userId, int maxIterations = 100, bool planMode = false, bool hasRemoteConnection = false, string remoteOs = null)
{
var session = await _db.GetSession(sessionId);
if (session == null || (userId != null && session.UserId != userId) || string.IsNullOrEmpty(session.AgentId))
@@ -89,7 +89,7 @@ public class ChatService
? _toolService.GetToolDefinitions(new ToolDefinitionOptions
{
IncludeFileTools = hasWorkspace, IncludeMemory = includeMemory,
IncludeUserChoice = agent.AllowUserChoice, IncludeRemote = hasRemoteConnection,
IncludeUserChoice = agent.AllowUserChoice, IncludeRemote = hasRemoteConnection, RemoteOs = remoteOs,
IncludeGitHubSearch = includeGitHubSearch, IncludeSerperSearch = includeSerperSearch
})
: Array.Empty<object>();
+13 -4
View File
@@ -21,6 +21,7 @@ public class ToolDefinitionOptions
public bool IncludeMemory { get; set; }
public bool IncludeUserChoice { get; set; } = true;
public bool IncludeRemote { get; set; }
public string RemoteOs { get; set; }
public bool IncludeMemorySearch { get; set; }
public bool IncludeSendToSession { get; set; }
public bool IncludeGitHubSearch { get; set; }
@@ -106,7 +107,7 @@ public class ToolService
if (opts.IncludeMemorySearch)
allTools.Add(GetMemorySearchTool());
if (opts.IncludeRemote)
allTools.Add(GetRemoteExecuteTool());
allTools.Add(GetRemoteExecuteTool(opts.RemoteOs));
if (opts.IncludeSendToSession)
allTools.Add(GetSendToSessionTool());
if (opts.IncludeGitHubSearch)
@@ -352,18 +353,26 @@ public class ToolService
};
}
private object GetRemoteExecuteTool()
private object GetRemoteExecuteTool(string remoteOs = null)
{
var isLinux = (remoteOs ?? "").Contains("Linux", StringComparison.OrdinalIgnoreCase);
var desc = isLinux
? "Führt einen Bash-Befehl auf der verbundenen Remote-Linux-Workstation aus. Gibt stdout und stderr zurück. Nutze dies für Diagnose und Administration des Remote-PCs (z.B. Netzwerk, Services, Logs, Pakete). Timeout: 180 Sekunden."
: "Führt einen PowerShell-Befehl auf der verbundenen Remote-Windows-Workstation aus. Gibt stdout und stderr zurück. Nutze dies für Diagnose und Administration des Remote-PCs (z.B. Druckerprobleme, Netzwerk, Services, Registry). Timeout: 180 Sekunden.";
var cmdDesc = isLinux
? "Bash-Befehl zum Ausführen auf dem Remote-PC"
: "PowerShell-Befehl zum Ausführen auf dem Remote-PC";
return new
{
name = "remote_execute",
description = "Führt einen PowerShell-Befehl auf der verbundenen Remote-Windows-Workstation aus. Gibt stdout und stderr zurück. Nutze dies für Diagnose und Administration des Remote-PCs (z.B. Druckerprobleme, Netzwerk, Services, Registry). Timeout: 180 Sekunden.",
description = desc,
input_schema = new
{
type = "object",
properties = new Dictionary<string, object>
{
["command"] = new { type = "string", description = "PowerShell-Befehl zum Ausführen auf dem Remote-PC" }
["command"] = new { type = "string", description = cmdDesc }
},
required = new[] { "command" }
}