@robota-sdk/agent-interface-execution 3.0.0-beta.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +661 -0
- package/README.md +23 -0
- package/dist/node/index.cjs +0 -0
- package/dist/node/index.d.cts +585 -0
- package/dist/node/index.d.cts.map +1 -0
- package/dist/node/index.d.ts +585 -0
- package/dist/node/index.d.ts.map +1 -0
- package/dist/node/index.js +1 -0
- package/package.json +70 -0
|
File without changes
|
|
@@ -0,0 +1,585 @@
|
|
|
1
|
+
import { IHistoryEntry, ITokenUsage, TBackgroundPermissionPolicy, TModelEffort, TUniversalValue } from "@robota-sdk/agent-core";
|
|
2
|
+
//#region src/background-task-contracts.d.ts
|
|
3
|
+
type TBackgroundTaskKind = 'agent' | 'process' | 'scheduled' | 'tool-invocation';
|
|
4
|
+
type TBackgroundTaskMode = 'foreground' | 'background';
|
|
5
|
+
type TBackgroundTaskIsolation = 'none' | 'worktree';
|
|
6
|
+
type TBackgroundTaskStatus = 'queued' | 'running' | 'waiting_permission' | 'sleeping' | 'paused' | 'completed' | 'failed' | 'cancelled';
|
|
7
|
+
type TBackgroundTaskTimeoutReason = 'idle' | 'max_runtime' | 'output_limit' | 'repetition' | 'stale_worker';
|
|
8
|
+
type TBackgroundTaskErrorCategory = 'validation' | 'capacity' | 'permission' | 'timeout' | 'runner' | 'crash' | 'provider' | 'process';
|
|
9
|
+
type TBackgroundPrimitive = string | number | boolean;
|
|
10
|
+
interface IBackgroundTaskError {
|
|
11
|
+
category: TBackgroundTaskErrorCategory;
|
|
12
|
+
message: string;
|
|
13
|
+
recoverable: boolean;
|
|
14
|
+
}
|
|
15
|
+
interface ISerializableProviderProfile {
|
|
16
|
+
profileName?: string;
|
|
17
|
+
type: string;
|
|
18
|
+
model: string;
|
|
19
|
+
apiKey?: string;
|
|
20
|
+
apiKeyEnv?: string;
|
|
21
|
+
baseURL?: string;
|
|
22
|
+
timeout?: number;
|
|
23
|
+
options?: Record<string, TUniversalValue>;
|
|
24
|
+
}
|
|
25
|
+
interface IBaseBackgroundTaskRequest {
|
|
26
|
+
kind: TBackgroundTaskKind;
|
|
27
|
+
label: string;
|
|
28
|
+
mode: TBackgroundTaskMode;
|
|
29
|
+
parentSessionId: string;
|
|
30
|
+
parentTaskId?: string;
|
|
31
|
+
depth: number;
|
|
32
|
+
cwd: string;
|
|
33
|
+
timeoutMs?: number;
|
|
34
|
+
idleTimeoutMs?: number;
|
|
35
|
+
maxRuntimeMs?: number;
|
|
36
|
+
metadata?: Record<string, TBackgroundPrimitive>;
|
|
37
|
+
}
|
|
38
|
+
interface IAgentBackgroundTaskRequest extends IBaseBackgroundTaskRequest {
|
|
39
|
+
kind: 'agent';
|
|
40
|
+
agentType: string;
|
|
41
|
+
prompt: string;
|
|
42
|
+
model?: string;
|
|
43
|
+
effort?: TModelEffort;
|
|
44
|
+
isolation?: TBackgroundTaskIsolation;
|
|
45
|
+
/**
|
|
46
|
+
* CLI-1994: the persisted session record the child RESTORES before its first turn — a fork of the
|
|
47
|
+
* parent conversation written under a fresh id by `/fork`. Only the id crosses: the conversation
|
|
48
|
+
* itself never rides on the request, so the child-process wire stays as narrow as ARCH-044 left it
|
|
49
|
+
* (the child reads the record from the session store, exactly as `--fork-session` does). Absent ⇒
|
|
50
|
+
* the child starts with an empty conversation, unchanged.
|
|
51
|
+
*/
|
|
52
|
+
resumeSessionId?: string;
|
|
53
|
+
allowedTools?: string[];
|
|
54
|
+
disallowedTools?: string[];
|
|
55
|
+
permissionPolicy: TBackgroundPermissionPolicy;
|
|
56
|
+
providerProfile?: ISerializableProviderProfile;
|
|
57
|
+
outputLimitBytes?: number;
|
|
58
|
+
maxTextDeltas?: number;
|
|
59
|
+
repetitionWindow?: number;
|
|
60
|
+
repetitionThreshold?: number;
|
|
61
|
+
}
|
|
62
|
+
interface IProcessBackgroundTaskRequest extends IBaseBackgroundTaskRequest {
|
|
63
|
+
kind: 'process';
|
|
64
|
+
command: string;
|
|
65
|
+
shell?: string;
|
|
66
|
+
env?: Record<string, string>;
|
|
67
|
+
stdin?: string;
|
|
68
|
+
outputLimitBytes?: number;
|
|
69
|
+
/**
|
|
70
|
+
* FLOW-004 (monitor): a regular-expression source. Output lines matching it fire a
|
|
71
|
+
* `background_task_waking` carrying `agentInstruction` + the matched line, so the agent
|
|
72
|
+
* reacts to "something happened in this process's output".
|
|
73
|
+
*/
|
|
74
|
+
matchPattern?: string;
|
|
75
|
+
/** FLOW-004: the instruction injected on a monitor match (paired with `matchPattern`). */
|
|
76
|
+
agentInstruction?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* A scheduled task carries NO `permissionPolicy`, by decision (issue #2354).
|
|
80
|
+
*
|
|
81
|
+
* A `kind: 'agent'` task spawns a SEPARATE agent, so it declares its own policy and CORE-025
|
|
82
|
+
* enforces it. A schedule with `agentInstruction` does not spawn anything: it WAKES the host
|
|
83
|
+
* session (`background_task_waking` → `requestWakeup` → an `agent-wakeup` turn), and that turn runs
|
|
84
|
+
* under the host session's own permission configuration — mode, allow/deny rules, hooks, session
|
|
85
|
+
* consent — exactly as a turn the user typed would. Inheritance is the contract, not an omission:
|
|
86
|
+
* a policy field here would either duplicate the session's or silently disagree with it. The
|
|
87
|
+
* `contracts.test.ts` type assertion fails if one is added without that wiring being designed.
|
|
88
|
+
*/
|
|
89
|
+
interface IScheduledBackgroundTaskRequest extends IBaseBackgroundTaskRequest {
|
|
90
|
+
kind: 'scheduled';
|
|
91
|
+
cronExpression: string;
|
|
92
|
+
/**
|
|
93
|
+
* Shell command to run on each fire. Optional when `agentInstruction` is set —
|
|
94
|
+
* an agent-wake schedule may fire the agent loop instead of (or in addition to) a shell command.
|
|
95
|
+
*/
|
|
96
|
+
command?: string;
|
|
97
|
+
/**
|
|
98
|
+
* FLOW-001: when set, each fire carries this instruction on the `background_task_waking`
|
|
99
|
+
* event so an upper layer (FLOW-002) can wake the agent loop with a non-user turn.
|
|
100
|
+
*/
|
|
101
|
+
agentInstruction?: string;
|
|
102
|
+
shell?: string;
|
|
103
|
+
env?: Record<string, string>;
|
|
104
|
+
outputLimitBytes?: number;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* MCP-004 §S1: an in-flight MCP tool call handed off to the background-task manager. Data only —
|
|
108
|
+
* the naming split is deliberate: the KIND is `'tool-invocation'` (INFRA-025's closed vocabulary
|
|
109
|
+
* names the thing that runs), while the feature, its files and its tests keep the name "tool-call
|
|
110
|
+
* handoff" (what a user does with it). Provenance is flattened into primitive fields rather than a
|
|
111
|
+
* nested object so the request stays data-only and the executor helpers can project the same
|
|
112
|
+
* fields into `metadata` for `/tasks` to read (agent-executor, not this package, owns that
|
|
113
|
+
* projection). The remaining budget rides the base request's `maxRuntimeMs` — no dedicated field.
|
|
114
|
+
*/
|
|
115
|
+
interface IToolInvocationBackgroundTaskRequest extends IBaseBackgroundTaskRequest {
|
|
116
|
+
kind: 'tool-invocation';
|
|
117
|
+
toolName: string;
|
|
118
|
+
/** Looked up by the runner's adoption registry (`agent-executor`) to find the already-running call. */
|
|
119
|
+
adoptionToken: string;
|
|
120
|
+
/** MCP-004 provenance: the only owner today. A closed union of one, matching the request's origin. */
|
|
121
|
+
provenanceOwner: 'mcp';
|
|
122
|
+
serverId: string;
|
|
123
|
+
sourceName: string;
|
|
124
|
+
securityIdentity?: string;
|
|
125
|
+
/** Provenance metadata for `/tasks` and the notification — not an enforcement carrier (§ Decision). */
|
|
126
|
+
permissionMode: string;
|
|
127
|
+
}
|
|
128
|
+
type TBackgroundTaskRequest = IAgentBackgroundTaskRequest | IProcessBackgroundTaskRequest | IScheduledBackgroundTaskRequest | IToolInvocationBackgroundTaskRequest;
|
|
129
|
+
/**
|
|
130
|
+
* ANALYTICS-001 (Phase 2): token usage a completed task/subagent consumed, for source attribution.
|
|
131
|
+
* TYPE-003: alias of the `agent-core` usage-triple SSOT (`ITokenUsage`) — derived, not re-declared.
|
|
132
|
+
*/
|
|
133
|
+
type IBackgroundTaskUsage = ITokenUsage;
|
|
134
|
+
interface IBaseBackgroundTaskResult {
|
|
135
|
+
taskId: string;
|
|
136
|
+
output: string;
|
|
137
|
+
metadata?: Record<string, TBackgroundPrimitive>;
|
|
138
|
+
}
|
|
139
|
+
interface IAgentBackgroundTaskResult extends IBaseBackgroundTaskResult {
|
|
140
|
+
kind: 'agent';
|
|
141
|
+
/** ANALYTICS-001 (Phase 2): total token usage of an agent task, attributed to it in the parent log. */
|
|
142
|
+
usage?: IBackgroundTaskUsage;
|
|
143
|
+
}
|
|
144
|
+
interface IProcessBackgroundTaskResult extends IBaseBackgroundTaskResult {
|
|
145
|
+
kind: 'process';
|
|
146
|
+
exitCode?: number;
|
|
147
|
+
signalCode?: string;
|
|
148
|
+
}
|
|
149
|
+
interface IScheduledBackgroundTaskResult extends IBaseBackgroundTaskResult {
|
|
150
|
+
kind: 'scheduled';
|
|
151
|
+
}
|
|
152
|
+
interface IToolInvocationBackgroundTaskResult extends IBaseBackgroundTaskResult {
|
|
153
|
+
kind: 'tool-invocation';
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* #2079: the outcome hop discriminates by kind exactly as the request hop
|
|
157
|
+
* (`TBackgroundTaskRequest`) does — `exitCode`/`signalCode` are producible only by the process
|
|
158
|
+
* runner and `usage` only by the agent runner (`ISubagentJobResult` is now
|
|
159
|
+
* `Omit<IBackgroundTaskResult<'agent'>, 'kind'>`, not a hand-maintained `Omit` off the flat shape).
|
|
160
|
+
* `IBackgroundTaskResult<K>` narrows to the kind-specific member for a caller that knows `K`
|
|
161
|
+
* statically (a runner's `start()`, the decoder once it has
|
|
162
|
+
* checked `kind`); called with no type argument it stays the full union. `IBackgroundTaskState<K>`
|
|
163
|
+
* is discriminated the same way, and its `result` field is `IBackgroundTaskResult<K>` — correlated
|
|
164
|
+
* with `state.kind`, not the free-standing full union.
|
|
165
|
+
*/
|
|
166
|
+
type TBackgroundTaskResult = IAgentBackgroundTaskResult | IProcessBackgroundTaskResult | IScheduledBackgroundTaskResult | IToolInvocationBackgroundTaskResult;
|
|
167
|
+
type IBackgroundTaskResult<K extends TBackgroundTaskKind = TBackgroundTaskKind> = Extract<TBackgroundTaskResult, {
|
|
168
|
+
kind: K;
|
|
169
|
+
}>;
|
|
170
|
+
/**
|
|
171
|
+
* #2079: the persisted/live state hop discriminates by kind exactly as the request and result hops
|
|
172
|
+
* do. Fields a single runner alone can produce — `agentType`/`isolation`/`resumeSessionId`/
|
|
173
|
+
* `promptPreview`/the worktree-isolation fields (agent), `schedule`/`nextFireAt` (scheduled) — live
|
|
174
|
+
* only on that kind's member. `commandPreview` is produced by every runner except the agent one (a
|
|
175
|
+
* process command, a tool-invocation summary, or a schedule's shell command / wake instruction), so
|
|
176
|
+
* it stays on the three non-agent members, not the base. `pid`/`logPath`/`transcriptPath` stay on
|
|
177
|
+
* the shared base: the handle SPI (`IBackgroundTaskHandle`) already reports them generically for
|
|
178
|
+
* whichever runner's process happens to produce them, and a subagent run as a child process (the
|
|
179
|
+
* worktree-isolation runner) carries a `pid` exactly as a `process`-kind task does — an audit of
|
|
180
|
+
* every producer (`background-task-manager-helpers.ts`, `subagent-manager.ts`,
|
|
181
|
+
* `worktree-subagent-runner.ts`) found no case of an agent/process pid being kind-exclusive.
|
|
182
|
+
* `timeoutReason` is likewise base: `interactive-session-restore.ts` sets `'stale_worker'` on ANY
|
|
183
|
+
* non-terminal, non-rearmable task regardless of kind, not only on agent tasks.
|
|
184
|
+
*/
|
|
185
|
+
interface IBaseBackgroundTaskState<K extends TBackgroundTaskKind> {
|
|
186
|
+
id: string;
|
|
187
|
+
kind: K;
|
|
188
|
+
label: string;
|
|
189
|
+
status: TBackgroundTaskStatus;
|
|
190
|
+
mode: TBackgroundTaskMode;
|
|
191
|
+
parentSessionId: string;
|
|
192
|
+
parentTaskId?: string;
|
|
193
|
+
depth: number;
|
|
194
|
+
cwd: string;
|
|
195
|
+
pid?: number;
|
|
196
|
+
startedAt?: string;
|
|
197
|
+
updatedAt: string;
|
|
198
|
+
lastActivityAt?: string;
|
|
199
|
+
completedAt?: string;
|
|
200
|
+
currentAction?: string;
|
|
201
|
+
unread: boolean;
|
|
202
|
+
result?: IBackgroundTaskResult<K>;
|
|
203
|
+
error?: IBackgroundTaskError;
|
|
204
|
+
logPath?: string;
|
|
205
|
+
transcriptPath?: string;
|
|
206
|
+
timeoutReason?: TBackgroundTaskTimeoutReason;
|
|
207
|
+
metadata?: Record<string, TBackgroundPrimitive>;
|
|
208
|
+
}
|
|
209
|
+
interface IAgentBackgroundTaskState extends IBaseBackgroundTaskState<'agent'> {
|
|
210
|
+
agentType?: string;
|
|
211
|
+
promptPreview?: string;
|
|
212
|
+
isolation?: TBackgroundTaskIsolation;
|
|
213
|
+
/**
|
|
214
|
+
* CLI-1994: carried from `IAgentBackgroundTaskRequest.resumeSessionId` so a surface can offer to
|
|
215
|
+
* ATTACH to the forked session — a view switch onto that record, never a merge with the parent.
|
|
216
|
+
*/
|
|
217
|
+
resumeSessionId?: string;
|
|
218
|
+
worktreePath?: string;
|
|
219
|
+
branchName?: string;
|
|
220
|
+
worktreeStatus?: string;
|
|
221
|
+
worktreeNextAction?: string;
|
|
222
|
+
worktreeBaseRevision?: string;
|
|
223
|
+
parentWorktreeStatus?: string;
|
|
224
|
+
}
|
|
225
|
+
interface IProcessBackgroundTaskState extends IBaseBackgroundTaskState<'process'> {
|
|
226
|
+
commandPreview?: string;
|
|
227
|
+
}
|
|
228
|
+
interface IScheduledBackgroundTaskState extends IBaseBackgroundTaskState<'scheduled'> {
|
|
229
|
+
commandPreview?: string;
|
|
230
|
+
nextFireAt?: string;
|
|
231
|
+
/**
|
|
232
|
+
* FLOW-003: for `kind: 'scheduled'` tasks, the reconstructable schedule definition.
|
|
233
|
+
* Persisted with the task so a resumed session can re-arm the croner job.
|
|
234
|
+
*/
|
|
235
|
+
schedule?: IBackgroundTaskSchedule;
|
|
236
|
+
}
|
|
237
|
+
interface IToolInvocationBackgroundTaskState extends IBaseBackgroundTaskState<'tool-invocation'> {
|
|
238
|
+
commandPreview?: string;
|
|
239
|
+
}
|
|
240
|
+
type TBackgroundTaskState = IAgentBackgroundTaskState | IProcessBackgroundTaskState | IScheduledBackgroundTaskState | IToolInvocationBackgroundTaskState;
|
|
241
|
+
type IBackgroundTaskState<K extends TBackgroundTaskKind = TBackgroundTaskKind> = Extract<TBackgroundTaskState, {
|
|
242
|
+
kind: K;
|
|
243
|
+
}>;
|
|
244
|
+
/** FLOW-003: the persisted, reconstructable definition of a scheduled wake. */
|
|
245
|
+
interface IBackgroundTaskSchedule {
|
|
246
|
+
cronExpression: string;
|
|
247
|
+
agentInstruction?: string;
|
|
248
|
+
command?: string;
|
|
249
|
+
shell?: string;
|
|
250
|
+
env?: Record<string, string>;
|
|
251
|
+
}
|
|
252
|
+
interface IBackgroundTaskInput {
|
|
253
|
+
prompt?: string;
|
|
254
|
+
stdin?: string;
|
|
255
|
+
}
|
|
256
|
+
interface IBackgroundTaskLogCursor {
|
|
257
|
+
offset: number;
|
|
258
|
+
}
|
|
259
|
+
interface IBackgroundTaskLogPage {
|
|
260
|
+
taskId: string;
|
|
261
|
+
cursor?: IBackgroundTaskLogCursor;
|
|
262
|
+
nextCursor?: IBackgroundTaskLogCursor;
|
|
263
|
+
lines: string[];
|
|
264
|
+
}
|
|
265
|
+
interface IBackgroundTaskListFilter {
|
|
266
|
+
kind?: TBackgroundTaskKind;
|
|
267
|
+
status?: TBackgroundTaskStatus;
|
|
268
|
+
mode?: TBackgroundTaskMode;
|
|
269
|
+
includeClosed?: boolean;
|
|
270
|
+
}
|
|
271
|
+
type TBackgroundTaskEvent = {
|
|
272
|
+
type: 'background_task_created';
|
|
273
|
+
task: IBackgroundTaskState;
|
|
274
|
+
} | {
|
|
275
|
+
type: 'background_task_started';
|
|
276
|
+
task: IBackgroundTaskState;
|
|
277
|
+
} | {
|
|
278
|
+
type: 'background_task_updated';
|
|
279
|
+
task: IBackgroundTaskState;
|
|
280
|
+
} | {
|
|
281
|
+
type: 'background_task_text_delta';
|
|
282
|
+
taskId: string;
|
|
283
|
+
delta: string;
|
|
284
|
+
} | {
|
|
285
|
+
type: 'background_task_tool_start';
|
|
286
|
+
taskId: string;
|
|
287
|
+
toolName: string;
|
|
288
|
+
firstArg?: string;
|
|
289
|
+
} | {
|
|
290
|
+
type: 'background_task_tool_end';
|
|
291
|
+
taskId: string;
|
|
292
|
+
toolName: string;
|
|
293
|
+
success: boolean;
|
|
294
|
+
error?: string;
|
|
295
|
+
} | {
|
|
296
|
+
type: 'background_task_permission_request';
|
|
297
|
+
taskId: string;
|
|
298
|
+
requestId: string;
|
|
299
|
+
toolName: string;
|
|
300
|
+
toolArgs: Record<string, TBackgroundPrimitive>;
|
|
301
|
+
} | {
|
|
302
|
+
type: 'background_task_completed';
|
|
303
|
+
task: IBackgroundTaskState;
|
|
304
|
+
} | {
|
|
305
|
+
type: 'background_task_failed';
|
|
306
|
+
task: IBackgroundTaskState;
|
|
307
|
+
} | {
|
|
308
|
+
type: 'background_task_cancelled';
|
|
309
|
+
task: IBackgroundTaskState;
|
|
310
|
+
} | {
|
|
311
|
+
type: 'background_task_closed';
|
|
312
|
+
taskId: string;
|
|
313
|
+
} | {
|
|
314
|
+
type: 'background_task_waking';
|
|
315
|
+
taskId: string;
|
|
316
|
+
instruction?: string;
|
|
317
|
+
};
|
|
318
|
+
type TBackgroundTaskEventListener = (event: TBackgroundTaskEvent) => void;
|
|
319
|
+
//#endregion
|
|
320
|
+
//#region src/background-group-contracts.d.ts
|
|
321
|
+
type TBackgroundJobWaitPolicy = 'detached' | 'wait_all' | 'wait_any' | 'manual';
|
|
322
|
+
type TBackgroundJobGroupStatus = 'running' | 'completed';
|
|
323
|
+
interface IBackgroundJobResultEnvelope {
|
|
324
|
+
taskId: string;
|
|
325
|
+
label: string;
|
|
326
|
+
status: TBackgroundTaskStatus;
|
|
327
|
+
summary?: string;
|
|
328
|
+
outputRef?: string;
|
|
329
|
+
error?: IBackgroundTaskError;
|
|
330
|
+
startedAt?: string;
|
|
331
|
+
completedAt?: string;
|
|
332
|
+
}
|
|
333
|
+
interface IBackgroundJobGroupState {
|
|
334
|
+
id: string;
|
|
335
|
+
parentSessionId: string;
|
|
336
|
+
waitPolicy: TBackgroundJobWaitPolicy;
|
|
337
|
+
taskIds: string[];
|
|
338
|
+
status: TBackgroundJobGroupStatus;
|
|
339
|
+
createdAt: string;
|
|
340
|
+
updatedAt: string;
|
|
341
|
+
label?: string;
|
|
342
|
+
completedAt?: string;
|
|
343
|
+
results: IBackgroundJobResultEnvelope[];
|
|
344
|
+
}
|
|
345
|
+
interface IBackgroundJobGroupSummary {
|
|
346
|
+
groupId: string;
|
|
347
|
+
status: TBackgroundJobGroupStatus;
|
|
348
|
+
total: number;
|
|
349
|
+
completed: number;
|
|
350
|
+
failed: number;
|
|
351
|
+
cancelled: number;
|
|
352
|
+
pending: number;
|
|
353
|
+
lines: string[];
|
|
354
|
+
}
|
|
355
|
+
interface IBackgroundJobGroupCreateRequest {
|
|
356
|
+
parentSessionId: string;
|
|
357
|
+
waitPolicy: TBackgroundJobWaitPolicy;
|
|
358
|
+
taskIds: string[];
|
|
359
|
+
label?: string;
|
|
360
|
+
}
|
|
361
|
+
type TBackgroundJobGroupEvent = {
|
|
362
|
+
type: 'background_job_group_created';
|
|
363
|
+
group: IBackgroundJobGroupState;
|
|
364
|
+
} | {
|
|
365
|
+
type: 'background_job_group_updated';
|
|
366
|
+
group: IBackgroundJobGroupState;
|
|
367
|
+
} | {
|
|
368
|
+
type: 'background_job_group_completed';
|
|
369
|
+
group: IBackgroundJobGroupState;
|
|
370
|
+
};
|
|
371
|
+
type TBackgroundJobGroupEventListener = (event: TBackgroundJobGroupEvent) => void;
|
|
372
|
+
type TBackgroundJobGroupIdFactory = (request: IBackgroundJobGroupCreateRequest) => string;
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/subagent-contracts.d.ts
|
|
375
|
+
/**
|
|
376
|
+
* TYPE-003: derived from the background-task status SSOT ({@link TBackgroundTaskStatus}) instead of
|
|
377
|
+
* a second hand-maintained union — a status added to the SSOT now flows here mechanically (the
|
|
378
|
+
* prior manual copy silently missed `paused` when SELFHOST-012 added it). `paused` is excluded on
|
|
379
|
+
* purpose: it is a scheduled-task-only status and a subagent is never a scheduled task
|
|
380
|
+
* (`SubagentManager.toSubagentState` maps it to `sleeping`).
|
|
381
|
+
*/
|
|
382
|
+
type TSubagentJobStatus = Exclude<TBackgroundTaskStatus, 'paused'>;
|
|
383
|
+
/** TYPE-003: alias of the background-task mode SSOT — the job mode is the same foreground/background pair. */
|
|
384
|
+
type TSubagentJobMode = TBackgroundTaskMode;
|
|
385
|
+
/**
|
|
386
|
+
* Subagent-job projection of {@link IBackgroundTaskState}.
|
|
387
|
+
*
|
|
388
|
+
* TYPE-003: every field a subagent job shares with the background-task SSOT is derived via `Pick`
|
|
389
|
+
* (previously a ~20-field manual mirror that could drift silently). Only the genuinely
|
|
390
|
+
* subagent-specific fields are declared here:
|
|
391
|
+
* - `type` — the agent-definition type (the task-side counterpart is the optional `agentType`);
|
|
392
|
+
* - `status` — the derived {@link TSubagentJobStatus} (no `paused`);
|
|
393
|
+
* - `promptPreview` — required here (every subagent job is created from a prompt; optional on tasks);
|
|
394
|
+
* - `currentTool` — the job-level projection of the task's free-form `currentAction`;
|
|
395
|
+
* - `result`/`error` — flattened display strings (the task carries structured
|
|
396
|
+
* `IBackgroundTaskResult`/`IBackgroundTaskError` objects).
|
|
397
|
+
*/
|
|
398
|
+
interface ISubagentJobState extends Pick<IBackgroundTaskState<'agent'>, 'id' | 'label' | 'parentSessionId' | 'mode' | 'depth' | 'pid' | 'cwd' | 'isolation' | 'resumeSessionId' | 'worktreePath' | 'branchName' | 'worktreeStatus' | 'worktreeNextAction' | 'worktreeBaseRevision' | 'parentWorktreeStatus' | 'logPath' | 'transcriptPath' | 'startedAt' | 'updatedAt' | 'completedAt' | 'timeoutReason' | 'metadata'> {
|
|
399
|
+
type: string;
|
|
400
|
+
status: TSubagentJobStatus;
|
|
401
|
+
promptPreview: string;
|
|
402
|
+
currentTool?: string;
|
|
403
|
+
result?: string;
|
|
404
|
+
error?: string;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* A subagent spawn request IS an agent background-task request (ARCH-031).
|
|
408
|
+
*
|
|
409
|
+
* `kind` is fixed by the seam — a subagent is never a process task — so omitting it both removes a
|
|
410
|
+
* field every caller would have to set identically and structurally prevents `kind: 'process'` from
|
|
411
|
+
* reaching `SubagentManager.spawn`. Everything else is carried by derivation rather than by a
|
|
412
|
+
* hand-written projection remembering it, which is the whole point: `parentTaskId` and
|
|
413
|
+
* `providerProfile` reach the runner because they exist on the source, not because someone recalled
|
|
414
|
+
* them.
|
|
415
|
+
*
|
|
416
|
+
* Nothing is added here. The worktree identity a runner produces (`worktreePath`, and formerly a
|
|
417
|
+
* write-only `branchName`) belongs on the runner envelope `ISubagentJobStart`, not on a request that
|
|
418
|
+
* models what the CALLER asked for.
|
|
419
|
+
*/
|
|
420
|
+
type ISubagentSpawnRequest = Omit<IAgentBackgroundTaskRequest, 'kind'>;
|
|
421
|
+
/**
|
|
422
|
+
* A subagent job result IS a background-task result, for the `'agent'` kind, minus the discriminant
|
|
423
|
+
* (ARCH-031, #2079). `kind` is fixed by the seam the same way `ISubagentSpawnRequest` fixes it on the
|
|
424
|
+
* request side — a subagent job is never a process/scheduled/tool-invocation task, so a caller of
|
|
425
|
+
* `ISubagentManager.wait` has no use for a field that can only ever read `'agent'` — so `wait()`
|
|
426
|
+
* strips it (`subagent-manager.ts`) rather than this alias ever carrying it.
|
|
427
|
+
*
|
|
428
|
+
* `IBackgroundTaskResult` is now discriminated by kind, so `IBackgroundTaskResult<'agent'>` is the
|
|
429
|
+
* exact agent-kind member: `exitCode`/`signalCode` (process-only; their sole producer is the shell
|
|
430
|
+
* runner, `agent-executor/src/background-tasks/runners/managed-shell-process-runner.ts`) are
|
|
431
|
+
* structurally absent rather than omitted by hand, and `usage` (agent-only) is carried without a
|
|
432
|
+
* separate key list to forget it from.
|
|
433
|
+
*
|
|
434
|
+
* `IBackgroundTaskState<'agent'>.result` is `IBackgroundTaskResult<'agent'>` too (#2079 discriminated
|
|
435
|
+
* the state hop the same way), so `state.kind === 'agent'` now narrows `state.result` there as well.
|
|
436
|
+
* This alias narrows at a seam where the kind is statically known instead — a subagent job never
|
|
437
|
+
* becomes a process task — which is why `ISubagentJobResult` exists as its own name rather than just
|
|
438
|
+
* reading `state.result` after a kind check everywhere a job result is needed.
|
|
439
|
+
*/
|
|
440
|
+
type ISubagentJobResult = Omit<IBackgroundTaskResult<'agent'>, 'kind'>;
|
|
441
|
+
//#endregion
|
|
442
|
+
//#region src/workspace-contracts.d.ts
|
|
443
|
+
type TExecutionEntryKind = 'main_thread' | 'background_task' | 'background_group';
|
|
444
|
+
type TExecutionWorkspaceStatus = 'active' | 'idle' | TBackgroundTaskStatus;
|
|
445
|
+
type TExecutionAttention = 'none' | 'unread' | 'failed' | 'permission' | 'completed';
|
|
446
|
+
type TExecutionWorkspaceVisibility = 'default' | 'collapsed';
|
|
447
|
+
/**
|
|
448
|
+
* `attach` (CLI-1994) is offered on a `background_task` entry whose request carried a
|
|
449
|
+
* `resumeSessionId` — a forked conversation. Selecting it is a VIEW SWITCH onto that session record,
|
|
450
|
+
* not a merge: the parent and the fork stay separate records.
|
|
451
|
+
*/
|
|
452
|
+
type TExecutionControl = 'select' | 'cancel' | 'close' | 'send' | 'read_log' | 'wait' | 'attach';
|
|
453
|
+
type TExecutionOriginKind = 'user_prompt' | 'slash_command' | 'model_command' | 'tool_call' | 'skill' | 'transport' | 'system';
|
|
454
|
+
type TExecutionDetailRecordKind = 'message' | 'tool_activity' | 'process_output' | 'progress' | 'result' | 'error' | 'group_summary';
|
|
455
|
+
type TExecutionWorkspaceUpdateCause = 'main_thread' | 'background_task' | 'background_group';
|
|
456
|
+
/**
|
|
457
|
+
* SCREEN-1992 — the five-word normalization every surface renders beside the detailed `status`:
|
|
458
|
+
* `working` (queued/running/sleeping/active), `needs-input` (a parked prompt or a task waiting for
|
|
459
|
+
* permission), `completed`, `failed`, `stopped` (cancelled or paused — never reported as completed).
|
|
460
|
+
* Total over every `TExecutionWorkspaceStatus`; derived once by the projection, never re-derived.
|
|
461
|
+
*/
|
|
462
|
+
type TExecutionNormalizedState = 'working' | 'needs-input' | 'completed' | 'failed' | 'stopped';
|
|
463
|
+
/** SCREEN-1992 — the row's one-line text: what it is doing, the question it is asking, or its result. */
|
|
464
|
+
type TExecutionHeadlineKind = 'activity' | 'question' | 'result';
|
|
465
|
+
interface IExecutionHeadline {
|
|
466
|
+
readonly kind: TExecutionHeadlineKind;
|
|
467
|
+
readonly text: string;
|
|
468
|
+
}
|
|
469
|
+
/** SCREEN-1992 — the prompt the main thread is parked on, so a surface can say what it is waiting for. */
|
|
470
|
+
interface IExecutionPendingRequest {
|
|
471
|
+
readonly kind: 'permission' | 'ask';
|
|
472
|
+
readonly text: string;
|
|
473
|
+
}
|
|
474
|
+
interface IExecutionOrigin {
|
|
475
|
+
readonly kind: TExecutionOriginKind;
|
|
476
|
+
readonly sessionId: string;
|
|
477
|
+
readonly turnId?: string;
|
|
478
|
+
readonly commandName?: string;
|
|
479
|
+
readonly toolCallId?: string;
|
|
480
|
+
readonly skillId?: string;
|
|
481
|
+
readonly label?: string;
|
|
482
|
+
}
|
|
483
|
+
interface IExecutionWorkspaceEntry {
|
|
484
|
+
readonly id: string;
|
|
485
|
+
readonly sourceId: string;
|
|
486
|
+
readonly kind: TExecutionEntryKind;
|
|
487
|
+
readonly parentId?: string;
|
|
488
|
+
readonly groupId?: string;
|
|
489
|
+
readonly origin: IExecutionOrigin;
|
|
490
|
+
readonly taskKind?: TBackgroundTaskKind;
|
|
491
|
+
readonly status: TExecutionWorkspaceStatus;
|
|
492
|
+
readonly title: string;
|
|
493
|
+
readonly subtitle?: string;
|
|
494
|
+
readonly preview?: string;
|
|
495
|
+
readonly currentAction?: string;
|
|
496
|
+
readonly unread: boolean;
|
|
497
|
+
readonly attention: TExecutionAttention;
|
|
498
|
+
readonly visibility: TExecutionWorkspaceVisibility;
|
|
499
|
+
readonly updatedAt: string;
|
|
500
|
+
readonly controls: readonly TExecutionControl[];
|
|
501
|
+
/** CLI-1994: the forked session record an `attach` control switches the view onto. */
|
|
502
|
+
readonly resumeSessionId?: string;
|
|
503
|
+
/** SCREEN-1992: the normalized state word (see `TExecutionNormalizedState`). */
|
|
504
|
+
readonly state: TExecutionNormalizedState;
|
|
505
|
+
/** SCREEN-1992: the row's one-line text SSOT; `preview` stays the raw last output. */
|
|
506
|
+
readonly headline?: IExecutionHeadline;
|
|
507
|
+
/** SCREEN-1992: ISO time of a sleeping schedule's next fire, for a surface-side countdown. */
|
|
508
|
+
readonly nextFireAt?: string;
|
|
509
|
+
}
|
|
510
|
+
interface IExecutionWorkspaceFilter {
|
|
511
|
+
readonly includeMainThread?: boolean;
|
|
512
|
+
readonly kinds?: readonly TExecutionEntryKind[];
|
|
513
|
+
readonly visibility?: readonly TExecutionWorkspaceVisibility[];
|
|
514
|
+
}
|
|
515
|
+
interface IExecutionWorkspaceSnapshot {
|
|
516
|
+
readonly sessionId: string;
|
|
517
|
+
readonly selectedEntryId?: string;
|
|
518
|
+
readonly updatedAt: string;
|
|
519
|
+
readonly entries: readonly IExecutionWorkspaceEntry[];
|
|
520
|
+
}
|
|
521
|
+
interface IExecutionWorkspaceSnapshotOptions {
|
|
522
|
+
readonly selectedEntryId?: string;
|
|
523
|
+
readonly filter?: IExecutionWorkspaceFilter;
|
|
524
|
+
}
|
|
525
|
+
interface IExecutionWorkspaceEvent {
|
|
526
|
+
readonly type: 'execution_workspace_updated';
|
|
527
|
+
readonly cause: TExecutionWorkspaceUpdateCause;
|
|
528
|
+
readonly entryId?: string;
|
|
529
|
+
readonly snapshot: IExecutionWorkspaceSnapshot;
|
|
530
|
+
}
|
|
531
|
+
interface IExecutionDetailCursor {
|
|
532
|
+
readonly offset: number;
|
|
533
|
+
}
|
|
534
|
+
interface IExecutionDetailRecord {
|
|
535
|
+
readonly id: string;
|
|
536
|
+
readonly kind: TExecutionDetailRecordKind;
|
|
537
|
+
readonly text: string;
|
|
538
|
+
readonly timestamp?: string;
|
|
539
|
+
readonly sourceId?: string;
|
|
540
|
+
}
|
|
541
|
+
interface IExecutionDetailPage {
|
|
542
|
+
readonly entryId: string;
|
|
543
|
+
readonly cursor?: IExecutionDetailCursor;
|
|
544
|
+
readonly nextCursor?: IExecutionDetailCursor;
|
|
545
|
+
readonly records: readonly IExecutionDetailRecord[];
|
|
546
|
+
}
|
|
547
|
+
interface ICreateMainThreadEntryInput {
|
|
548
|
+
readonly sessionId: string;
|
|
549
|
+
readonly isExecuting: boolean;
|
|
550
|
+
readonly hasPendingPrompt: boolean;
|
|
551
|
+
readonly historyLength: number;
|
|
552
|
+
readonly updatedAt: string;
|
|
553
|
+
readonly preview?: string;
|
|
554
|
+
/** SCREEN-1992: the parked permission/ask the main thread is waiting on, when there is one. */
|
|
555
|
+
readonly pendingRequest?: IExecutionPendingRequest;
|
|
556
|
+
}
|
|
557
|
+
interface ICreateExecutionWorkspaceSnapshotInput {
|
|
558
|
+
readonly sessionId: string;
|
|
559
|
+
readonly mainThread: ICreateMainThreadEntryInput;
|
|
560
|
+
readonly tasks: readonly IBackgroundTaskState[];
|
|
561
|
+
readonly groups: readonly IBackgroundJobGroupState[];
|
|
562
|
+
readonly selectedEntryId?: string;
|
|
563
|
+
readonly filter?: IExecutionWorkspaceFilter;
|
|
564
|
+
}
|
|
565
|
+
interface IExecutionWorkspaceEntryRef {
|
|
566
|
+
readonly kind: TExecutionEntryKind;
|
|
567
|
+
readonly sourceId: string;
|
|
568
|
+
}
|
|
569
|
+
interface ICreateMainThreadDetailPageInput {
|
|
570
|
+
readonly entryId: string;
|
|
571
|
+
readonly history: readonly IHistoryEntry[];
|
|
572
|
+
readonly cursor?: IExecutionDetailCursor;
|
|
573
|
+
/** SCREEN-1992: a parked prompt leads the page so a peek shows the blocking question first. */
|
|
574
|
+
readonly pendingRequest?: IExecutionPendingRequest;
|
|
575
|
+
}
|
|
576
|
+
interface ICreateLineDetailPageInput {
|
|
577
|
+
readonly entryId: string;
|
|
578
|
+
readonly lines: readonly string[];
|
|
579
|
+
readonly cursor?: IBackgroundTaskLogCursor;
|
|
580
|
+
readonly nextCursor?: IBackgroundTaskLogCursor;
|
|
581
|
+
readonly kind?: TExecutionDetailRecordKind;
|
|
582
|
+
}
|
|
583
|
+
//#endregion
|
|
584
|
+
export type { IAgentBackgroundTaskRequest, IAgentBackgroundTaskResult, IAgentBackgroundTaskState, IBackgroundJobGroupCreateRequest, IBackgroundJobGroupState, IBackgroundJobGroupSummary, IBackgroundJobResultEnvelope, IBackgroundTaskError, IBackgroundTaskInput, IBackgroundTaskListFilter, IBackgroundTaskLogCursor, IBackgroundTaskLogPage, IBackgroundTaskResult, IBackgroundTaskSchedule, IBackgroundTaskState, IBackgroundTaskUsage, IBaseBackgroundTaskRequest, ICreateExecutionWorkspaceSnapshotInput, ICreateLineDetailPageInput, ICreateMainThreadDetailPageInput, ICreateMainThreadEntryInput, IExecutionDetailCursor, IExecutionDetailPage, IExecutionDetailRecord, IExecutionHeadline, IExecutionOrigin, IExecutionPendingRequest, IExecutionWorkspaceEntry, IExecutionWorkspaceEntryRef, IExecutionWorkspaceEvent, IExecutionWorkspaceFilter, IExecutionWorkspaceSnapshot, IExecutionWorkspaceSnapshotOptions, IProcessBackgroundTaskRequest, IProcessBackgroundTaskResult, IProcessBackgroundTaskState, IScheduledBackgroundTaskRequest, IScheduledBackgroundTaskResult, IScheduledBackgroundTaskState, ISerializableProviderProfile, ISubagentJobResult, ISubagentJobState, ISubagentSpawnRequest, IToolInvocationBackgroundTaskRequest, IToolInvocationBackgroundTaskResult, IToolInvocationBackgroundTaskState, TBackgroundJobGroupEvent, TBackgroundJobGroupEventListener, TBackgroundJobGroupIdFactory, TBackgroundJobGroupStatus, TBackgroundJobWaitPolicy, TBackgroundPrimitive, TBackgroundTaskErrorCategory, TBackgroundTaskEvent, TBackgroundTaskEventListener, TBackgroundTaskIsolation, TBackgroundTaskKind, TBackgroundTaskMode, TBackgroundTaskRequest, TBackgroundTaskResult, TBackgroundTaskState, TBackgroundTaskStatus, TBackgroundTaskTimeoutReason, TExecutionAttention, TExecutionControl, TExecutionDetailRecordKind, TExecutionEntryKind, TExecutionHeadlineKind, TExecutionNormalizedState, TExecutionOriginKind, TExecutionWorkspaceStatus, TExecutionWorkspaceUpdateCause, TExecutionWorkspaceVisibility, TSubagentJobMode, TSubagentJobStatus };
|
|
585
|
+
//# sourceMappingURL=index.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/background-task-contracts.ts","../../src/background-group-contracts.ts","../../src/subagent-contracts.ts","../../src/workspace-contracts.ts"],"mappings":";;KAsBY;KAEA;KAEA;KAEA;KAYA;KAGA;KAUA;UAEK;EACf,UAAU;EACV;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA,UAAU,eAAe;;UAGV;EACf,MAAM;EACN;EACA,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA,WAAW,eAAe;;UAGX,oCAAoC;EACnD;EACA;EACA;EACA;EACA,SAAS;EACT,YAAY;;;;;;;;EAQZ;EACA;EACA;EACA,kBAAkB;EAClB,kBAAkB;EAClB;EACA;EACA;EACA;;UAGe,sCAAsC;EACrD;EACA;EACA;EACA,MAAM;EACN;EACA;;;;;;EAMA;;EAEA;;;;;;;;;;;;;UAce,wCAAwC;EACvD;EACA;;;;;EAKA;;;;;EAKA;EACA;EACA,MAAM;EACN;;;;;;;;;;;UAYe,6CAA6C;EAC5D;EACA;;EAEA;;EAEA;EACA;EACA;EACA;;EAEA;;KAGU,yBACR,8BACA,gCACA,kCACA;;;;;KAMQ,uBAAuB;UAEzB;EACR;EACA;EACA,WAAW,eAAe;;UAGX,mCAAmC;EAClD;;EAEA,QAAQ;;UAGO,qCAAqC;EACpD;EACA;EACA;;UAGe,uCAAuC;EACtD;;UAGe,4CAA4C;EAC3D;;;;;;;;;;;;;KAcU,wBACR,6BACA,+BACA,iCACA;KAEQ,sBAAsB,UAAU,sBAAsB,uBAAuB,QACvF;EACE,MAAM;;;;;;;;;;;;;;;;;UAkBA,yBAAyB,UAAU;EAC3C;EACA,MAAM;EACN;EACA,QAAQ;EACR,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,sBAAsB;EAC/B,QAAQ;EACR;EACA;EACA,gBAAgB;EAChB,WAAW,eAAe;;UAGX,kCAAkC;EACjD;EACA;EACA,YAAY;;;;;EAKZ;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe,oCAAoC;EACnD;;UAGe,sCAAsC;EACrD;EACA;;;;;EAKA,WAAW;;UAGI,2CAA2C;EAC1D;;KAGU,uBACR,4BACA,8BACA,gCACA;KAEQ,qBAAqB,UAAU,sBAAsB,uBAAuB,QACtF;EACE,MAAM;;;UAIO;EACf;EACA;EACA;EACA;EACA,MAAM;;UAGS;EACf;EACA;;UAGe;EACf;;UAGe;EACf;EACA,SAAS;EACT,aAAa;EACb;;UAGe;EACf,OAAO;EACP,SAAS;EACT,OAAO;EACP;;KAGU;EACN;EAAiC,MAAM;;EACvC;EAAiC,MAAM;;EACvC;EAAiC,MAAM;;EACvC;EAAoC;EAAgB;;EACpD;EAAoC;EAAgB;EAAkB;;EAEtE;EACA;EACA;EACA;EACA;;EAGA;EACA;EACA;EACA;EACA,UAAU,eAAe;;EAEzB;EAAmC,MAAM;;EACzC;EAAgC,MAAM;;EACtC;EAAmC,MAAM;;EACzC;EAAgC;;EAGhC;EAAgC;EAAgB;;KAE1C,gCAAgC,OAAO;;;KCxXvC;KAEA;UAEK;EACf;EACA;EACA,QAAQ;EACR;EACA;EACA,QAAQ;EACR;EACA;;UAGe;EACf;EACA;EACA,YAAY;EACZ;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA,SAAS;;UAGM;EACf;EACA,QAAQ;EACR;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA,YAAY;EACZ;EACA;;KAGU;EACN;EAAsC,OAAO;;EAC7C;EAAsC,OAAO;;EAC7C;EAAwC,OAAO;;KAEzC,oCAAoC,OAAO;KAE3C,gCAAgC,SAAS;;;;;;;;;;KClCzC,qBAAqB,QAAQ;;KAG7B,mBAAmB;;;;;;;;;;;;;;UAed,0BAA0B,KACzC;EAwBA;EACA,QAAQ;EACR;EACA;EACA;EACA;;;;;;;;;;;;;;;;KAiBU,wBAAwB,KAAK;;;;;;;;;;;;;;;;;;;;KAqB7B,qBAAqB,KAAK;;;KClG1B;KACA,gDAAgD;KAChD;KACA;;;;;;KAMA;KAEA;KAQA;KAQA;;;;;;;KAOA;;KAGA;UACK;WACN,MAAM;WACN;;;UAGM;WACN;WACA;;UAGM;WACN,MAAM;WACN;WACA;WACA;WACA;WACA;WACA;;UAGM;WACN;WACA;WACA,MAAM;WACN;WACA;WACA,QAAQ;WACR,WAAW;WACX,QAAQ;WACR;WACA;WACA;WACA;WACA;WACA,WAAW;WACX,YAAY;WACZ;WACA,mBAAmB;;WAEnB;;WAEA,OAAO;;WAEP,WAAW;;WAEX;;UAGM;WACN;WACA,iBAAiB;WACjB,sBAAsB;;UAGhB;WACN;WACA;WACA;WACA,kBAAkB;;UAGZ;WACN;WACA,SAAS;;UAGH;WACN;WACA,OAAO;WACP;WACA,UAAU;;UAGJ;WACN;;UAGM;WACN;WACA,MAAM;WACN;WACA;WACA;;UAGM;WACN;WACA,SAAS;WACT,aAAa;WACb,kBAAkB;;UAGZ;WACN;WACA;WACA;WACA;WACA;WACA;;WAEA,iBAAiB;;UAGX;WACN;WACA,YAAY;WACZ,gBAAgB;WAChB,iBAAiB;WACjB;WACA,SAAS;;UAGH;WACN,MAAM;WACN;;UAGM;WACN;WACA,kBAAkB;WAClB,SAAS;;WAET,iBAAiB;;UAGX;WACN;WACA;WACA,SAAS;WACT,aAAa;WACb,OAAO"}
|