use serde::{Deserialize, Deserializer, Serialize};
use crate::schema::{IsoDateTime, NonEmptyString, RunxSchema};
use crate::{JsonNumber, JsonObject, Reference, ResolutionRequest};
pub const EXTERNAL_ADAPTER_PROTOCOL_VERSION: &str = "runx.external_adapter.v1";
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ExternalAdapterProtocolVersion {
#[serde(rename = "runx.external_adapter.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ExternalAdapterManifestSchema {
#[serde(rename = "runx.external_adapter.manifest.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ExternalAdapterCredentialRequestSchema {
#[serde(rename = "runx.external_adapter.credential_request.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ExternalAdapterInvocationSchema {
#[serde(rename = "runx.external_adapter.invocation.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ExternalAdapterHostResolutionSchema {
#[serde(rename = "runx.external_adapter.host_resolution.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
pub enum ExternalAdapterCancellationSchema {
#[serde(rename = "runx.external_adapter.cancellation.v1")]
V1,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExternalAdapterTransportKind {
Process,
Http,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExternalAdapterStatus {
Completed,
Failed,
HostResolutionRequested,
Cancelled,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExternalAdapterCredentialPurpose {
ProviderApi,
Registry,
ArtifactStore,
WebhookVerification,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterTransport {
pub kind: ExternalAdapterTransportKind,
#[serde(skip_serializing_if = "Option::is_none")]
pub command: Option<NonEmptyString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub args: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub endpoint: Option<NonEmptyString>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterCredentialNeed {
pub purpose: ExternalAdapterCredentialPurpose,
pub provider: NonEmptyString,
#[serde(skip_serializing_if = "Option::is_none")]
pub scope_refs: Option<Vec<Reference>>,
pub required: bool,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterSandboxIntent {
pub profile: NonEmptyString,
pub network: bool,
pub cwd_policy: NonEmptyString,
#[serde(skip_serializing_if = "Option::is_none")]
pub writable_paths: Option<Vec<NonEmptyString>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterTimeouts {
pub startup_ms: u64,
pub invocation_ms: u64,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.external_adapter.manifest.v1")]
pub struct ExternalAdapterManifest {
pub schema: ExternalAdapterManifestSchema,
pub protocol_version: ExternalAdapterProtocolVersion,
pub adapter_id: NonEmptyString,
pub name: NonEmptyString,
pub version: NonEmptyString,
pub supported_source_types: Vec<NonEmptyString>,
pub transport: ExternalAdapterTransport,
pub timeouts: ExternalAdapterTimeouts,
#[serde(skip_serializing_if = "Option::is_none")]
pub credential_needs: Option<Vec<ExternalAdapterCredentialNeed>>,
pub sandbox_intent: ExternalAdapterSandboxIntent,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<JsonObject>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterCredentialReference {
pub credential_ref: Reference,
pub provider: NonEmptyString,
pub purpose: ExternalAdapterCredentialPurpose,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.external_adapter.credential_request.v1")]
pub struct ExternalAdapterCredentialRequest {
pub schema: ExternalAdapterCredentialRequestSchema,
pub protocol_version: ExternalAdapterProtocolVersion,
pub request_id: NonEmptyString,
pub adapter_id: NonEmptyString,
pub invocation_id: NonEmptyString,
pub credential_refs: Vec<ExternalAdapterCredentialReference>,
pub requested_at: IsoDateTime,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.external_adapter.invocation.v1")]
pub struct ExternalAdapterInvocation {
pub schema: ExternalAdapterInvocationSchema,
pub protocol_version: ExternalAdapterProtocolVersion,
pub invocation_id: NonEmptyString,
pub adapter_id: NonEmptyString,
pub run_id: NonEmptyString,
pub step_id: NonEmptyString,
pub source_type: NonEmptyString,
pub skill_ref: NonEmptyString,
pub harness_ref: Reference,
pub host_ref: Reference,
pub inputs: JsonObject,
#[serde(skip_serializing_if = "Option::is_none")]
pub resolved_inputs: Option<JsonObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub cwd: Option<NonEmptyString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub receipt_dir: Option<NonEmptyString>,
#[serde(skip_serializing_if = "Option::is_none")]
pub env: Option<JsonObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub credential_refs: Option<Vec<ExternalAdapterCredentialReference>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<JsonObject>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterArtifactObservation {
pub artifact_ref: Reference,
#[serde(skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterErrorObservation {
pub code: String,
pub message: String,
pub retryable: bool,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(untagged)]
pub enum ExternalAdapterTelemetryValue {
Number(JsonNumber),
String(String),
Bool(bool),
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
pub struct ExternalAdapterTelemetryObservation {
pub name: String,
pub value: ExternalAdapterTelemetryValue,
#[serde(skip_serializing_if = "Option::is_none")]
pub unit: Option<String>,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.external_adapter.response.v1")]
pub struct ExternalAdapterResponse {
pub schema: String,
pub protocol_version: String,
pub invocation_id: String,
pub adapter_id: String,
pub status: ExternalAdapterStatus,
#[serde(skip_serializing_if = "Option::is_none")]
pub stdout: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub stderr: Option<String>,
#[serde(
default,
deserialize_with = "deserialize_optional_nullable_i64",
skip_serializing_if = "Option::is_none"
)]
pub exit_code: Option<Option<i64>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub output: Option<JsonObject>,
#[serde(skip_serializing_if = "Option::is_none")]
pub artifacts: Option<Vec<ExternalAdapterArtifactObservation>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub errors: Option<Vec<ExternalAdapterErrorObservation>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub telemetry: Option<Vec<ExternalAdapterTelemetryObservation>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub metadata: Option<JsonObject>,
pub observed_at: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.external_adapter.host_resolution.v1")]
pub struct ExternalAdapterHostResolutionFrame {
pub schema: ExternalAdapterHostResolutionSchema,
pub protocol_version: ExternalAdapterProtocolVersion,
pub frame_id: NonEmptyString,
pub invocation_id: NonEmptyString,
pub adapter_id: NonEmptyString,
pub request: ResolutionRequest,
pub requested_at: IsoDateTime,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, RunxSchema)]
#[serde(deny_unknown_fields)]
#[runx_schema(id = "runx.external_adapter.cancellation.v1")]
pub struct ExternalAdapterCancellationFrame {
pub schema: ExternalAdapterCancellationSchema,
pub protocol_version: ExternalAdapterProtocolVersion,
pub frame_id: NonEmptyString,
pub invocation_id: NonEmptyString,
pub adapter_id: NonEmptyString,
pub reason: NonEmptyString,
pub requested_at: IsoDateTime,
}
fn deserialize_optional_nullable_i64<'de, D>(
deserializer: D,
) -> Result<Option<Option<i64>>, D::Error>
where
D: Deserializer<'de>,
{
Option::<i64>::deserialize(deserializer).map(Some)
}