Fremde Laufzeiten: Claude Code und Befehl in der Sandbox, Egress-Proxy, Vorschlag statt Einsatz (#712)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-09-25 22:46:49 +02:00
co-authored by Claude Opus 5.5
parent 7d6c2c9495
commit 367ea387f6
40 changed files with 3428 additions and 29 deletions
+31 -1
View File
@@ -55,7 +55,37 @@ public sealed record AgentDto(
IReadOnlyList<AgentToolDto> Tools,
// #715: What makes the agent read foreign content — its tools, or "setting". Empty: standard tier.
IReadOnlyList<string> ForeignContentSources,
bool TreatAsForeignReader);
bool TreatAsForeignReader,
// #712
AgentRuntimeDto Runtime);
/// <summary>#712: Where an agent's runs happen.</summary>
public sealed record AgentRuntimeDto(
string Kind,
IReadOnlyList<string> AllowedTools,
int MaxTurns,
int TimeoutMinutes,
string Command,
IReadOnlyList<string> Arguments,
IReadOnlyList<string> Egress);
/// <summary>#712: What foreign runtimes find on this machine — never a key, only whether there is one.</summary>
public sealed record RuntimesDto(
bool SandboxAvailable,
string? SandboxReason,
IReadOnlyList<string> Kinds,
IReadOnlyList<string> DefaultAllowedTools,
ClaudeCodeDto ClaudeCode);
public sealed record ClaudeCodeDto(
string Executable,
string? Located,
string Auth,
bool HasApiKey,
bool HasOAuthToken);
/// <summary>#712: Changes to the Claude Code account. Empty keys keep the stored ones.</summary>
public sealed record ClaudeCodeInputDto(string? Executable, string? Auth, string? ApiKey, string? OAuthToken);
/// <summary>
/// Ein Werkzeug am Agenten. <b>Ohne die Einstellungen</b> — die stehen in einem freien
+17 -1
View File
@@ -43,7 +43,23 @@ internal static class Mapping
tools?.Invoke(name)?.ReadsForeignContent == true))
.ToList(),
tools is null ? [] : Core.Organisation.ReportingLine.TrustOf(agent, tools).Sources,
agent.TreatAsForeignReader);
agent.TreatAsForeignReader,
agent.Runtime.ToDto());
public static AgentRuntimeDto ToDto(this Core.Runtimes.AgentRuntimeConfig runtime)
=> new(Core.Runtimes.RuntimeKinds.Normalize(runtime.Kind), runtime.AllowedTools, runtime.MaxTurns,
runtime.TimeoutMinutes, runtime.Command, runtime.Arguments, runtime.Egress);
public static Core.Runtimes.AgentRuntimeConfig ToConfig(this AgentRuntimeDto dto) => new()
{
Kind = dto.Kind ?? Core.Runtimes.RuntimeKinds.Native,
AllowedTools = [.. dto.AllowedTools ?? []],
MaxTurns = dto.MaxTurns,
TimeoutMinutes = dto.TimeoutMinutes,
Command = dto.Command ?? "",
Arguments = [.. dto.Arguments ?? []],
Egress = [.. dto.Egress ?? []]
};
/// <summary>
/// Die Einstellungen eines Werkzeugs — <b>ohne die Geheimnisse</b>.
@@ -134,6 +134,30 @@ internal static class ApiEndpoints
agents.MapDelete("/{agentId}", (AppHost host, string agentId) =>
host.AgentAdmin.Remove(agentId).ToResponse());
// #712: the runtime — native, or foreign in the sandbox.
agents.MapPut("/{agentId}/runtime", (AppHost host, string agentId, AgentRuntimeDto input) =>
host.AgentAdmin.SetRuntime(agentId, input.ToConfig()).ToResponse());
var runtimes = api.MapGroup("/runtimes");
runtimes.MapGet("/", (AppHost host) =>
{
var sandbox = host.Engine?.Sandbox;
var claude = host.Instance.ClaudeCode;
return new RuntimesDto(
sandbox?.IsAvailable ?? false,
sandbox?.UnavailableReason ?? (sandbox is null ? "no engine" : null),
Core.Runtimes.RuntimeKinds.All,
Core.Runtimes.ClaudeCodeRuntime.DefaultAllowedTools,
new ClaudeCodeDto(
claude.Executable,
Core.Runtimes.ClaudeCodeRuntime.Locate(claude),
claude.Auth,
!string.IsNullOrWhiteSpace(claude.ApiKey),
!string.IsNullOrWhiteSpace(claude.OAuthToken)));
});
runtimes.MapPut("/claude-code", (AppHost host, ClaudeCodeInputDto input) =>
host.AgentAdmin.SetClaudeCode(input.Executable, input.Auth, input.ApiKey, input.OAuthToken).ToResponse());
// #715: Can only tighten — the tools decide the tier, this adds to it.
agents.MapPut("/{agentId}/foreign-reader", (AppHost host, string agentId, bool value) =>
host.AgentAdmin.SetTreatAsForeignReader(agentId, value).ToResponse());