///|
pub(all) enum CommunicationKind {
MessageEvent
Handoff
Broadcast
ReviewRequest
Approval
ToolResult
RecoveryNotice
} derive(Debug, Eq)
///|
pub struct Thread {
id : String
title : String
owner_actor_id : String
subject_ref : String
status : RunStatus
} derive(Debug, Eq)
///|
pub struct Communication {
id : String
thread_id : String
kind : CommunicationKind
from_actor_id : String
to_actor_id : String
text : String
artifact_ref : String
timestamp : String
status : RunStatus
open_message : String
} derive(Debug, Eq)
///|
pub fn thread(
id~ : String,
title~ : String,
owner_actor_id~ : String,
subject_ref? : String = "",
status? : RunStatus = Running,
) -> Thread {
{ id, title, owner_actor_id, subject_ref, status }
}
///|
pub fn communication(
id~ : String,
thread_id~ : String,
kind~ : CommunicationKind,
from_actor_id~ : String,
to_actor_id? : String = "",
text~ : String,
artifact_ref? : String = "",
timestamp? : String = "",
status? : RunStatus = Done,
open_message? : String = "",
) -> Communication {
{
id,
thread_id,
kind,
from_actor_id,
to_actor_id,
text,
artifact_ref,
timestamp,
status,
open_message,
}
}
///|
pub fn message_event(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
text~ : String,
artifact_ref? : String = "",
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=MessageEvent,
from_actor_id~,
text~,
artifact_ref~,
open_message~,
)
}
///|
pub fn handoff(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
to_actor_id~ : String,
text~ : String,
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=Handoff,
from_actor_id~,
to_actor_id~,
text~,
open_message~,
)
}
///|
pub fn broadcast(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
text~ : String,
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=Broadcast,
from_actor_id~,
text~,
open_message~,
)
}
///|
pub fn review_request(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
to_actor_id~ : String,
text~ : String,
artifact_ref? : String = "",
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=ReviewRequest,
from_actor_id~,
to_actor_id~,
text~,
artifact_ref~,
status=WaitingReview,
open_message~,
)
}
///|
pub fn approval(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
to_actor_id~ : String,
text~ : String,
artifact_ref? : String = "",
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=Approval,
from_actor_id~,
to_actor_id~,
text~,
artifact_ref~,
status=Done,
open_message~,
)
}
///|
pub fn tool_result(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
text~ : String,
artifact_ref~ : String,
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=ToolResult,
from_actor_id~,
text~,
artifact_ref~,
open_message~,
)
}
///|
pub fn recovery_notice(
id~ : String,
thread_id~ : String,
from_actor_id~ : String,
text~ : String,
open_message? : String = "",
) -> Communication {
communication(
id~,
thread_id~,
kind=RecoveryNotice,
from_actor_id~,
text~,
status=Failed,
open_message~,
)
}
///|
pub fn communication_kind_id(kind : CommunicationKind) -> String {
match kind {
MessageEvent => "message"
Handoff => "handoff"
Broadcast => "broadcast"
ReviewRequest => "review-request"
Approval => "approval"
ToolResult => "tool-result"
RecoveryNotice => "recovery-notice"
}
}
///|
pub fn thread_card(input : Thread) -> @core.Node {
@core.keyed(
input.id,
@core.view_with_attrs(
[
@core.class_name("bunnia-thread \{run_status_class(input.status)}"),
@core.data("thread-id", input.id),
@core.data("owner-actor-id", input.owner_actor_id),
@core.data("subject-ref", input.subject_ref),
@core.data("run-status", run_status_id(input.status)),
],
[@core.text(input.title), subject_badge(input.subject_ref)],
),
)
}
///|
pub fn communication_row(input : Communication) -> @core.Node {
let events = if input.open_message == "" {
[]
} else {
[@core.tap(input.open_message)]
}
@core.keyed(
input.id,
@core.node(
kind="view",
attrs=[
@core.class_name(
"bunnia-communication bunnia-communication-\{communication_kind_id(input.kind)} \{run_status_class(input.status)}",
),
@core.data("communication-id", input.id),
@core.data("thread-id", input.thread_id),
@core.data("communication-kind", communication_kind_id(input.kind)),
@core.data("from-actor-id", input.from_actor_id),
@core.data("to-actor-id", input.to_actor_id),
@core.data("artifact-ref", input.artifact_ref),
@core.data("timestamp", input.timestamp),
@core.data("run-status", run_status_id(input.status)),
],
events~,
children=[@core.text(input.text), artifact_badge(input.artifact_ref)],
),
)
}
///|
pub fn communication_trace(items : Array[Communication]) -> @core.Node {
let rows : Array[@core.Node] = []
for item in items {
rows.push(communication_row(item))
}
@core.view_with_attrs([@core.class_name("bunnia-communication-trace")], rows)
}
///|
pub fn windowed_communication_trace(
items : Array[Communication],
total_count~ : Int,
offset? : Int = 0,
) -> @core.Node {
let rows : Array[@core.Node] = []
for item in items {
rows.push(communication_row(item))
}
@core.node(
kind="view",
attrs=[
@core.class_name(
"bunnia-communication-trace bunnia-communication-trace-windowed",
),
@core.data("bunnia-list-mode", "windowed"),
@core.data("total-count", total_count.to_string()),
@core.data("visible-start", offset.to_string()),
@core.data("visible-count", items.length().to_string()),
],
children=rows,
list_total_count=total_count,
list_visible_count=items.length(),
)
}
///|
fn subject_badge(subject_ref : String) -> @core.Node {
if subject_ref == "" {
@core.view([])
} else {
@core.view_with_attrs(
[
@core.class_name("bunnia-subject-link"),
@core.data("subject-ref", subject_ref),
],
[@core.text("subject")],
)
}
}