Merge branch 'feature/117-opencode-headless-recovery' into develop
This commit is contained in:
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::conversation::ConversationId;
|
||||
use crate::ids::{AgentId, ProjectId, ScheduleId, TaskId};
|
||||
use crate::ids::{AgentId, ProjectId, RendezvousId, ScheduleId, TaskId};
|
||||
use crate::mailbox::TicketId;
|
||||
|
||||
/// Maximum length for human-facing task labels.
|
||||
@ -59,6 +59,22 @@ pub enum BackgroundTaskWakePolicy {
|
||||
RecordOnly,
|
||||
}
|
||||
|
||||
/// Structural link from a background task to a composite inter-agent rendezvous.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct BackgroundTaskRendezvousLink {
|
||||
/// Stable business rendezvous id, independent from any task id.
|
||||
pub rendezvous_id: RendezvousId,
|
||||
/// Mailbox ticket that must receive the eventual business `Final`.
|
||||
pub ticket_id: TicketId,
|
||||
/// Agent that requested the rendezvous, when known.
|
||||
pub requester_agent_id: Option<AgentId>,
|
||||
/// Target agent doing the work.
|
||||
pub target_agent_id: AgentId,
|
||||
/// Conversation entered by the target turn.
|
||||
pub conversation_id: ConversationId,
|
||||
}
|
||||
|
||||
/// Kind-specific payload of a background task.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase", tag = "kind")]
|
||||
@ -107,6 +123,9 @@ pub struct BackgroundTask {
|
||||
pub owner_agent_id: AgentId,
|
||||
/// Kind-specific payload.
|
||||
pub kind: BackgroundTaskKind,
|
||||
/// Optional composite rendezvous this task participates in.
|
||||
#[serde(default)]
|
||||
pub rendezvous: Option<BackgroundTaskRendezvousLink>,
|
||||
/// Current lifecycle state.
|
||||
pub state: BackgroundTaskState,
|
||||
/// Completion wake policy.
|
||||
@ -143,6 +162,7 @@ impl BackgroundTask {
|
||||
project_id,
|
||||
owner_agent_id,
|
||||
kind,
|
||||
rendezvous: None,
|
||||
state: BackgroundTaskState::Queued,
|
||||
wake_policy,
|
||||
created_at_ms: now_ms,
|
||||
@ -155,6 +175,13 @@ impl BackgroundTask {
|
||||
Ok(task)
|
||||
}
|
||||
|
||||
/// Returns a copy linked to a composite inter-agent rendezvous.
|
||||
#[must_use]
|
||||
pub fn with_rendezvous(mut self, link: BackgroundTaskRendezvousLink) -> Self {
|
||||
self.rendezvous = Some(link);
|
||||
self
|
||||
}
|
||||
|
||||
/// Returns a copy moved to a non-terminal state.
|
||||
///
|
||||
/// Terminal transitions must use [`Self::complete`] so the result/state
|
||||
|
||||
@ -115,6 +115,10 @@ typed_id!(
|
||||
/// Identifies a first-class background task.
|
||||
TaskId
|
||||
);
|
||||
typed_id!(
|
||||
/// Identifies one composite inter-agent business rendezvous.
|
||||
RendezvousId
|
||||
);
|
||||
|
||||
/// Runtime-only key for an agent scoped by its project.
|
||||
///
|
||||
|
||||
@ -79,8 +79,8 @@ pub use error::DomainError;
|
||||
pub use events::RendezvousContext;
|
||||
|
||||
pub use ids::{
|
||||
AgentId, IssueId, LayoutId, LocalModelServerId, NodeId, ProfileId, ProjectId, RuntimeAgentKey,
|
||||
ScheduleId, SessionId, SkillId, SprintId, TabId, TaskId, TemplateId, WindowId,
|
||||
AgentId, IssueId, LayoutId, LocalModelServerId, NodeId, ProfileId, ProjectId, RendezvousId,
|
||||
RuntimeAgentKey, ScheduleId, SessionId, SkillId, SprintId, TabId, TaskId, TemplateId, WindowId,
|
||||
};
|
||||
|
||||
pub use project::{Project, ProjectPath};
|
||||
@ -95,9 +95,10 @@ pub use mcp_tool_permissions::{
|
||||
};
|
||||
|
||||
pub use background_task::{
|
||||
BackgroundTask, BackgroundTaskError, BackgroundTaskKind, BackgroundTaskResult,
|
||||
BackgroundTaskState, BackgroundTaskWakePolicy, BACKGROUND_TASK_LABEL_MAX_CHARS,
|
||||
BACKGROUND_TASK_OUTPUT_TAIL_MAX_BYTES, BACKGROUND_TASK_TEXT_MAX_BYTES,
|
||||
BackgroundTask, BackgroundTaskError, BackgroundTaskKind, BackgroundTaskRendezvousLink,
|
||||
BackgroundTaskResult, BackgroundTaskState, BackgroundTaskWakePolicy,
|
||||
BACKGROUND_TASK_LABEL_MAX_CHARS, BACKGROUND_TASK_OUTPUT_TAIL_MAX_BYTES,
|
||||
BACKGROUND_TASK_TEXT_MAX_BYTES,
|
||||
};
|
||||
|
||||
pub use skill::{Skill, SkillRef, SkillScope};
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
//! Pure invariants for first-class background tasks.
|
||||
|
||||
use domain::{
|
||||
BackgroundTask, BackgroundTaskError, BackgroundTaskKind, BackgroundTaskResult,
|
||||
BackgroundTaskState, BackgroundTaskWakePolicy,
|
||||
BackgroundTask, BackgroundTaskError, BackgroundTaskKind, BackgroundTaskRendezvousLink,
|
||||
BackgroundTaskResult, BackgroundTaskState, BackgroundTaskWakePolicy, ConversationId,
|
||||
RendezvousId, TicketId,
|
||||
};
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -43,6 +44,23 @@ fn success_result(at: u64) -> BackgroundTaskResult {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rendezvous_link_roundtrips_on_background_task() {
|
||||
let link = BackgroundTaskRendezvousLink {
|
||||
rendezvous_id: RendezvousId::from_uuid(Uuid::from_u128(9)),
|
||||
ticket_id: TicketId::from_uuid(Uuid::from_u128(10)),
|
||||
requester_agent_id: Some(agent_id(4)),
|
||||
target_agent_id: agent_id(3),
|
||||
conversation_id: ConversationId::from_uuid(Uuid::from_u128(11)),
|
||||
};
|
||||
let task = command_task().with_rendezvous(link.clone());
|
||||
|
||||
let json = serde_json::to_string(&task).unwrap();
|
||||
let decoded: BackgroundTask = serde_json::from_str(&json).unwrap();
|
||||
|
||||
assert_eq!(decoded.rendezvous, Some(link));
|
||||
}
|
||||
|
||||
fn failure_result(at: u64) -> BackgroundTaskResult {
|
||||
BackgroundTaskResult::Failure {
|
||||
finished_at_ms: at,
|
||||
|
||||
Reference in New Issue
Block a user