feat: ship agent-first mission control v0.2.57
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
using System.Text.Json.Nodes;
|
||||
using Nexus.Api.Models;
|
||||
|
||||
namespace Nexus.Api.Services;
|
||||
@@ -19,7 +20,8 @@ public interface IGatewayConnector
|
||||
string? GatewayVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Required version from configuration, or null when unpinned.
|
||||
/// Required version from configuration, falling back to Nexus' verified
|
||||
/// OpenClaw release pin when the setting is absent or blank.
|
||||
/// </summary>
|
||||
string? RequiredVersion { get; }
|
||||
|
||||
@@ -37,6 +39,169 @@ public interface IGatewayConnector
|
||||
/// Detailed status message (e.g. error or version info).
|
||||
/// </summary>
|
||||
string? StatusMessage { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Stable Nexus backend device id used for non-loopback Gateway pairing.
|
||||
/// The private key and device token are never exposed through this contract.
|
||||
/// </summary>
|
||||
string? DeviceId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether a paired backend device token is available in protected server-side storage.
|
||||
/// </summary>
|
||||
bool DeviceTokenConfigured { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Whether the Gateway is waiting for an operator to approve the current device request.
|
||||
/// </summary>
|
||||
bool PairingRequired { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Exact pending OpenClaw pairing request id, when supplied by the Gateway.
|
||||
/// </summary>
|
||||
string? PairingRequestId { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Negotiated Gateway protocol version from the latest hello-ok frame.
|
||||
/// </summary>
|
||||
int? ProtocolVersion { get; }
|
||||
|
||||
/// <summary>
|
||||
/// RPC methods advertised by the connected Gateway.
|
||||
/// </summary>
|
||||
IReadOnlySet<string> AdvertisedMethods { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Event families advertised by the connected Gateway.
|
||||
/// </summary>
|
||||
IReadOnlySet<string> AdvertisedEvents { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Operator scopes granted by the Gateway during the handshake.
|
||||
/// </summary>
|
||||
IReadOnlySet<string> GrantedScopes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Normalized endpoint and TLS pin currently used by the running connector.
|
||||
/// These values never include credentials.
|
||||
/// </summary>
|
||||
string? ActiveEndpoint => null;
|
||||
string? ActiveTlsFingerprint => null;
|
||||
|
||||
/// <summary>
|
||||
/// Timestamp of the latest event frame received from the Gateway.
|
||||
/// </summary>
|
||||
DateTimeOffset? LastEventAt { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether the current Gateway explicitly advertises an RPC method.
|
||||
/// </summary>
|
||||
bool Supports(string method);
|
||||
|
||||
/// <summary>
|
||||
/// Invokes a Gateway RPC over the authenticated protocol-v4 connection.
|
||||
/// </summary>
|
||||
Task<JsonNode?> InvokeAsync(
|
||||
string method,
|
||||
object? parameters = null,
|
||||
TimeSpan? timeout = null,
|
||||
CancellationToken cancellationToken = default,
|
||||
OpenClawInvocationContext? invocationContext = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a bounded newest-first snapshot of recently received Gateway events.
|
||||
/// </summary>
|
||||
IReadOnlyList<GatewayEventEnvelope> GetRecentEvents(int limit = 100);
|
||||
|
||||
/// <summary>
|
||||
/// Requests a new explicit operator-scope set for the next Gateway
|
||||
/// handshake. The production connector closes the current socket so
|
||||
/// OpenClaw can start its normal pairing or scope-upgrade flow.
|
||||
/// Test connectors may keep the default no-op implementation.
|
||||
/// </summary>
|
||||
Task RequestOperatorScopesAsync(
|
||||
IReadOnlyCollection<string> scopes,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Re-targets the single connector after Setup has validated the endpoint.
|
||||
/// The optional bootstrap token remains process-memory-only until OpenClaw
|
||||
/// issues a bound device token.
|
||||
/// </summary>
|
||||
Task ConfigureEndpointAsync(
|
||||
string endpoint,
|
||||
string? tlsFingerprint,
|
||||
string? bootstrapToken,
|
||||
CancellationToken cancellationToken = default)
|
||||
=> Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Closes the active socket after a local detach. The background connector
|
||||
/// may return to an unauthenticated discovery/pairing state, but the
|
||||
/// adopted profile and protected device token are no longer active.
|
||||
/// </summary>
|
||||
Task DisconnectAsync(CancellationToken cancellationToken = default)
|
||||
=> Task.CompletedTask;
|
||||
}
|
||||
|
||||
public sealed record GatewayEventEnvelope(
|
||||
string Event,
|
||||
JsonNode? Payload,
|
||||
long? Sequence,
|
||||
long? StateVersion,
|
||||
DateTimeOffset ReceivedAt);
|
||||
|
||||
/// <summary>
|
||||
/// Correlation metadata for one logical Nexus-to-OpenClaw invocation.
|
||||
/// Only fields defined by the OpenClaw wire schema are sent to the Gateway:
|
||||
/// correlation is reflected in the request id, W3C traceparent is attached to
|
||||
/// the request frame, and idempotencyKey is added to params only when
|
||||
/// <see cref="IncludeIdempotencyParameter"/> is explicitly enabled for a
|
||||
/// schema-confirmed method. Actor and the complete context remain in Nexus'
|
||||
/// local audit boundary.
|
||||
/// </summary>
|
||||
public sealed record OpenClawInvocationContext(
|
||||
string IdempotencyKey,
|
||||
string CorrelationId,
|
||||
string Actor,
|
||||
string TraceParent,
|
||||
bool IncludeIdempotencyParameter = false)
|
||||
{
|
||||
public static OpenClawInvocationContext Create(
|
||||
string? actor = null,
|
||||
string? idempotencyKey = null,
|
||||
string? correlationId = null,
|
||||
string? traceParent = null,
|
||||
bool includeIdempotencyParameter = false)
|
||||
=> OpenClawInvocationContextFactory.Create(
|
||||
actor,
|
||||
idempotencyKey,
|
||||
correlationId,
|
||||
traceParent,
|
||||
includeIdempotencyParameter);
|
||||
}
|
||||
|
||||
public sealed class OpenClawGatewayRpcException : Exception
|
||||
{
|
||||
public OpenClawGatewayRpcException(
|
||||
string code,
|
||||
string message,
|
||||
JsonNode? details = null,
|
||||
bool retryable = false,
|
||||
int? retryAfterMs = null)
|
||||
: base(message)
|
||||
{
|
||||
Code = code;
|
||||
Details = details;
|
||||
Retryable = retryable;
|
||||
RetryAfterMs = retryAfterMs;
|
||||
}
|
||||
|
||||
public string Code { get; }
|
||||
public JsonNode? Details { get; }
|
||||
public bool Retryable { get; }
|
||||
public int? RetryAfterMs { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user