1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
//! The harness-integration seam: the [`AgentHarness`] trait an integrator implements and the
//! live [`AgentSession`] it produces.
//!
//! This is the SDK's published extension seam, mirroring `aion-client`'s `WorkflowTransport`
//! (a dedicated `#[async_trait]` contract module). It is **harness-blind by construction**: no
//! signature names a concrete harness, a transport, or a wire protocol. A harness is integrated
//! by implementing these traits in a separate adapter crate; the seam speaks only neutral run
//! identity, the neutral [`ActivityEvent`] / [`InterventionCommand`] types, the neutral
//! [`InterventionCapabilities`] advertisement, and a neutral terminal [`Payload`].
//!
//! # Designed from two cases so it is provably general
//!
//! The seam is designed against two deliberately different integrations at once, so it cannot be
//! shaped by any one harness:
//!
//! - a full rich-path harness (a bidirectional channel, streamed events out, acknowledged
//! commands in, a structured terminal result), and
//! - a plain-stdout, **observability-only** CLI agent (no command channel at all): it demuxes
//! interleaved stdout into [`ActivityEvent`]s (mostly [`aion_core::ActivityEventKind::Raw`]),
//! advertises an **empty** [`InterventionCapabilities`] set, and yields its final output as the
//! result.
//!
//! The empty-capability case is what forces [`AgentSession::intervene`] to be
//! optional-by-capability: an empty advertisement is a valid, first-class tier, and a session
//! that advertises it rejects every command with [`HarnessError::CapabilityNotSupported`].
use ;
use async_trait;
use BoxStream;
use crateHarnessError;
use crateAgentRunSpec;
/// How to run one agent harness — the SDK's published extension seam.
///
/// An integrator implements this (in a separate adapter crate) to teach Aion how to spawn or
/// connect their harness for a single activity attempt. It is harness-blind: [`Self::start`]
/// takes only the neutral [`AgentRunSpec`] and returns a live [`AgentSession`].
/// A live agent run for one activity attempt.
///
/// Produced by [`AgentHarness::start`]. Exposes the negotiated capability set, a stream of
/// neutral events OUT, a neutral command sink IN, and a single terminal result.
/// An object-safe erased [`AgentSession`], so a worker can drive a session behind a
/// `Box<dyn ..>` without being generic over the concrete harness.
///
/// It mirrors [`AgentSession`] exactly EXCEPT that the terminal [`Self::wait_result`]
/// takes `self: Box<Self>` (rather than `self` by value), which is what makes the
/// trait object-safe — an owned-`self` method is not dispatchable through `dyn`. A
/// blanket impl over every [`AgentSession`] means an integrator implements only the
/// ergonomic typed trait and gets the erased form for free.
///
/// The async methods are `?Send`-dispatched. [`AgentSession`] is `Send` but not
/// `Sync`, so a `&session` cannot cross threads; the worker holds an erased session
/// inside ONE task and drives it (plus its event drain) there — never `tokio::spawn`-ing
/// a borrow of it — so requiring `Sync` would over-constrain every adapter for no gain.
/// An object-safe erased [`AgentHarness`], so a worker can HOLD a harness behind a
/// `Arc<dyn DynAgentHarness>` (the typed [`AgentHarness`] is not object-safe — it has
/// an associated `Session` type).
///
/// A blanket impl over every [`AgentHarness`] erases the session type into a
/// `Box<dyn DynAgentSession>`, so a composition root passes any typed harness and the
/// worker drives it without naming the concrete type.