Decouple gateway protocol from Rust runtime types
Move all worker-facing record types (TaskListRecord, RuntimeTaskRecord, TeamRecord, MailboxSummary, FeedItemRecord, LibraryAppRecord, etc.) into protocol-owned mirrors in records.rs. The gateway and worker_client now use these protocol types instead of importing from the runtime crate. Add worker-protocol/ with OpenAPI spec and JSON schemas as the language-neutral contract authority for the gateway-worker boundary. This is the migration surface for the TS worker replacement. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
pub mod manifest;
|
||||
pub mod protocol;
|
||||
pub mod records;
|
||||
pub mod runtime_host;
|
||||
pub mod unraid_template;
|
||||
|
||||
@@ -9,6 +10,15 @@ pub use manifest::{
|
||||
ChannelIdentity, DmKind, GatewayManifest, GatewaySettings, ManifestError, ProfileId,
|
||||
ProfileRecord, WorkerDefaults, WorkerSpec,
|
||||
};
|
||||
pub use records::{
|
||||
AppBundleManifestV1, AppCapability, AppHistoryEntry, AppHistoryResponse, AppKind,
|
||||
AppPackageRequest, AppPackageResult, AppPublishRequest, AppPublishResult, AppRepoLink,
|
||||
AppVisibility, AppWorkspaceRecord, BackgroundApprovalDecision,
|
||||
BackgroundApprovalRecord, FeedItemChangeKind, FeedItemKind, FeedItemRecord, FeedItemSource,
|
||||
FeedItemSourceKind, LibraryAppManifestV2, LibraryAppRecord, LibraryAppVersionRecord,
|
||||
MailboxMessage, MailboxSummary, MessageEnvelope, RuntimeTaskKind, RuntimeTaskRecord,
|
||||
RuntimeTaskStatus, TaskListRecord, TaskListStatus, TeamMemberRecord, TeamRecord,
|
||||
};
|
||||
pub use protocol::{
|
||||
GeneratedFileDescriptor, InboundAttachment, TurnSource, WorkerAgentListResponse,
|
||||
WorkerAppHistoryResponse, WorkerAppListResponse, WorkerAppPackageResponse,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use runtime::{
|
||||
|
||||
use crate::records::{
|
||||
AppHistoryResponse, AppPackageResult, AppPublishResult, AppWorkspaceRecord,
|
||||
BackgroundApprovalRecord, FeedItemRecord, LibraryAppRecord, LibraryAppVersionRecord,
|
||||
MailboxSummary, RuntimeTaskRecord, TaskListRecord, TeamRecord,
|
||||
MailboxMessage, MailboxSummary, RuntimeTaskRecord, TaskListRecord, TeamRecord,
|
||||
};
|
||||
|
||||
use crate::runtime_host::{ApprovalRequestPayload, AttachmentKind};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
@@ -182,7 +182,7 @@ pub struct WorkerMailboxSummaryResponse {
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct WorkerMailboxPendingResponse {
|
||||
pub messages: Vec<runtime::MailboxMessage>,
|
||||
pub messages: Vec<MailboxMessage>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
|
||||
@@ -0,0 +1,877 @@
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
fn default_branch_name() -> String {
|
||||
"main".to_string()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum TaskListStatus {
|
||||
Pending,
|
||||
InProgress,
|
||||
Completed,
|
||||
}
|
||||
|
||||
impl std::fmt::Display for TaskListStatus {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Pending => write!(f, "pending"),
|
||||
Self::InProgress => write!(f, "in_progress"),
|
||||
Self::Completed => write!(f, "completed"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<runtime::TaskListStatus> for TaskListStatus {
|
||||
fn from(value: runtime::TaskListStatus) -> Self {
|
||||
match value {
|
||||
runtime::TaskListStatus::Pending => Self::Pending,
|
||||
runtime::TaskListStatus::InProgress => Self::InProgress,
|
||||
runtime::TaskListStatus::Completed => Self::Completed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct TaskListRecord {
|
||||
pub id: String,
|
||||
pub subject: String,
|
||||
pub description: String,
|
||||
#[serde(rename = "activeForm", default, skip_serializing_if = "Option::is_none")]
|
||||
pub active_form: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub owner: Option<String>,
|
||||
pub status: TaskListStatus,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub blocks: Vec<String>,
|
||||
#[serde(rename = "blockedBy", default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub blocked_by: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub metadata: Option<BTreeMap<String, Value>>,
|
||||
#[serde(default)]
|
||||
pub internal: bool,
|
||||
#[serde(rename = "createdAt")]
|
||||
pub created_at: u64,
|
||||
#[serde(rename = "updatedAt")]
|
||||
pub updated_at: u64,
|
||||
}
|
||||
|
||||
impl From<runtime::TaskListRecord> for TaskListRecord {
|
||||
fn from(value: runtime::TaskListRecord) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
subject: value.subject,
|
||||
description: value.description,
|
||||
active_form: value.active_form,
|
||||
owner: value.owner,
|
||||
status: value.status.into(),
|
||||
blocks: value.blocks,
|
||||
blocked_by: value.blocked_by,
|
||||
metadata: value.metadata,
|
||||
internal: value.internal,
|
||||
created_at: value.created_at,
|
||||
updated_at: value.updated_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RuntimeTaskKind {
|
||||
Agent,
|
||||
Shell,
|
||||
}
|
||||
|
||||
impl From<runtime::RuntimeTaskKind> for RuntimeTaskKind {
|
||||
fn from(value: runtime::RuntimeTaskKind) -> Self {
|
||||
match value {
|
||||
runtime::RuntimeTaskKind::Agent => Self::Agent,
|
||||
runtime::RuntimeTaskKind::Shell => Self::Shell,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum RuntimeTaskStatus {
|
||||
Running,
|
||||
Completed,
|
||||
Failed,
|
||||
Stopped,
|
||||
}
|
||||
|
||||
impl RuntimeTaskStatus {
|
||||
#[must_use]
|
||||
pub fn is_terminal(self) -> bool {
|
||||
matches!(self, Self::Completed | Self::Failed | Self::Stopped)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for RuntimeTaskStatus {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Running => write!(f, "running"),
|
||||
Self::Completed => write!(f, "completed"),
|
||||
Self::Failed => write!(f, "failed"),
|
||||
Self::Stopped => write!(f, "stopped"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<runtime::RuntimeTaskStatus> for RuntimeTaskStatus {
|
||||
fn from(value: runtime::RuntimeTaskStatus) -> Self {
|
||||
match value {
|
||||
runtime::RuntimeTaskStatus::Running => Self::Running,
|
||||
runtime::RuntimeTaskStatus::Completed => Self::Completed,
|
||||
runtime::RuntimeTaskStatus::Failed => Self::Failed,
|
||||
runtime::RuntimeTaskStatus::Stopped => Self::Stopped,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct RuntimeTaskRecord {
|
||||
pub task_id: String,
|
||||
pub kind: RuntimeTaskKind,
|
||||
pub status: RuntimeTaskStatus,
|
||||
pub description: String,
|
||||
pub prompt: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub output_file: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub exit_code_file: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub final_result: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub error: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub exit_code: Option<i32>,
|
||||
#[serde(default)]
|
||||
pub notified: bool,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub pid: Option<u32>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub agent_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub agent_name: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub team_name: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub cwd: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub worktree_path: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub worktree_branch: Option<String>,
|
||||
pub created_at: u64,
|
||||
pub started_at: u64,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub completed_at: Option<u64>,
|
||||
}
|
||||
|
||||
impl From<runtime::RuntimeTaskRecord> for RuntimeTaskRecord {
|
||||
fn from(value: runtime::RuntimeTaskRecord) -> Self {
|
||||
Self {
|
||||
task_id: value.task_id,
|
||||
kind: value.kind.into(),
|
||||
status: value.status.into(),
|
||||
description: value.description,
|
||||
prompt: value.prompt,
|
||||
output_file: value.output_file,
|
||||
exit_code_file: value.exit_code_file,
|
||||
final_result: value.final_result,
|
||||
error: value.error,
|
||||
exit_code: value.exit_code,
|
||||
notified: value.notified,
|
||||
pid: value.pid,
|
||||
agent_id: value.agent_id,
|
||||
agent_name: value.agent_name,
|
||||
team_name: value.team_name,
|
||||
cwd: value.cwd,
|
||||
worktree_path: value.worktree_path,
|
||||
worktree_branch: value.worktree_branch,
|
||||
created_at: value.created_at,
|
||||
started_at: value.started_at,
|
||||
completed_at: value.completed_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TeamMemberRecord {
|
||||
pub agent_id: String,
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub agent_type: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub model: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub status: Option<String>,
|
||||
pub joined_at: u64,
|
||||
}
|
||||
|
||||
impl From<runtime::TeamMemberRecord> for TeamMemberRecord {
|
||||
fn from(value: runtime::TeamMemberRecord) -> Self {
|
||||
Self {
|
||||
agent_id: value.agent_id,
|
||||
name: value.name,
|
||||
agent_type: value.agent_type,
|
||||
model: value.model,
|
||||
status: value.status,
|
||||
joined_at: value.joined_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct TeamRecord {
|
||||
pub team_name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub agent_type: Option<String>,
|
||||
pub lead_agent_id: String,
|
||||
pub created_at: u64,
|
||||
pub updated_at: u64,
|
||||
#[serde(default)]
|
||||
pub deleted: bool,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub members: Vec<TeamMemberRecord>,
|
||||
}
|
||||
|
||||
impl From<runtime::TeamRecord> for TeamRecord {
|
||||
fn from(value: runtime::TeamRecord) -> Self {
|
||||
Self {
|
||||
team_name: value.team_name,
|
||||
description: value.description,
|
||||
agent_type: value.agent_type,
|
||||
lead_agent_id: value.lead_agent_id,
|
||||
created_at: value.created_at,
|
||||
updated_at: value.updated_at,
|
||||
deleted: value.deleted,
|
||||
members: value.members.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MessageEnvelope {
|
||||
pub id: String,
|
||||
pub from: String,
|
||||
pub to: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub summary: Option<String>,
|
||||
pub message: Value,
|
||||
pub timestamp: u64,
|
||||
#[serde(default)]
|
||||
pub read: bool,
|
||||
#[serde(default)]
|
||||
pub notified: bool,
|
||||
}
|
||||
|
||||
impl From<runtime::MessageEnvelope> for MessageEnvelope {
|
||||
fn from(value: runtime::MessageEnvelope) -> Self {
|
||||
Self {
|
||||
id: value.id,
|
||||
from: value.from,
|
||||
to: value.to,
|
||||
summary: value.summary,
|
||||
message: value.message,
|
||||
timestamp: value.timestamp,
|
||||
read: value.read,
|
||||
notified: value.notified,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MailboxMessage {
|
||||
pub recipient: String,
|
||||
pub envelope: MessageEnvelope,
|
||||
}
|
||||
|
||||
impl From<runtime::MailboxMessage> for MailboxMessage {
|
||||
fn from(value: runtime::MailboxMessage) -> Self {
|
||||
Self {
|
||||
recipient: value.recipient,
|
||||
envelope: value.envelope.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MailboxSummary {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub team_name: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub recent_messages: Vec<MailboxMessage>,
|
||||
}
|
||||
|
||||
impl From<runtime::MailboxSummary> for MailboxSummary {
|
||||
fn from(value: runtime::MailboxSummary) -> Self {
|
||||
Self {
|
||||
team_name: value.team_name,
|
||||
recent_messages: value.recent_messages.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(tag = "decision", rename_all = "snake_case")]
|
||||
pub enum BackgroundApprovalDecision {
|
||||
ApproveOnce,
|
||||
ApproveToolForSession,
|
||||
ApproveAllForSession,
|
||||
Deny { reason: String },
|
||||
CancelTurn,
|
||||
}
|
||||
|
||||
impl From<runtime::BackgroundApprovalDecision> for BackgroundApprovalDecision {
|
||||
fn from(value: runtime::BackgroundApprovalDecision) -> Self {
|
||||
match value {
|
||||
runtime::BackgroundApprovalDecision::ApproveOnce => Self::ApproveOnce,
|
||||
runtime::BackgroundApprovalDecision::ApproveToolForSession => {
|
||||
Self::ApproveToolForSession
|
||||
}
|
||||
runtime::BackgroundApprovalDecision::ApproveAllForSession => {
|
||||
Self::ApproveAllForSession
|
||||
}
|
||||
runtime::BackgroundApprovalDecision::Deny { reason } => Self::Deny { reason },
|
||||
runtime::BackgroundApprovalDecision::CancelTurn => Self::CancelTurn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct BackgroundApprovalRecord {
|
||||
pub approval_id: String,
|
||||
pub task_id: String,
|
||||
pub tool_name: String,
|
||||
pub input: String,
|
||||
pub current_mode: String,
|
||||
pub required_mode: String,
|
||||
#[serde(default)]
|
||||
pub reason: Option<String>,
|
||||
pub created_at: u64,
|
||||
#[serde(default)]
|
||||
pub notified: bool,
|
||||
#[serde(default)]
|
||||
pub decision: Option<BackgroundApprovalDecision>,
|
||||
}
|
||||
|
||||
impl From<runtime::BackgroundApprovalRecord> for BackgroundApprovalRecord {
|
||||
fn from(value: runtime::BackgroundApprovalRecord) -> Self {
|
||||
Self {
|
||||
approval_id: value.approval_id,
|
||||
task_id: value.task_id,
|
||||
tool_name: value.tool_name,
|
||||
input: value.input,
|
||||
current_mode: value.current_mode,
|
||||
required_mode: value.required_mode,
|
||||
reason: value.reason,
|
||||
created_at: value.created_at,
|
||||
notified: value.notified,
|
||||
decision: value.decision.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum FeedItemKind {
|
||||
Markdown,
|
||||
Code,
|
||||
Json,
|
||||
Diff,
|
||||
Image,
|
||||
HtmlPreview,
|
||||
Table,
|
||||
Binary,
|
||||
DeletedFile,
|
||||
AppPublished,
|
||||
}
|
||||
|
||||
impl From<runtime::FeedItemKind> for FeedItemKind {
|
||||
fn from(value: runtime::FeedItemKind) -> Self {
|
||||
match value {
|
||||
runtime::FeedItemKind::Markdown => Self::Markdown,
|
||||
runtime::FeedItemKind::Code => Self::Code,
|
||||
runtime::FeedItemKind::Json => Self::Json,
|
||||
runtime::FeedItemKind::Diff => Self::Diff,
|
||||
runtime::FeedItemKind::Image => Self::Image,
|
||||
runtime::FeedItemKind::HtmlPreview => Self::HtmlPreview,
|
||||
runtime::FeedItemKind::Table => Self::Table,
|
||||
runtime::FeedItemKind::Binary => Self::Binary,
|
||||
runtime::FeedItemKind::DeletedFile => Self::DeletedFile,
|
||||
runtime::FeedItemKind::AppPublished => Self::AppPublished,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum FeedItemSourceKind {
|
||||
Generated,
|
||||
Workspace,
|
||||
AppEvent,
|
||||
}
|
||||
|
||||
impl From<runtime::FeedItemSourceKind> for FeedItemSourceKind {
|
||||
fn from(value: runtime::FeedItemSourceKind) -> Self {
|
||||
match value {
|
||||
runtime::FeedItemSourceKind::Generated => Self::Generated,
|
||||
runtime::FeedItemSourceKind::Workspace => Self::Workspace,
|
||||
runtime::FeedItemSourceKind::AppEvent => Self::AppEvent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum FeedItemChangeKind {
|
||||
Created,
|
||||
Modified,
|
||||
Deleted,
|
||||
}
|
||||
|
||||
impl From<runtime::FeedItemChangeKind> for FeedItemChangeKind {
|
||||
fn from(value: runtime::FeedItemChangeKind) -> Self {
|
||||
match value {
|
||||
runtime::FeedItemChangeKind::Created => Self::Created,
|
||||
runtime::FeedItemChangeKind::Modified => Self::Modified,
|
||||
runtime::FeedItemChangeKind::Deleted => Self::Deleted,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct FeedItemSource {
|
||||
pub source_kind: FeedItemSourceKind,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub turn_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_file_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub source_files: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub change_kind: Option<FeedItemChangeKind>,
|
||||
}
|
||||
|
||||
impl From<runtime::FeedItemSource> for FeedItemSource {
|
||||
fn from(value: runtime::FeedItemSource) -> Self {
|
||||
Self {
|
||||
source_kind: value.source_kind.into(),
|
||||
turn_id: value.turn_id,
|
||||
source_file_id: value.source_file_id,
|
||||
source_files: value.source_files,
|
||||
change_kind: value.change_kind.map(Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct FeedItemRecord {
|
||||
pub feed_item_id: String,
|
||||
pub title: String,
|
||||
pub kind: FeedItemKind,
|
||||
pub source: FeedItemSource,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub linked_app_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub media_type: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub file_name: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub stored_path: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub preview_text: Option<String>,
|
||||
#[serde(default)]
|
||||
pub deleted: bool,
|
||||
pub created_at: u64,
|
||||
pub updated_at: u64,
|
||||
}
|
||||
|
||||
impl From<runtime::FeedItemRecord> for FeedItemRecord {
|
||||
fn from(value: runtime::FeedItemRecord) -> Self {
|
||||
Self {
|
||||
feed_item_id: value.feed_item_id,
|
||||
title: value.title,
|
||||
kind: value.kind.into(),
|
||||
source: value.source.into(),
|
||||
linked_app_id: value.linked_app_id,
|
||||
media_type: value.media_type,
|
||||
file_name: value.file_name,
|
||||
stored_path: value.stored_path,
|
||||
preview_text: value.preview_text,
|
||||
deleted: value.deleted,
|
||||
created_at: value.created_at,
|
||||
updated_at: value.updated_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AppKind {
|
||||
HtmlPage,
|
||||
ReactApp,
|
||||
Dashboard,
|
||||
DocumentExperience,
|
||||
ToolApp,
|
||||
}
|
||||
|
||||
impl From<runtime::AppKind> for AppKind {
|
||||
fn from(value: runtime::AppKind) -> Self {
|
||||
match value {
|
||||
runtime::AppKind::HtmlPage => Self::HtmlPage,
|
||||
runtime::AppKind::ReactApp => Self::ReactApp,
|
||||
runtime::AppKind::Dashboard => Self::Dashboard,
|
||||
runtime::AppKind::DocumentExperience => Self::DocumentExperience,
|
||||
runtime::AppKind::ToolApp => Self::ToolApp,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AppVisibility {
|
||||
Family,
|
||||
Admin,
|
||||
Archived,
|
||||
}
|
||||
|
||||
impl From<runtime::AppVisibility> for AppVisibility {
|
||||
fn from(value: runtime::AppVisibility) -> Self {
|
||||
match value {
|
||||
runtime::AppVisibility::Family => Self::Family,
|
||||
runtime::AppVisibility::Admin => Self::Admin,
|
||||
runtime::AppVisibility::Archived => Self::Archived,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum AppCapability {
|
||||
GetContext,
|
||||
ListFiles,
|
||||
ReadText,
|
||||
ReadJson,
|
||||
OpenFeedItem,
|
||||
OpenApp,
|
||||
PublishPatch,
|
||||
RequestAction,
|
||||
EmitEvent,
|
||||
}
|
||||
|
||||
impl From<runtime::AppCapability> for AppCapability {
|
||||
fn from(value: runtime::AppCapability) -> Self {
|
||||
match value {
|
||||
runtime::AppCapability::GetContext => Self::GetContext,
|
||||
runtime::AppCapability::ListFiles => Self::ListFiles,
|
||||
runtime::AppCapability::ReadText => Self::ReadText,
|
||||
runtime::AppCapability::ReadJson => Self::ReadJson,
|
||||
runtime::AppCapability::OpenFeedItem => Self::OpenFeedItem,
|
||||
runtime::AppCapability::OpenApp => Self::OpenApp,
|
||||
runtime::AppCapability::PublishPatch => Self::PublishPatch,
|
||||
runtime::AppCapability::RequestAction => Self::RequestAction,
|
||||
runtime::AppCapability::EmitEvent => Self::EmitEvent,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppRepoLink {
|
||||
pub url: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub branch: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub commit: Option<String>,
|
||||
}
|
||||
|
||||
impl From<runtime::AppRepoLink> for AppRepoLink {
|
||||
fn from(value: runtime::AppRepoLink) -> Self {
|
||||
Self {
|
||||
url: value.url,
|
||||
branch: value.branch,
|
||||
commit: value.commit,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct LibraryAppManifestV2 {
|
||||
pub schema_version: String,
|
||||
pub app_id: String,
|
||||
pub title: String,
|
||||
pub name: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub visibility: AppVisibility,
|
||||
pub created_at: u64,
|
||||
pub updated_at: u64,
|
||||
pub last_launched_at: u64,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub created_from_feed_item_id: Option<String>,
|
||||
pub current_version_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub published_commit: Option<String>,
|
||||
pub default_branch: String,
|
||||
pub local_repo_path: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub remote_repo: Option<AppRepoLink>,
|
||||
pub kind: AppKind,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub icon: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub tags: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub capabilities: Vec<AppCapability>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_turn_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub source_feed_item_ids: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<runtime::LibraryAppManifestV2> for LibraryAppManifestV2 {
|
||||
fn from(value: runtime::LibraryAppManifestV2) -> Self {
|
||||
Self {
|
||||
schema_version: value.schema_version,
|
||||
app_id: value.app_id,
|
||||
title: value.title,
|
||||
name: value.name,
|
||||
description: value.description,
|
||||
visibility: value.visibility.into(),
|
||||
created_at: value.created_at,
|
||||
updated_at: value.updated_at,
|
||||
last_launched_at: value.last_launched_at,
|
||||
created_from_feed_item_id: value.created_from_feed_item_id,
|
||||
current_version_id: value.current_version_id,
|
||||
published_commit: value.published_commit,
|
||||
default_branch: value.default_branch,
|
||||
local_repo_path: value.local_repo_path,
|
||||
remote_repo: value.remote_repo.map(Into::into),
|
||||
kind: value.kind.into(),
|
||||
icon: value.icon,
|
||||
tags: value.tags,
|
||||
capabilities: value.capabilities.into_iter().map(Into::into).collect(),
|
||||
source_turn_id: value.source_turn_id,
|
||||
source_feed_item_ids: value.source_feed_item_ids,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppBundleManifestV1 {
|
||||
pub schema_version: String,
|
||||
pub app_id: String,
|
||||
pub name: String,
|
||||
pub title: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
pub kind: AppKind,
|
||||
pub entry: String,
|
||||
pub files: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub icon: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub capabilities: Vec<AppCapability>,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
pub tags: Vec<String>,
|
||||
}
|
||||
|
||||
impl From<runtime::AppBundleManifestV1> for AppBundleManifestV1 {
|
||||
fn from(value: runtime::AppBundleManifestV1) -> Self {
|
||||
Self {
|
||||
schema_version: value.schema_version,
|
||||
app_id: value.app_id,
|
||||
name: value.name,
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
kind: value.kind.into(),
|
||||
entry: value.entry,
|
||||
files: value.files,
|
||||
icon: value.icon,
|
||||
capabilities: value.capabilities.into_iter().map(Into::into).collect(),
|
||||
tags: value.tags,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct LibraryAppVersionRecord {
|
||||
pub version_id: String,
|
||||
pub created_at: u64,
|
||||
pub entry: String,
|
||||
pub files: Vec<String>,
|
||||
#[serde(default = "default_branch_name")]
|
||||
pub branch: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub commit: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub published_at: Option<u64>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub source_turn_id: Option<String>,
|
||||
#[serde(
|
||||
alias = "source_artifact_ids",
|
||||
default,
|
||||
skip_serializing_if = "Vec::is_empty"
|
||||
)]
|
||||
pub source_feed_item_ids: Vec<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub changelog_summary: Option<String>,
|
||||
}
|
||||
|
||||
impl From<runtime::LibraryAppVersionRecord> for LibraryAppVersionRecord {
|
||||
fn from(value: runtime::LibraryAppVersionRecord) -> Self {
|
||||
Self {
|
||||
version_id: value.version_id,
|
||||
created_at: value.created_at,
|
||||
entry: value.entry,
|
||||
files: value.files,
|
||||
branch: value.branch,
|
||||
commit: value.commit,
|
||||
published_at: value.published_at,
|
||||
source_turn_id: value.source_turn_id,
|
||||
source_feed_item_ids: value.source_feed_item_ids,
|
||||
changelog_summary: value.changelog_summary,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct LibraryAppRecord {
|
||||
pub manifest: LibraryAppManifestV2,
|
||||
pub bundle_manifest: AppBundleManifestV1,
|
||||
pub current_version: LibraryAppVersionRecord,
|
||||
}
|
||||
|
||||
impl From<runtime::LibraryAppRecord> for LibraryAppRecord {
|
||||
fn from(value: runtime::LibraryAppRecord) -> Self {
|
||||
Self {
|
||||
manifest: value.manifest.into(),
|
||||
bundle_manifest: value.bundle_manifest.into(),
|
||||
current_version: value.current_version.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppPackageRequest {
|
||||
pub feed_item_id: String,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub requested_app_id: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub title: Option<String>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub description: Option<String>,
|
||||
}
|
||||
|
||||
impl From<AppPackageRequest> for runtime::AppPackageRequest {
|
||||
fn from(value: AppPackageRequest) -> Self {
|
||||
Self {
|
||||
feed_item_id: value.feed_item_id,
|
||||
requested_app_id: value.requested_app_id,
|
||||
title: value.title,
|
||||
description: value.description,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppPackageResult {
|
||||
pub app: LibraryAppRecord,
|
||||
pub created: bool,
|
||||
}
|
||||
|
||||
impl From<runtime::AppPackageResult> for AppPackageResult {
|
||||
fn from(value: runtime::AppPackageResult) -> Self {
|
||||
Self {
|
||||
app: value.app.into(),
|
||||
created: value.created,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppWorkspaceRecord {
|
||||
pub app_id: String,
|
||||
pub cwd: String,
|
||||
pub branch: String,
|
||||
pub head_commit: String,
|
||||
pub dirty: bool,
|
||||
pub bundle_manifest: AppBundleManifestV1,
|
||||
}
|
||||
|
||||
impl From<runtime::AppWorkspaceRecord> for AppWorkspaceRecord {
|
||||
fn from(value: runtime::AppWorkspaceRecord) -> Self {
|
||||
Self {
|
||||
app_id: value.app_id,
|
||||
cwd: value.cwd,
|
||||
branch: value.branch,
|
||||
head_commit: value.head_commit,
|
||||
dirty: value.dirty,
|
||||
bundle_manifest: value.bundle_manifest.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppPublishRequest {
|
||||
pub message: String,
|
||||
}
|
||||
|
||||
impl From<AppPublishRequest> for runtime::AppPublishRequest {
|
||||
fn from(value: AppPublishRequest) -> Self {
|
||||
Self {
|
||||
message: value.message,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppPublishResult {
|
||||
pub app: LibraryAppRecord,
|
||||
pub workspace: AppWorkspaceRecord,
|
||||
}
|
||||
|
||||
impl From<runtime::AppPublishResult> for AppPublishResult {
|
||||
fn from(value: runtime::AppPublishResult) -> Self {
|
||||
Self {
|
||||
app: value.app.into(),
|
||||
workspace: value.workspace.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppHistoryEntry {
|
||||
pub commit: String,
|
||||
pub message: String,
|
||||
pub authored_at: u64,
|
||||
}
|
||||
|
||||
impl From<runtime::AppHistoryEntry> for AppHistoryEntry {
|
||||
fn from(value: runtime::AppHistoryEntry) -> Self {
|
||||
Self {
|
||||
commit: value.commit,
|
||||
message: value.message,
|
||||
authored_at: value.authored_at,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub struct AppHistoryResponse {
|
||||
pub entries: Vec<AppHistoryEntry>,
|
||||
}
|
||||
|
||||
impl From<runtime::AppHistoryResponse> for AppHistoryResponse {
|
||||
fn from(value: runtime::AppHistoryResponse) -> Self {
|
||||
Self {
|
||||
entries: value.entries.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,13 @@ use axum::routing::{get, post};
|
||||
use axum::{Json, Router};
|
||||
use base64::Engine as _;
|
||||
use channel_gateway_core::{
|
||||
ApprovalDecision, ApprovalResponder, AttachmentRef, GeneratedFileDescriptor, HostError,
|
||||
RuntimeEvent, RuntimeHost, RuntimeHostConfig, SessionApprovalState, WorkerApprovalDecision,
|
||||
AppPackageRequest, AppPublishRequest, ApprovalDecision, ApprovalResponder, AttachmentRef,
|
||||
BackgroundApprovalRecord, GeneratedFileDescriptor, HostError, LibraryAppVersionRecord,
|
||||
MailboxMessage, MailboxSummary, RuntimeEvent, RuntimeHost, RuntimeHostConfig,
|
||||
RuntimeTaskRecord, SessionApprovalState,
|
||||
WorkerAgentListResponse, WorkerAppHistoryResponse, WorkerAppListResponse,
|
||||
WorkerAppPackageResponse, WorkerAppPublishResponse, WorkerAppSnapshotResponse,
|
||||
WorkerAppVersionResponse, WorkerAppWorkspaceResponse,
|
||||
WorkerAppVersionResponse, WorkerAppWorkspaceResponse, WorkerApprovalDecision,
|
||||
WorkerBackgroundApprovalListResponse, WorkerFeedItemResponse, WorkerFeedListResponse,
|
||||
WorkerMailboxMessageEvent, WorkerMailboxPendingResponse, WorkerMailboxSummaryResponse,
|
||||
WorkerStatusResponse, WorkerTaskListResponse, WorkerTaskSnapshotResponse,
|
||||
@@ -26,10 +28,10 @@ use channel_gateway_core::{
|
||||
WorkerTurnRequest,
|
||||
};
|
||||
use runtime::{
|
||||
clear_app_workspace_context, current_task_list_id, AppPackageRequest, AppPublishRequest,
|
||||
ArtifactLibraryStore, BackgroundApprovalDecision, BackgroundApprovalStore, FeedFileInput,
|
||||
FeedItemChangeKind, FeedItemSourceKind, RuntimeTaskKind, RuntimeTaskRecord,
|
||||
RuntimeTaskStore, TaskListStore, TeamStore, WorkspaceSnapshot,
|
||||
clear_app_workspace_context, current_task_list_id, ArtifactLibraryStore,
|
||||
BackgroundApprovalDecision, BackgroundApprovalStore, FeedFileInput, FeedItemChangeKind,
|
||||
FeedItemSourceKind, RuntimeTaskKind, RuntimeTaskStore, TaskListStore, TeamStore,
|
||||
WorkspaceSnapshot,
|
||||
};
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
@@ -311,7 +313,10 @@ async fn list_feed(
|
||||
let store = ArtifactLibraryStore::new();
|
||||
let items = store
|
||||
.list_feed(query.turn_id.as_deref())
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
Ok(Json(WorkerFeedListResponse {
|
||||
items,
|
||||
state_root: store.state_root_display().ok(),
|
||||
@@ -328,7 +333,8 @@ async fn get_feed_item(
|
||||
let store = ArtifactLibraryStore::new();
|
||||
let item = store
|
||||
.get_feed_item(&feed_item_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerFeedItemResponse {
|
||||
item,
|
||||
state_root: store.state_root_display().ok(),
|
||||
@@ -382,9 +388,11 @@ async fn package_feed_item(
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
request.feed_item_id = feed_item_id;
|
||||
let result = ArtifactLibraryStore::new()
|
||||
.package_feed_item(request)
|
||||
.package_feed_item(request.into())
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
Ok(Json(WorkerAppPackageResponse { result }))
|
||||
Ok(Json(WorkerAppPackageResponse {
|
||||
result: result.map(Into::into),
|
||||
}))
|
||||
}
|
||||
|
||||
async fn list_tasks(
|
||||
@@ -393,7 +401,12 @@ async fn list_tasks(
|
||||
) -> Result<Json<WorkerTaskListResponse>, StatusCode> {
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
let store = TaskListStore::current().map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let tasks = store.list(false).map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
let tasks = store
|
||||
.list(false)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
Ok(Json(WorkerTaskListResponse {
|
||||
task_list_id: store.task_list_id().to_string(),
|
||||
tasks,
|
||||
@@ -409,10 +422,12 @@ async fn get_task(
|
||||
let task = TaskListStore::current()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.get(&task_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
let runtime_task = RuntimeTaskStore::new()
|
||||
.get(&task_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
if task.is_none() && runtime_task.is_none() {
|
||||
return Err(StatusCode::NOT_FOUND);
|
||||
}
|
||||
@@ -440,7 +455,8 @@ async fn get_team(
|
||||
let task_list_id = current_task_list_id().unwrap_or_else(|_| state.config.profile_id.clone());
|
||||
let team = TeamStore::new()
|
||||
.current_team()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerTeamSnapshotResponse { team, task_list_id }))
|
||||
}
|
||||
|
||||
@@ -454,6 +470,7 @@ async fn list_agents(
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.into_iter()
|
||||
.filter(|task| task.kind == RuntimeTaskKind::Agent)
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
Ok(Json(WorkerAgentListResponse { agents }))
|
||||
}
|
||||
@@ -468,7 +485,7 @@ async fn list_apps(
|
||||
.list_apps_with_warnings()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
Ok(Json(WorkerAppListResponse {
|
||||
apps,
|
||||
apps: apps.into_iter().map(Into::into).collect(),
|
||||
state_root: store.state_root_display().ok(),
|
||||
warnings,
|
||||
}))
|
||||
@@ -483,7 +500,8 @@ async fn get_app(
|
||||
let store = ArtifactLibraryStore::new();
|
||||
let app = store
|
||||
.get_app(&app_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerAppSnapshotResponse {
|
||||
app,
|
||||
state_root: store.state_root_display().ok(),
|
||||
@@ -499,7 +517,7 @@ async fn get_app_version(
|
||||
let version = ArtifactLibraryStore::new()
|
||||
.get_app(&app_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(|app| app.current_version);
|
||||
.map(|app| LibraryAppVersionRecord::from(app.current_version));
|
||||
Ok(Json(WorkerAppVersionResponse { version }))
|
||||
}
|
||||
|
||||
@@ -511,7 +529,8 @@ async fn get_app_history(
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
let history = ArtifactLibraryStore::new()
|
||||
.app_history(&app_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerAppHistoryResponse { history }))
|
||||
}
|
||||
|
||||
@@ -524,7 +543,8 @@ async fn launch_app(
|
||||
let store = ArtifactLibraryStore::new();
|
||||
let app = store
|
||||
.mark_app_launched(&app_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerAppSnapshotResponse {
|
||||
app,
|
||||
state_root: store.state_root_display().ok(),
|
||||
@@ -539,7 +559,8 @@ async fn open_app_workspace(
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
let workspace = ArtifactLibraryStore::new()
|
||||
.open_workspace(&app_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerAppWorkspaceResponse { workspace }))
|
||||
}
|
||||
|
||||
@@ -551,9 +572,11 @@ async fn publish_app_workspace(
|
||||
) -> Result<Json<WorkerAppPublishResponse>, StatusCode> {
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
let result = ArtifactLibraryStore::new()
|
||||
.publish_workspace(&app_id, request)
|
||||
.publish_workspace(&app_id, request.into())
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
Ok(Json(WorkerAppPublishResponse { result }))
|
||||
Ok(Json(WorkerAppPublishResponse {
|
||||
result: result.map(Into::into),
|
||||
}))
|
||||
}
|
||||
|
||||
async fn archive_app(
|
||||
@@ -580,7 +603,8 @@ async fn get_app_workspace_status(
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
let workspace = ArtifactLibraryStore::new()
|
||||
.workspace_status(&app_id)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.map(Into::into);
|
||||
Ok(Json(WorkerAppWorkspaceResponse { workspace }))
|
||||
}
|
||||
|
||||
@@ -628,7 +652,7 @@ async fn get_agent(
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.filter(|task| task.kind == RuntimeTaskKind::Agent)
|
||||
.ok_or(StatusCode::NOT_FOUND)?;
|
||||
Ok(Json(task))
|
||||
Ok(Json(task.into()))
|
||||
}
|
||||
|
||||
async fn mark_agent_notified(
|
||||
@@ -652,7 +676,10 @@ async fn list_background_approvals(
|
||||
authorize(&headers, &state.config.auth_token)?;
|
||||
let approvals = BackgroundApprovalStore::new()
|
||||
.list_pending()
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.into_iter()
|
||||
.map(BackgroundApprovalRecord::from)
|
||||
.collect();
|
||||
Ok(Json(WorkerBackgroundApprovalListResponse { approvals }))
|
||||
}
|
||||
|
||||
@@ -710,8 +737,9 @@ async fn get_mailbox(
|
||||
{
|
||||
Some(team) => TeamStore::new()
|
||||
.mailbox_summary(&team.team_name, 20)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
None => runtime::MailboxSummary {
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.into(),
|
||||
None => MailboxSummary {
|
||||
team_name: None,
|
||||
recent_messages: Vec::new(),
|
||||
},
|
||||
@@ -731,7 +759,10 @@ async fn get_pending_mailbox_messages(
|
||||
{
|
||||
Some(team) => TeamStore::new()
|
||||
.pending_messages(&team.team_name, &recipient, 20)
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?,
|
||||
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
|
||||
.into_iter()
|
||||
.map(MailboxMessage::from)
|
||||
.collect(),
|
||||
None => Vec::new(),
|
||||
};
|
||||
Ok(Json(WorkerMailboxPendingResponse { messages }))
|
||||
@@ -1291,7 +1322,7 @@ fn derive_task_created_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
let task = store.get(task_id).ok()??;
|
||||
Some(WorkerTurnEvent::TaskCreated {
|
||||
task_list_id: store.task_list_id().to_string(),
|
||||
task,
|
||||
task: task.into(),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1301,14 +1332,14 @@ fn derive_task_updated_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
let task = store.get(task_id).ok()??;
|
||||
Some(WorkerTurnEvent::TaskUpdated {
|
||||
task_list_id: store.task_list_id().to_string(),
|
||||
task,
|
||||
task: task.into(),
|
||||
})
|
||||
}
|
||||
|
||||
fn derive_task_stopped_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
let task_id = value.get("task_id")?.as_str()?;
|
||||
let task = RuntimeTaskStore::new().get(task_id).ok()??;
|
||||
Some(WorkerTurnEvent::TaskStopped { task })
|
||||
Some(WorkerTurnEvent::TaskStopped { task: task.into() })
|
||||
}
|
||||
|
||||
fn derive_agent_spawned_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
@@ -1317,7 +1348,7 @@ fn derive_agent_spawned_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
.and_then(Value::as_str)
|
||||
.or_else(|| value.get("agentId").and_then(Value::as_str))?;
|
||||
let task = RuntimeTaskStore::new().get(task_id).ok()??;
|
||||
Some(WorkerTurnEvent::AgentSpawned { agent: task })
|
||||
Some(WorkerTurnEvent::AgentSpawned { agent: task.into() })
|
||||
}
|
||||
|
||||
fn derive_team_created_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
@@ -1331,7 +1362,7 @@ fn derive_team_created_event(value: &Value) -> Option<WorkerTurnEvent> {
|
||||
.and_then(Value::as_str)
|
||||
.unwrap_or_default()
|
||||
.to_string(),
|
||||
team,
|
||||
team: team.into(),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,13 +5,14 @@ use std::sync::Arc;
|
||||
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
||||
|
||||
use channel_gateway_core::{
|
||||
AttachmentKind, AttachmentRef, GatewayManifest, GatewaySettings, ManifestError, ProfileId,
|
||||
ProfileRecord, TurnSource, WorkerAgentListResponse, WorkerApprovalDecision,
|
||||
AttachmentKind, AttachmentRef, BackgroundApprovalRecord, GatewayManifest, GatewaySettings,
|
||||
MailboxMessage, ManifestError, ProfileId, ProfileRecord, RuntimeTaskRecord,
|
||||
RuntimeTaskStatus, TaskListRecord, TurnSource, WorkerAgentListResponse,
|
||||
WorkerApprovalDecision,
|
||||
WorkerBackgroundApprovalListResponse, WorkerDefaults, WorkerMailboxMessageEvent,
|
||||
WorkerMailboxSummaryResponse, WorkerTaskListResponse, WorkerTaskSnapshotResponse,
|
||||
WorkerTeamCreatedEvent, WorkerTeamSnapshotResponse, WorkerTurnEvent,
|
||||
};
|
||||
use runtime::{BackgroundApprovalRecord, MailboxMessage, RuntimeTaskRecord};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::config::GatewayConfig;
|
||||
@@ -1625,10 +1626,10 @@ fn render_agent_snapshot(agent: &RuntimeTaskRecord) -> String {
|
||||
|
||||
fn render_background_agent_terminal_notice(agent: &RuntimeTaskRecord) -> String {
|
||||
let title = match agent.status {
|
||||
runtime::RuntimeTaskStatus::Completed => "Background agent completed",
|
||||
runtime::RuntimeTaskStatus::Failed => "Background agent failed",
|
||||
runtime::RuntimeTaskStatus::Stopped => "Background agent stopped",
|
||||
runtime::RuntimeTaskStatus::Running => "Background agent update",
|
||||
RuntimeTaskStatus::Completed => "Background agent completed",
|
||||
RuntimeTaskStatus::Failed => "Background agent failed",
|
||||
RuntimeTaskStatus::Stopped => "Background agent stopped",
|
||||
RuntimeTaskStatus::Running => "Background agent update",
|
||||
};
|
||||
let mut lines = vec![
|
||||
title.to_string(),
|
||||
@@ -1716,14 +1717,14 @@ fn render_runtime_task(label: &str, task: &RuntimeTaskRecord) -> String {
|
||||
)
|
||||
}
|
||||
|
||||
fn render_task_created_notice(task_list_id: &str, task: &runtime::TaskListRecord) -> String {
|
||||
fn render_task_created_notice(task_list_id: &str, task: &TaskListRecord) -> String {
|
||||
format!(
|
||||
"Task created\nTask list: {}\n{} [{}] {}",
|
||||
task_list_id, task.id, task.status, task.subject
|
||||
)
|
||||
}
|
||||
|
||||
fn render_task_updated_notice(task_list_id: &str, task: &runtime::TaskListRecord) -> String {
|
||||
fn render_task_updated_notice(task_list_id: &str, task: &TaskListRecord) -> String {
|
||||
format!(
|
||||
"Task updated\nTask list: {}\n{} [{}] {}",
|
||||
task_list_id, task.id, task.status, task.subject
|
||||
|
||||
@@ -3,16 +3,15 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use base64::Engine as _;
|
||||
use channel_gateway_core::{
|
||||
AttachmentRef, GeneratedFileDescriptor, TurnSource, WorkerAgentListResponse,
|
||||
WorkerAppHistoryResponse, WorkerAppListResponse, WorkerAppPackageResponse,
|
||||
WorkerAppPublishResponse, WorkerAppSnapshotResponse, WorkerAppVersionResponse,
|
||||
WorkerAppWorkspaceResponse,
|
||||
AppPackageRequest, AppPublishRequest, AttachmentRef, GeneratedFileDescriptor,
|
||||
RuntimeTaskRecord, TurnSource, WorkerAgentListResponse, WorkerAppHistoryResponse,
|
||||
WorkerAppListResponse, WorkerAppPackageResponse, WorkerAppPublishResponse,
|
||||
WorkerAppSnapshotResponse, WorkerAppVersionResponse, WorkerAppWorkspaceResponse,
|
||||
WorkerApprovalDecision, WorkerBackgroundApprovalListResponse, WorkerMailboxSummaryResponse,
|
||||
WorkerFeedItemResponse, WorkerFeedListResponse, WorkerMailboxPendingResponse,
|
||||
WorkerStatusResponse, WorkerTaskListResponse, WorkerTaskSnapshotResponse,
|
||||
WorkerTeamSnapshotResponse, WorkerTurnAccepted, WorkerTurnEvent, WorkerTurnRequest,
|
||||
};
|
||||
use runtime::{AppPackageRequest, AppPublishRequest, RuntimeTaskRecord};
|
||||
use futures_util::StreamExt;
|
||||
use serde::Serialize;
|
||||
use tokio::sync::mpsc;
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Worker Protocol
|
||||
|
||||
This directory is the contract boundary between the Rust gateway in
|
||||
[`/Users/makarnovozhilov/clawdcode/claw-code-parity`](/Users/makarnovozhilov/clawdcode/claw-code-parity)
|
||||
and the future TypeScript worker forked from
|
||||
[`/Users/makarnovozhilov/clawdcode/claude-code-source`](/Users/makarnovozhilov/clawdcode/claude-code-source).
|
||||
|
||||
The migration goal is:
|
||||
|
||||
- keep the current gateway HTTP/SSE client stable
|
||||
- move worker ownership out of Rust runtime internals
|
||||
- make the worker contract language-neutral
|
||||
|
||||
Current state:
|
||||
|
||||
- `openapi.yaml` is the contract authority for the worker surface the gateway
|
||||
already calls
|
||||
- `schemas/` contains standalone JSON Schemas for the most important request
|
||||
and event payloads used by the migration slice
|
||||
- Rust protocol code is being migrated to use protocol-owned record mirrors
|
||||
instead of importing runtime structs directly
|
||||
|
||||
Notes:
|
||||
|
||||
- The contract is intentionally endpoint-compatible with the current gateway.
|
||||
- Some domain records are still broad `object` shapes in the OpenAPI file while
|
||||
the TS worker port is in progress.
|
||||
- The next tightening step is to generate TS/Rust bindings from this directory
|
||||
instead of hand-maintaining parallel definitions.
|
||||
@@ -0,0 +1,953 @@
|
||||
openapi: 3.1.0
|
||||
info:
|
||||
title: Claw Worker Protocol
|
||||
version: 0.1.0
|
||||
description: >
|
||||
Language-neutral HTTP/SSE contract between the Rust gateway and the worker
|
||||
process. This is the migration boundary for the Rust gateway plus
|
||||
TypeScript worker architecture.
|
||||
servers:
|
||||
- url: http://worker
|
||||
paths:
|
||||
/healthz:
|
||||
get:
|
||||
operationId: healthz
|
||||
responses:
|
||||
"200":
|
||||
description: Worker is healthy
|
||||
/v1/status:
|
||||
get:
|
||||
operationId: getStatus
|
||||
responses:
|
||||
"200":
|
||||
description: Session status
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerStatusResponse"
|
||||
/v1/session/reset:
|
||||
post:
|
||||
operationId: resetSession
|
||||
responses:
|
||||
"204":
|
||||
description: Session reset
|
||||
/v1/turns:
|
||||
post:
|
||||
operationId: submitTurn
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerTurnRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: Turn accepted
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerTurnAccepted"
|
||||
/v1/turns/{turn_id}/events:
|
||||
get:
|
||||
operationId: streamTurnEvents
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TurnId"
|
||||
responses:
|
||||
"200":
|
||||
description: SSE stream of worker turn events
|
||||
content:
|
||||
text/event-stream:
|
||||
schema:
|
||||
type: string
|
||||
/v1/turns/{turn_id}/approval:
|
||||
post:
|
||||
operationId: resolveTurnApproval
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TurnId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/TurnApprovalRequest"
|
||||
responses:
|
||||
"204":
|
||||
description: Approval applied
|
||||
/v1/turns/{turn_id}/cancel:
|
||||
post:
|
||||
operationId: cancelTurn
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TurnId"
|
||||
responses:
|
||||
"204":
|
||||
description: Turn cancelled
|
||||
/v1/turns/{turn_id}/files/{file_id}:
|
||||
get:
|
||||
operationId: fetchGeneratedFile
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TurnId"
|
||||
- $ref: "#/components/parameters/FileId"
|
||||
responses:
|
||||
"200":
|
||||
description: Generated file bytes
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
/v1/tasks:
|
||||
get:
|
||||
operationId: listTasks
|
||||
responses:
|
||||
"200":
|
||||
description: Task list snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerTaskListResponse"
|
||||
/v1/tasks/{task_id}:
|
||||
get:
|
||||
operationId: getTask
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TaskId"
|
||||
responses:
|
||||
"200":
|
||||
description: Task snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerTaskSnapshotResponse"
|
||||
/v1/tasks/{task_id}/stop:
|
||||
post:
|
||||
operationId: stopTask
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/TaskId"
|
||||
responses:
|
||||
"204":
|
||||
description: Task stop requested
|
||||
/v1/team:
|
||||
get:
|
||||
operationId: getTeam
|
||||
responses:
|
||||
"200":
|
||||
description: Team snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerTeamSnapshotResponse"
|
||||
/v1/agents:
|
||||
get:
|
||||
operationId: listAgents
|
||||
responses:
|
||||
"200":
|
||||
description: Agent runtime list
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAgentListResponse"
|
||||
/v1/agents/{agent_id}:
|
||||
get:
|
||||
operationId: getAgent
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AgentId"
|
||||
responses:
|
||||
"200":
|
||||
description: Agent runtime snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/RuntimeTaskRecord"
|
||||
/v1/background-approvals:
|
||||
get:
|
||||
operationId: listBackgroundApprovals
|
||||
responses:
|
||||
"200":
|
||||
description: Background approvals
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerBackgroundApprovalListResponse"
|
||||
/v1/background-approvals/{approval_id}:
|
||||
post:
|
||||
operationId: resolveBackgroundApproval
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ApprovalId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/TurnApprovalRequest"
|
||||
responses:
|
||||
"204":
|
||||
description: Background approval applied
|
||||
/v1/background-approvals/{approval_id}/notified:
|
||||
post:
|
||||
operationId: markBackgroundApprovalNotified
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/ApprovalId"
|
||||
responses:
|
||||
"204":
|
||||
description: Background approval notification acknowledged
|
||||
/v1/mailbox:
|
||||
get:
|
||||
operationId: getMailbox
|
||||
responses:
|
||||
"200":
|
||||
description: Mailbox summary
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerMailboxSummaryResponse"
|
||||
/v1/mailbox/pending/{recipient}:
|
||||
get:
|
||||
operationId: getPendingMailboxMessages
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Recipient"
|
||||
responses:
|
||||
"200":
|
||||
description: Pending mailbox messages
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerMailboxPendingResponse"
|
||||
/v1/feed:
|
||||
get:
|
||||
operationId: listFeed
|
||||
parameters:
|
||||
- in: query
|
||||
name: turn_id
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: Feed items
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerFeedListResponse"
|
||||
/v1/feed/{feed_item_id}:
|
||||
get:
|
||||
operationId: getFeedItem
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/FeedItemId"
|
||||
responses:
|
||||
"200":
|
||||
description: Feed item snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerFeedItemResponse"
|
||||
/v1/feed/{feed_item_id}/file:
|
||||
get:
|
||||
operationId: fetchFeedFile
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/FeedItemId"
|
||||
responses:
|
||||
"200":
|
||||
description: Feed payload bytes
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
/v1/feed/{feed_item_id}/make-app:
|
||||
post:
|
||||
operationId: packageFeedItem
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/FeedItemId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AppPackageRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: App create/update result
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppPackageResponse"
|
||||
/v1/apps:
|
||||
get:
|
||||
operationId: listApps
|
||||
responses:
|
||||
"200":
|
||||
description: Library apps
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppListResponse"
|
||||
/v1/apps/{app_id}:
|
||||
get:
|
||||
operationId: getApp
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"200":
|
||||
description: App snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppSnapshotResponse"
|
||||
/v1/apps/{app_id}/version:
|
||||
get:
|
||||
operationId: getAppVersion
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"200":
|
||||
description: App current version
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppVersionResponse"
|
||||
/v1/apps/{app_id}/history:
|
||||
get:
|
||||
operationId: getAppHistory
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"200":
|
||||
description: App publish history
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppHistoryResponse"
|
||||
/v1/apps/{app_id}/launch:
|
||||
post:
|
||||
operationId: launchApp
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"200":
|
||||
description: App launch side effect
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppSnapshotResponse"
|
||||
/v1/apps/{app_id}/open-workspace:
|
||||
post:
|
||||
operationId: openAppWorkspace
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"200":
|
||||
description: App workspace snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppWorkspaceResponse"
|
||||
/v1/apps/{app_id}/publish:
|
||||
post:
|
||||
operationId: publishAppWorkspace
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/AppPublishRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: App publish result
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppPublishResponse"
|
||||
/v1/apps/{app_id}/archive:
|
||||
post:
|
||||
operationId: archiveApp
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"204":
|
||||
description: App archived
|
||||
/v1/apps/{app_id}/worktree-status:
|
||||
get:
|
||||
operationId: getAppWorktreeStatus
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
responses:
|
||||
"200":
|
||||
description: App worktree snapshot
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/WorkerAppWorkspaceResponse"
|
||||
/v1/apps/{app_id}/files/{path}:
|
||||
get:
|
||||
operationId: fetchAppFile
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/AppId"
|
||||
- in: path
|
||||
name: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: App bundle file bytes
|
||||
content:
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
components:
|
||||
parameters:
|
||||
TurnId:
|
||||
in: path
|
||||
name: turn_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
TaskId:
|
||||
in: path
|
||||
name: task_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
AgentId:
|
||||
in: path
|
||||
name: agent_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
ApprovalId:
|
||||
in: path
|
||||
name: approval_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
Recipient:
|
||||
in: path
|
||||
name: recipient
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
FeedItemId:
|
||||
in: path
|
||||
name: feed_item_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
AppId:
|
||||
in: path
|
||||
name: app_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
FileId:
|
||||
in: path
|
||||
name: file_id
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
schemas:
|
||||
TurnSource:
|
||||
type: object
|
||||
required:
|
||||
- channel
|
||||
- sender_id
|
||||
properties:
|
||||
channel:
|
||||
type: string
|
||||
sender_id:
|
||||
type: string
|
||||
chat_id:
|
||||
type: string
|
||||
display_name:
|
||||
type: string
|
||||
InboundAttachment:
|
||||
type: object
|
||||
required:
|
||||
- file_name
|
||||
- kind
|
||||
- data_base64
|
||||
properties:
|
||||
file_name:
|
||||
type: string
|
||||
kind:
|
||||
type: string
|
||||
enum: [photo, document]
|
||||
media_type:
|
||||
type: string
|
||||
data_base64:
|
||||
type: string
|
||||
WorkerTurnRequest:
|
||||
type: object
|
||||
required:
|
||||
- prompt
|
||||
- source
|
||||
properties:
|
||||
prompt:
|
||||
type: string
|
||||
source:
|
||||
$ref: "#/components/schemas/TurnSource"
|
||||
attachments:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/InboundAttachment"
|
||||
WorkerTurnAccepted:
|
||||
type: object
|
||||
required: [turn_id]
|
||||
properties:
|
||||
turn_id:
|
||||
type: string
|
||||
ApprovalRequestPayload:
|
||||
type: object
|
||||
required:
|
||||
- approval_id
|
||||
- tool_name
|
||||
- input
|
||||
- current_mode
|
||||
- required_mode
|
||||
properties:
|
||||
approval_id:
|
||||
type: string
|
||||
tool_name:
|
||||
type: string
|
||||
input:
|
||||
type: string
|
||||
current_mode:
|
||||
type: string
|
||||
required_mode:
|
||||
type: string
|
||||
reason:
|
||||
type: string
|
||||
WorkerApprovalDecision:
|
||||
oneOf:
|
||||
- type: object
|
||||
required: [decision]
|
||||
properties:
|
||||
decision:
|
||||
type: string
|
||||
enum:
|
||||
- approve_once
|
||||
- approve_tool_for_session
|
||||
- approve_all_for_session
|
||||
- cancel_turn
|
||||
- type: object
|
||||
required: [decision, reason]
|
||||
properties:
|
||||
decision:
|
||||
type: string
|
||||
enum: [deny]
|
||||
reason:
|
||||
type: string
|
||||
TurnApprovalRequest:
|
||||
type: object
|
||||
required:
|
||||
- approval_id
|
||||
- decision
|
||||
properties:
|
||||
approval_id:
|
||||
type: string
|
||||
decision:
|
||||
$ref: "#/components/schemas/WorkerApprovalDecision"
|
||||
GeneratedFileDescriptor:
|
||||
type: object
|
||||
required:
|
||||
- file_id
|
||||
- file_name
|
||||
- size_bytes
|
||||
- is_image
|
||||
properties:
|
||||
file_id:
|
||||
type: string
|
||||
file_name:
|
||||
type: string
|
||||
media_type:
|
||||
type: string
|
||||
size_bytes:
|
||||
type: integer
|
||||
minimum: 0
|
||||
is_image:
|
||||
type: boolean
|
||||
TaskListRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
RuntimeTaskRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
TeamRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
MailboxMessage:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
MailboxSummary:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
BackgroundApprovalRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
FeedItemRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
LibraryAppRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
LibraryAppVersionRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
AppPackageRequest:
|
||||
type: object
|
||||
required: [feed_item_id]
|
||||
properties:
|
||||
feed_item_id:
|
||||
type: string
|
||||
requested_app_id:
|
||||
type: string
|
||||
title:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
AppPublishRequest:
|
||||
type: object
|
||||
required: [message]
|
||||
properties:
|
||||
message:
|
||||
type: string
|
||||
AppPackageResult:
|
||||
type: object
|
||||
required: [app, created]
|
||||
properties:
|
||||
app:
|
||||
$ref: "#/components/schemas/LibraryAppRecord"
|
||||
created:
|
||||
type: boolean
|
||||
AppWorkspaceRecord:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
AppPublishResult:
|
||||
type: object
|
||||
required: [app, workspace]
|
||||
properties:
|
||||
app:
|
||||
$ref: "#/components/schemas/LibraryAppRecord"
|
||||
workspace:
|
||||
$ref: "#/components/schemas/AppWorkspaceRecord"
|
||||
AppHistoryResponse:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
WorkerStatusResponse:
|
||||
type: object
|
||||
required:
|
||||
- profile_id
|
||||
- message_count
|
||||
- model
|
||||
- permission_mode
|
||||
- default_cwd
|
||||
- busy
|
||||
- task_list_id
|
||||
properties:
|
||||
profile_id:
|
||||
type: string
|
||||
message_count:
|
||||
type: integer
|
||||
minimum: 0
|
||||
model:
|
||||
type: string
|
||||
permission_mode:
|
||||
type: string
|
||||
default_cwd:
|
||||
type: string
|
||||
busy:
|
||||
type: boolean
|
||||
task_list_id:
|
||||
type: string
|
||||
active_team:
|
||||
type: string
|
||||
WorkerTaskListResponse:
|
||||
type: object
|
||||
required: [task_list_id, tasks]
|
||||
properties:
|
||||
task_list_id:
|
||||
type: string
|
||||
tasks:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/TaskListRecord"
|
||||
WorkerTaskSnapshotResponse:
|
||||
type: object
|
||||
properties:
|
||||
task:
|
||||
$ref: "#/components/schemas/TaskListRecord"
|
||||
runtime_task:
|
||||
$ref: "#/components/schemas/RuntimeTaskRecord"
|
||||
WorkerTeamSnapshotResponse:
|
||||
type: object
|
||||
required: [task_list_id]
|
||||
properties:
|
||||
team:
|
||||
$ref: "#/components/schemas/TeamRecord"
|
||||
task_list_id:
|
||||
type: string
|
||||
WorkerAgentListResponse:
|
||||
type: object
|
||||
required: [agents]
|
||||
properties:
|
||||
agents:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/RuntimeTaskRecord"
|
||||
WorkerMailboxSummaryResponse:
|
||||
type: object
|
||||
required: [mailbox]
|
||||
properties:
|
||||
mailbox:
|
||||
$ref: "#/components/schemas/MailboxSummary"
|
||||
WorkerMailboxPendingResponse:
|
||||
type: object
|
||||
required: [messages]
|
||||
properties:
|
||||
messages:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/MailboxMessage"
|
||||
WorkerBackgroundApprovalListResponse:
|
||||
type: object
|
||||
required: [approvals]
|
||||
properties:
|
||||
approvals:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/BackgroundApprovalRecord"
|
||||
WorkerFeedListResponse:
|
||||
type: object
|
||||
required: [items]
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/FeedItemRecord"
|
||||
state_root:
|
||||
type: string
|
||||
warnings:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
WorkerFeedItemResponse:
|
||||
type: object
|
||||
properties:
|
||||
item:
|
||||
$ref: "#/components/schemas/FeedItemRecord"
|
||||
state_root:
|
||||
type: string
|
||||
WorkerAppListResponse:
|
||||
type: object
|
||||
required: [apps]
|
||||
properties:
|
||||
apps:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/LibraryAppRecord"
|
||||
state_root:
|
||||
type: string
|
||||
warnings:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
WorkerAppSnapshotResponse:
|
||||
type: object
|
||||
properties:
|
||||
app:
|
||||
$ref: "#/components/schemas/LibraryAppRecord"
|
||||
state_root:
|
||||
type: string
|
||||
WorkerAppVersionResponse:
|
||||
type: object
|
||||
properties:
|
||||
version:
|
||||
$ref: "#/components/schemas/LibraryAppVersionRecord"
|
||||
WorkerAppPackageResponse:
|
||||
type: object
|
||||
properties:
|
||||
result:
|
||||
$ref: "#/components/schemas/AppPackageResult"
|
||||
WorkerAppWorkspaceResponse:
|
||||
type: object
|
||||
properties:
|
||||
workspace:
|
||||
$ref: "#/components/schemas/AppWorkspaceRecord"
|
||||
WorkerAppPublishResponse:
|
||||
type: object
|
||||
properties:
|
||||
result:
|
||||
$ref: "#/components/schemas/AppPublishResult"
|
||||
WorkerAppHistoryResponse:
|
||||
type: object
|
||||
properties:
|
||||
history:
|
||||
$ref: "#/components/schemas/AppHistoryResponse"
|
||||
WorkerTeamCreatedEvent:
|
||||
type: object
|
||||
required:
|
||||
- team
|
||||
- task_list_id
|
||||
- team_file_path
|
||||
properties:
|
||||
team:
|
||||
$ref: "#/components/schemas/TeamRecord"
|
||||
task_list_id:
|
||||
type: string
|
||||
team_file_path:
|
||||
type: string
|
||||
WorkerMailboxMessageEvent:
|
||||
type: object
|
||||
required:
|
||||
- team_name
|
||||
- sender
|
||||
- count
|
||||
properties:
|
||||
team_name:
|
||||
type: string
|
||||
sender:
|
||||
type: string
|
||||
count:
|
||||
type: integer
|
||||
minimum: 0
|
||||
recipients:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
summary:
|
||||
type: string
|
||||
WorkerTurnEvent:
|
||||
oneOf:
|
||||
- type: object
|
||||
required: [type, delta]
|
||||
properties:
|
||||
type:
|
||||
const: assistant_text_delta
|
||||
delta:
|
||||
type: string
|
||||
- type: object
|
||||
required: [type, id, name, input]
|
||||
properties:
|
||||
type:
|
||||
const: tool_use
|
||||
id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
input:
|
||||
type: string
|
||||
- type: object
|
||||
required: [type, tool_use_id, tool_name, output, is_error]
|
||||
properties:
|
||||
type:
|
||||
const: tool_result
|
||||
tool_use_id:
|
||||
type: string
|
||||
tool_name:
|
||||
type: string
|
||||
output:
|
||||
type: string
|
||||
is_error:
|
||||
type: boolean
|
||||
- type: object
|
||||
required: [type, request]
|
||||
properties:
|
||||
type:
|
||||
const: approval_requested
|
||||
request:
|
||||
$ref: "#/components/schemas/ApprovalRequestPayload"
|
||||
- type: object
|
||||
required: [type, removed_message_count]
|
||||
properties:
|
||||
type:
|
||||
const: auto_compaction
|
||||
removed_message_count:
|
||||
type: integer
|
||||
minimum: 0
|
||||
- type: object
|
||||
required: [type, task_list_id, task]
|
||||
properties:
|
||||
type:
|
||||
const: task_created
|
||||
task_list_id:
|
||||
type: string
|
||||
task:
|
||||
$ref: "#/components/schemas/TaskListRecord"
|
||||
- type: object
|
||||
required: [type, task_list_id, task]
|
||||
properties:
|
||||
type:
|
||||
const: task_updated
|
||||
task_list_id:
|
||||
type: string
|
||||
task:
|
||||
$ref: "#/components/schemas/TaskListRecord"
|
||||
- type: object
|
||||
required: [type, task]
|
||||
properties:
|
||||
type:
|
||||
const: task_stopped
|
||||
task:
|
||||
$ref: "#/components/schemas/RuntimeTaskRecord"
|
||||
- type: object
|
||||
required: [type, agent]
|
||||
properties:
|
||||
type:
|
||||
const: agent_spawned
|
||||
agent:
|
||||
$ref: "#/components/schemas/RuntimeTaskRecord"
|
||||
- type: object
|
||||
required: [type, team]
|
||||
properties:
|
||||
type:
|
||||
const: team_created
|
||||
team:
|
||||
$ref: "#/components/schemas/WorkerTeamCreatedEvent"
|
||||
- type: object
|
||||
required: [type, team_name]
|
||||
properties:
|
||||
type:
|
||||
const: team_deleted
|
||||
team_name:
|
||||
type: string
|
||||
- type: object
|
||||
required: [type, message]
|
||||
properties:
|
||||
type:
|
||||
const: mailbox_message
|
||||
message:
|
||||
$ref: "#/components/schemas/WorkerMailboxMessageEvent"
|
||||
- type: object
|
||||
required:
|
||||
- type
|
||||
- final_text
|
||||
- iterations
|
||||
- input_tokens
|
||||
- output_tokens
|
||||
- generated_files
|
||||
properties:
|
||||
type:
|
||||
const: completed
|
||||
final_text:
|
||||
type: string
|
||||
iterations:
|
||||
type: integer
|
||||
minimum: 0
|
||||
input_tokens:
|
||||
type: integer
|
||||
minimum: 0
|
||||
output_tokens:
|
||||
type: integer
|
||||
minimum: 0
|
||||
generated_files:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/GeneratedFileDescriptor"
|
||||
- type: object
|
||||
required: [type, message]
|
||||
properties:
|
||||
type:
|
||||
const: failed
|
||||
message:
|
||||
type: string
|
||||
@@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://claw.local/worker-protocol/schemas/worker-approval-decision.schema.json",
|
||||
"title": "WorkerApprovalDecision",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["decision"],
|
||||
"properties": {
|
||||
"decision": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"approve_once",
|
||||
"approve_tool_for_session",
|
||||
"approve_all_for_session",
|
||||
"cancel_turn"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["decision", "reason"],
|
||||
"properties": {
|
||||
"decision": {
|
||||
"type": "string",
|
||||
"enum": ["deny"]
|
||||
},
|
||||
"reason": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://claw.local/worker-protocol/schemas/worker-turn-event.schema.json",
|
||||
"title": "WorkerTurnEvent",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["type", "delta"],
|
||||
"properties": {
|
||||
"type": { "const": "assistant_text_delta" },
|
||||
"delta": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["type", "id", "name", "input"],
|
||||
"properties": {
|
||||
"type": { "const": "tool_use" },
|
||||
"id": { "type": "string" },
|
||||
"name": { "type": "string" },
|
||||
"input": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["type", "tool_use_id", "tool_name", "output", "is_error"],
|
||||
"properties": {
|
||||
"type": { "const": "tool_result" },
|
||||
"tool_use_id": { "type": "string" },
|
||||
"tool_name": { "type": "string" },
|
||||
"output": { "type": "string" },
|
||||
"is_error": { "type": "boolean" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["type", "request"],
|
||||
"properties": {
|
||||
"type": { "const": "approval_requested" },
|
||||
"request": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"approval_id",
|
||||
"tool_name",
|
||||
"input",
|
||||
"current_mode",
|
||||
"required_mode"
|
||||
],
|
||||
"properties": {
|
||||
"approval_id": { "type": "string" },
|
||||
"tool_name": { "type": "string" },
|
||||
"input": { "type": "string" },
|
||||
"current_mode": { "type": "string" },
|
||||
"required_mode": { "type": "string" },
|
||||
"reason": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": [
|
||||
"type",
|
||||
"final_text",
|
||||
"iterations",
|
||||
"input_tokens",
|
||||
"output_tokens",
|
||||
"generated_files"
|
||||
],
|
||||
"properties": {
|
||||
"type": { "const": "completed" },
|
||||
"final_text": { "type": "string" },
|
||||
"iterations": { "type": "integer", "minimum": 0 },
|
||||
"input_tokens": { "type": "integer", "minimum": 0 },
|
||||
"output_tokens": { "type": "integer", "minimum": 0 },
|
||||
"generated_files": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["file_id", "file_name", "size_bytes", "is_image"],
|
||||
"properties": {
|
||||
"file_id": { "type": "string" },
|
||||
"file_name": { "type": "string" },
|
||||
"media_type": { "type": "string" },
|
||||
"size_bytes": { "type": "integer", "minimum": 0 },
|
||||
"is_image": { "type": "boolean" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"required": ["type", "message"],
|
||||
"properties": {
|
||||
"type": { "const": "failed" },
|
||||
"message": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$id": "https://claw.local/worker-protocol/schemas/worker-turn-request.schema.json",
|
||||
"title": "WorkerTurnRequest",
|
||||
"type": "object",
|
||||
"required": ["prompt", "source"],
|
||||
"properties": {
|
||||
"prompt": {
|
||||
"type": "string"
|
||||
},
|
||||
"source": {
|
||||
"type": "object",
|
||||
"required": ["channel", "sender_id"],
|
||||
"properties": {
|
||||
"channel": { "type": "string" },
|
||||
"sender_id": { "type": "string" },
|
||||
"chat_id": { "type": "string" },
|
||||
"display_name": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
},
|
||||
"attachments": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["file_name", "kind", "data_base64"],
|
||||
"properties": {
|
||||
"file_name": { "type": "string" },
|
||||
"kind": { "type": "string", "enum": ["photo", "document"] },
|
||||
"media_type": { "type": "string" },
|
||||
"data_base64": { "type": "string" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user