@fungi.computer/shiitake-extensions 0.4.0 → 0.6.0

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.
@@ -1,45 +1,5 @@
1
1
  import * as Schema from "effect/Schema";
2
- /** A named cron cadence evaluated in one IANA time zone. */
3
- export declare const LoopCron: Schema.Struct<{
4
- /** Cron expression for the fixed cadence. */
5
- readonly expression: Schema.String;
6
- /** IANA time zone in which the expression is evaluated. */
7
- readonly timeZone: Schema.String;
8
- }>;
9
- /** One Session's loop as every client sees it. */
10
- export declare const Loop: Schema.Struct<{
11
- /** Identity of the loop whose occurrences are being tracked. */
12
- readonly loopId: Schema.String;
13
- /** Whether a person or the model started this loop. */
14
- readonly origin: Schema.Literals<readonly ["human", "model"]>;
15
- /** Configured expiry timestamp, or null when absent. */
16
- readonly expiresAt: Schema.NullOr<Schema.Int>;
17
- /** Original instruction repeated for every occurrence. */
18
- readonly prompt: Schema.String;
19
- /** Whether the model or a fixed cron cadence schedules occurrences. */
20
- readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
21
- /** Cadence of a fixed-interval loop; null when the model paces it. */
22
- readonly cron: Schema.NullOr<Schema.Struct<{
23
- /** Cron expression for the fixed cadence. */
24
- readonly expression: Schema.String;
25
- /** IANA time zone in which the expression is evaluated. */
26
- readonly timeZone: Schema.String;
27
- }>>;
28
- /** Current loop lifecycle state. */
29
- readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
30
- /** Latest accepted command associated with this loop. */
31
- readonly commandId: Schema.String;
32
- /** The model's stated reason for the next self-paced occurrence. */
33
- readonly reason: Schema.NullOr<Schema.String>;
34
- /** When the next occurrence is due, if one is scheduled. */
35
- readonly nextDueAt: Schema.NullOr<Schema.Int>;
36
- /** Visible explanation when loop work failed. */
37
- readonly lastError: Schema.NullOr<Schema.String>;
38
- /** Consecutive failed work outcomes; successful work resets this to zero. */
39
- readonly consecutiveFailures: Schema.Int;
40
- }>;
41
- /** One Session's loop. */
42
- export type Loop = Schema.Schema.Type<typeof Loop>;
2
+ export { Loop, LoopCron } from "./schema.js";
43
3
  /**
44
4
  * Arguments of the human `/loop` command. `start` carries the typed text:
45
5
  * `<prompt>` paces itself, `<N>m <prompt>` or `<N>h <prompt>` runs on an
@@ -62,43 +22,149 @@ export declare const LoopCommandInput: Schema.Union<readonly [Schema.Struct<{
62
22
  export declare const LoopProjection: Schema.Struct<{
63
23
  /** Loop currently visible to Session clients. */
64
24
  readonly loop: Schema.Struct<{
65
- /** Identity of the loop whose occurrences are being tracked. */
66
25
  readonly loopId: Schema.String;
67
- /** Whether a person or the model started this loop. */
68
26
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
69
- /** Configured expiry timestamp, or null when absent. */
70
27
  readonly expiresAt: Schema.NullOr<Schema.Int>;
71
- /** Original instruction repeated for every occurrence. */
72
28
  readonly prompt: Schema.String;
73
- /** Whether the model or a fixed cron cadence schedules occurrences. */
74
29
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
75
- /** Cadence of a fixed-interval loop; null when the model paces it. */
76
30
  readonly cron: Schema.NullOr<Schema.Struct<{
77
- /** Cron expression for the fixed cadence. */
78
31
  readonly expression: Schema.String;
79
- /** IANA time zone in which the expression is evaluated. */
80
32
  readonly timeZone: Schema.String;
81
33
  }>>;
82
- /** Current loop lifecycle state. */
83
34
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
84
- /** Latest accepted command associated with this loop. */
85
35
  readonly commandId: Schema.String;
86
- /** The model's stated reason for the next self-paced occurrence. */
87
36
  readonly reason: Schema.NullOr<Schema.String>;
88
- /** When the next occurrence is due, if one is scheduled. */
89
37
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
90
- /** Visible explanation when loop work failed. */
91
38
  readonly lastError: Schema.NullOr<Schema.String>;
92
- /** Consecutive failed work outcomes; successful work resets this to zero. */
93
39
  readonly consecutiveFailures: Schema.Int;
94
40
  }>;
95
41
  }>;
96
- /** Session-owned loop controls and their visible state. */
42
+ /** Session-owned current-Loop controls and Agent-scoped identified-Loop controls. */
97
43
  export declare const loopContract: {
98
44
  /** Stable extension identity. */
99
45
  readonly id: string & import("effect/Brand").Brand<"ExtensionId">;
100
- /** Loop operations admitted by the Session owner. */
46
+ /** Loop operations admitted by their Agent or Session owner. */
101
47
  readonly commands: {
48
+ /** Read an Agent's bounded Loop page, including each destination Session. */
49
+ readonly list: {
50
+ /** The Agent owns the collection of its Sessions' Loops. */
51
+ readonly scope: "agent";
52
+ /** Page strictly after a Session identity, in identity order. */
53
+ readonly input: Schema.Struct<{
54
+ readonly after: Schema.optionalKey<Schema.String>;
55
+ readonly limit: Schema.optionalKey<Schema.Int>;
56
+ }>;
57
+ /** Public Loop values with Session targets, never private scheduling state. */
58
+ readonly output: Schema.$Array<Schema.Struct<{
59
+ /** Session that owns this identified Loop. */
60
+ readonly sessionId: Schema.String;
61
+ readonly loopId: Schema.String;
62
+ readonly origin: Schema.Literals<readonly ["human", "model"]>;
63
+ readonly expiresAt: Schema.NullOr<Schema.Int>;
64
+ readonly prompt: Schema.String;
65
+ readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
66
+ readonly cron: Schema.NullOr<Schema.Struct<{
67
+ readonly expression: Schema.String;
68
+ readonly timeZone: Schema.String;
69
+ }>>;
70
+ readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
71
+ readonly commandId: Schema.String;
72
+ readonly reason: Schema.NullOr<Schema.String>;
73
+ readonly nextDueAt: Schema.NullOr<Schema.Int>;
74
+ readonly lastError: Schema.NullOr<Schema.String>;
75
+ readonly consecutiveFailures: Schema.Int;
76
+ }>>;
77
+ };
78
+ /** Pause an identified Loop; refuse a stale target after replacement. */
79
+ readonly pauseLoop: {
80
+ /** The Agent owns the identified Loop and its Session. */
81
+ readonly scope: "agent";
82
+ /** The listed Session and Loop identities must both still match. */
83
+ readonly input: Schema.Struct<{
84
+ /** Session containing the identified Loop. */
85
+ readonly sessionId: Schema.String;
86
+ /** Exact Loop identity, not whichever Loop later replaces it. */
87
+ readonly loopId: Schema.String;
88
+ }>;
89
+ /** Return the paused Loop without cancelling accepted work. */
90
+ readonly output: Schema.Struct<{
91
+ readonly loopId: Schema.String;
92
+ readonly origin: Schema.Literals<readonly ["human", "model"]>;
93
+ readonly expiresAt: Schema.NullOr<Schema.Int>;
94
+ readonly prompt: Schema.String;
95
+ readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
96
+ readonly cron: Schema.NullOr<Schema.Struct<{
97
+ readonly expression: Schema.String;
98
+ readonly timeZone: Schema.String;
99
+ }>>;
100
+ readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
101
+ readonly commandId: Schema.String;
102
+ readonly reason: Schema.NullOr<Schema.String>;
103
+ readonly nextDueAt: Schema.NullOr<Schema.Int>;
104
+ readonly lastError: Schema.NullOr<Schema.String>;
105
+ readonly consecutiveFailures: Schema.Int;
106
+ }>;
107
+ };
108
+ /** Resume an identified Loop; refuse a stale target after replacement. */
109
+ readonly resumeLoop: {
110
+ /** The Agent owns the identified Loop and its Session. */
111
+ readonly scope: "agent";
112
+ /** The listed Session and Loop identities must both still match. */
113
+ readonly input: Schema.Struct<{
114
+ /** Session containing the identified Loop. */
115
+ readonly sessionId: Schema.String;
116
+ /** Exact Loop identity, not whichever Loop later replaces it. */
117
+ readonly loopId: Schema.String;
118
+ }>;
119
+ /** Return the resumed Loop without changing accepted work. */
120
+ readonly output: Schema.Struct<{
121
+ readonly loopId: Schema.String;
122
+ readonly origin: Schema.Literals<readonly ["human", "model"]>;
123
+ readonly expiresAt: Schema.NullOr<Schema.Int>;
124
+ readonly prompt: Schema.String;
125
+ readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
126
+ readonly cron: Schema.NullOr<Schema.Struct<{
127
+ readonly expression: Schema.String;
128
+ readonly timeZone: Schema.String;
129
+ }>>;
130
+ readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
131
+ readonly commandId: Schema.String;
132
+ readonly reason: Schema.NullOr<Schema.String>;
133
+ readonly nextDueAt: Schema.NullOr<Schema.Int>;
134
+ readonly lastError: Schema.NullOr<Schema.String>;
135
+ readonly consecutiveFailures: Schema.Int;
136
+ }>;
137
+ };
138
+ /** Cancel an identified Loop's future occurrences, retaining accepted work. */
139
+ readonly stopLoop: {
140
+ /** The Agent owns the identified Loop and its Session. */
141
+ readonly scope: "agent";
142
+ /** The listed Session and Loop identities must both still match. */
143
+ readonly input: Schema.Struct<{
144
+ /** Session containing the identified Loop. */
145
+ readonly sessionId: Schema.String;
146
+ /** Exact Loop identity, not whichever Loop later replaces it. */
147
+ readonly loopId: Schema.String;
148
+ }>;
149
+ /** Return the cancelled Loop; its Session and history remain. */
150
+ readonly output: Schema.Struct<{
151
+ readonly loopId: Schema.String;
152
+ readonly origin: Schema.Literals<readonly ["human", "model"]>;
153
+ readonly expiresAt: Schema.NullOr<Schema.Int>;
154
+ readonly prompt: Schema.String;
155
+ readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
156
+ readonly cron: Schema.NullOr<Schema.Struct<{
157
+ readonly expression: Schema.String;
158
+ readonly timeZone: Schema.String;
159
+ }>>;
160
+ readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
161
+ readonly commandId: Schema.String;
162
+ readonly reason: Schema.NullOr<Schema.String>;
163
+ readonly nextDueAt: Schema.NullOr<Schema.Int>;
164
+ readonly lastError: Schema.NullOr<Schema.String>;
165
+ readonly consecutiveFailures: Schema.Int;
166
+ }>;
167
+ };
102
168
  /** Open or answer the human loop controls. */
103
169
  readonly loop: {
104
170
  /** The Session owns this loop. */
@@ -135,34 +201,20 @@ export declare const loopContract: {
135
201
  readonly output: Schema.Struct<{
136
202
  /** Newly started loop. */
137
203
  readonly loop: Schema.Struct<{
138
- /** Identity of the loop whose occurrences are being tracked. */
139
204
  readonly loopId: Schema.String;
140
- /** Whether a person or the model started this loop. */
141
205
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
142
- /** Configured expiry timestamp, or null when absent. */
143
206
  readonly expiresAt: Schema.NullOr<Schema.Int>;
144
- /** Original instruction repeated for every occurrence. */
145
207
  readonly prompt: Schema.String;
146
- /** Whether the model or a fixed cron cadence schedules occurrences. */
147
208
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
148
- /** Cadence of a fixed-interval loop; null when the model paces it. */
149
209
  readonly cron: Schema.NullOr<Schema.Struct<{
150
- /** Cron expression for the fixed cadence. */
151
210
  readonly expression: Schema.String;
152
- /** IANA time zone in which the expression is evaluated. */
153
211
  readonly timeZone: Schema.String;
154
212
  }>>;
155
- /** Current loop lifecycle state. */
156
213
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
157
- /** Latest accepted command associated with this loop. */
158
214
  readonly commandId: Schema.String;
159
- /** The model's stated reason for the next self-paced occurrence. */
160
215
  readonly reason: Schema.NullOr<Schema.String>;
161
- /** When the next occurrence is due, if one is scheduled. */
162
216
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
163
- /** Visible explanation when loop work failed. */
164
217
  readonly lastError: Schema.NullOr<Schema.String>;
165
- /** Consecutive failed work outcomes; successful work resets this to zero. */
166
218
  readonly consecutiveFailures: Schema.Int;
167
219
  }>;
168
220
  /** Admission receipt for the start command. */
@@ -180,9 +232,7 @@ export declare const loopContract: {
180
232
  readonly scope: "session";
181
233
  /** Decode the prompt, cadence and command identity. */
182
234
  readonly input: Schema.Struct<{
183
- /** Cron expression for the fixed cadence. */
184
235
  readonly expression: Schema.String;
185
- /** IANA time zone in which the expression is evaluated. */
186
236
  readonly timeZone: Schema.String;
187
237
  /** Instruction repeated on every occurrence. */
188
238
  readonly prompt: Schema.String;
@@ -193,34 +243,20 @@ export declare const loopContract: {
193
243
  readonly output: Schema.Struct<{
194
244
  /** Newly started loop. */
195
245
  readonly loop: Schema.Struct<{
196
- /** Identity of the loop whose occurrences are being tracked. */
197
246
  readonly loopId: Schema.String;
198
- /** Whether a person or the model started this loop. */
199
247
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
200
- /** Configured expiry timestamp, or null when absent. */
201
248
  readonly expiresAt: Schema.NullOr<Schema.Int>;
202
- /** Original instruction repeated for every occurrence. */
203
249
  readonly prompt: Schema.String;
204
- /** Whether the model or a fixed cron cadence schedules occurrences. */
205
250
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
206
- /** Cadence of a fixed-interval loop; null when the model paces it. */
207
251
  readonly cron: Schema.NullOr<Schema.Struct<{
208
- /** Cron expression for the fixed cadence. */
209
252
  readonly expression: Schema.String;
210
- /** IANA time zone in which the expression is evaluated. */
211
253
  readonly timeZone: Schema.String;
212
254
  }>>;
213
- /** Current loop lifecycle state. */
214
255
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
215
- /** Latest accepted command associated with this loop. */
216
256
  readonly commandId: Schema.String;
217
- /** The model's stated reason for the next self-paced occurrence. */
218
257
  readonly reason: Schema.NullOr<Schema.String>;
219
- /** When the next occurrence is due, if one is scheduled. */
220
258
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
221
- /** Visible explanation when loop work failed. */
222
259
  readonly lastError: Schema.NullOr<Schema.String>;
223
- /** Consecutive failed work outcomes; successful work resets this to zero. */
224
260
  readonly consecutiveFailures: Schema.Int;
225
261
  }>;
226
262
  /** Admission receipt for the start command. */
@@ -240,34 +276,20 @@ export declare const loopContract: {
240
276
  readonly input: Schema.Struct<{}>;
241
277
  /** Return the paused loop. */
242
278
  readonly output: Schema.Struct<{
243
- /** Identity of the loop whose occurrences are being tracked. */
244
279
  readonly loopId: Schema.String;
245
- /** Whether a person or the model started this loop. */
246
280
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
247
- /** Configured expiry timestamp, or null when absent. */
248
281
  readonly expiresAt: Schema.NullOr<Schema.Int>;
249
- /** Original instruction repeated for every occurrence. */
250
282
  readonly prompt: Schema.String;
251
- /** Whether the model or a fixed cron cadence schedules occurrences. */
252
283
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
253
- /** Cadence of a fixed-interval loop; null when the model paces it. */
254
284
  readonly cron: Schema.NullOr<Schema.Struct<{
255
- /** Cron expression for the fixed cadence. */
256
285
  readonly expression: Schema.String;
257
- /** IANA time zone in which the expression is evaluated. */
258
286
  readonly timeZone: Schema.String;
259
287
  }>>;
260
- /** Current loop lifecycle state. */
261
288
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
262
- /** Latest accepted command associated with this loop. */
263
289
  readonly commandId: Schema.String;
264
- /** The model's stated reason for the next self-paced occurrence. */
265
290
  readonly reason: Schema.NullOr<Schema.String>;
266
- /** When the next occurrence is due, if one is scheduled. */
267
291
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
268
- /** Visible explanation when loop work failed. */
269
292
  readonly lastError: Schema.NullOr<Schema.String>;
270
- /** Consecutive failed work outcomes; successful work resets this to zero. */
271
293
  readonly consecutiveFailures: Schema.Int;
272
294
  }>;
273
295
  };
@@ -279,34 +301,20 @@ export declare const loopContract: {
279
301
  readonly input: Schema.Struct<{}>;
280
302
  /** Return the resumed loop. */
281
303
  readonly output: Schema.Struct<{
282
- /** Identity of the loop whose occurrences are being tracked. */
283
304
  readonly loopId: Schema.String;
284
- /** Whether a person or the model started this loop. */
285
305
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
286
- /** Configured expiry timestamp, or null when absent. */
287
306
  readonly expiresAt: Schema.NullOr<Schema.Int>;
288
- /** Original instruction repeated for every occurrence. */
289
307
  readonly prompt: Schema.String;
290
- /** Whether the model or a fixed cron cadence schedules occurrences. */
291
308
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
292
- /** Cadence of a fixed-interval loop; null when the model paces it. */
293
309
  readonly cron: Schema.NullOr<Schema.Struct<{
294
- /** Cron expression for the fixed cadence. */
295
310
  readonly expression: Schema.String;
296
- /** IANA time zone in which the expression is evaluated. */
297
311
  readonly timeZone: Schema.String;
298
312
  }>>;
299
- /** Current loop lifecycle state. */
300
313
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
301
- /** Latest accepted command associated with this loop. */
302
314
  readonly commandId: Schema.String;
303
- /** The model's stated reason for the next self-paced occurrence. */
304
315
  readonly reason: Schema.NullOr<Schema.String>;
305
- /** When the next occurrence is due, if one is scheduled. */
306
316
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
307
- /** Visible explanation when loop work failed. */
308
317
  readonly lastError: Schema.NullOr<Schema.String>;
309
- /** Consecutive failed work outcomes; successful work resets this to zero. */
310
318
  readonly consecutiveFailures: Schema.Int;
311
319
  }>;
312
320
  };
@@ -318,34 +326,20 @@ export declare const loopContract: {
318
326
  readonly input: Schema.Struct<{}>;
319
327
  /** Return the stopped loop. */
320
328
  readonly output: Schema.Struct<{
321
- /** Identity of the loop whose occurrences are being tracked. */
322
329
  readonly loopId: Schema.String;
323
- /** Whether a person or the model started this loop. */
324
330
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
325
- /** Configured expiry timestamp, or null when absent. */
326
331
  readonly expiresAt: Schema.NullOr<Schema.Int>;
327
- /** Original instruction repeated for every occurrence. */
328
332
  readonly prompt: Schema.String;
329
- /** Whether the model or a fixed cron cadence schedules occurrences. */
330
333
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
331
- /** Cadence of a fixed-interval loop; null when the model paces it. */
332
334
  readonly cron: Schema.NullOr<Schema.Struct<{
333
- /** Cron expression for the fixed cadence. */
334
335
  readonly expression: Schema.String;
335
- /** IANA time zone in which the expression is evaluated. */
336
336
  readonly timeZone: Schema.String;
337
337
  }>>;
338
- /** Current loop lifecycle state. */
339
338
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
340
- /** Latest accepted command associated with this loop. */
341
339
  readonly commandId: Schema.String;
342
- /** The model's stated reason for the next self-paced occurrence. */
343
340
  readonly reason: Schema.NullOr<Schema.String>;
344
- /** When the next occurrence is due, if one is scheduled. */
345
341
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
346
- /** Visible explanation when loop work failed. */
347
342
  readonly lastError: Schema.NullOr<Schema.String>;
348
- /** Consecutive failed work outcomes; successful work resets this to zero. */
349
343
  readonly consecutiveFailures: Schema.Int;
350
344
  }>;
351
345
  };
@@ -356,34 +350,20 @@ export declare const loopContract: {
356
350
  readonly schema: Schema.Struct<{
357
351
  /** Loop currently visible to Session clients. */
358
352
  readonly loop: Schema.Struct<{
359
- /** Identity of the loop whose occurrences are being tracked. */
360
353
  readonly loopId: Schema.String;
361
- /** Whether a person or the model started this loop. */
362
354
  readonly origin: Schema.Literals<readonly ["human", "model"]>;
363
- /** Configured expiry timestamp, or null when absent. */
364
355
  readonly expiresAt: Schema.NullOr<Schema.Int>;
365
- /** Original instruction repeated for every occurrence. */
366
356
  readonly prompt: Schema.String;
367
- /** Whether the model or a fixed cron cadence schedules occurrences. */
368
357
  readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
369
- /** Cadence of a fixed-interval loop; null when the model paces it. */
370
358
  readonly cron: Schema.NullOr<Schema.Struct<{
371
- /** Cron expression for the fixed cadence. */
372
359
  readonly expression: Schema.String;
373
- /** IANA time zone in which the expression is evaluated. */
374
360
  readonly timeZone: Schema.String;
375
361
  }>>;
376
- /** Current loop lifecycle state. */
377
362
  readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
378
- /** Latest accepted command associated with this loop. */
379
363
  readonly commandId: Schema.String;
380
- /** The model's stated reason for the next self-paced occurrence. */
381
364
  readonly reason: Schema.NullOr<Schema.String>;
382
- /** When the next occurrence is due, if one is scheduled. */
383
365
  readonly nextDueAt: Schema.NullOr<Schema.Int>;
384
- /** Visible explanation when loop work failed. */
385
366
  readonly lastError: Schema.NullOr<Schema.String>;
386
- /** Consecutive failed work outcomes; successful work resets this to zero. */
387
367
  readonly consecutiveFailures: Schema.Int;
388
368
  }>;
389
369
  }>;
@@ -1,53 +1,15 @@
1
1
  import { ExtensionId } from "@fungi.computer/shiitake/extensions";
2
2
  import * as Schema from "effect/Schema";
3
3
  import { CatalogStep } from "../internal/catalog.js";
4
+ import { Prompt, SessionId } from "../internal/schedule-fields.js";
5
+ import { LoopCron, Loop, LoopListInput } from "./schema.js";
6
+ export { Loop, LoopCron } from "./schema.js";
4
7
  /**
5
8
  * Session loop: one repeated prompt per Session, either paced by the model
6
9
  * (`schedule_next`) or by a fixed cron cadence. Shared by the server
7
10
  * extension and every client; its schemas are the one decoder.
8
11
  */
9
- const Prompt = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(256 * 1024)));
10
12
  const RequestId = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(200)));
11
- /** A named cron cadence evaluated in one IANA time zone. */
12
- export const LoopCron = Schema.Struct({
13
- /** Cron expression for the fixed cadence. */
14
- expression: Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(256))),
15
- /** IANA time zone in which the expression is evaluated. */
16
- timeZone: Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(128))),
17
- });
18
- /** One Session's loop as every client sees it. */
19
- export const Loop = Schema.Struct({
20
- /** Identity of the loop whose occurrences are being tracked. */
21
- loopId: Schema.String,
22
- /** Whether a person or the model started this loop. */
23
- origin: Schema.Literals(["human", "model"]),
24
- /** Configured expiry timestamp, or null when absent. */
25
- expiresAt: Schema.NullOr(Schema.Int),
26
- /** Original instruction repeated for every occurrence. */
27
- prompt: Prompt,
28
- /** Whether the model or a fixed cron cadence schedules occurrences. */
29
- mode: Schema.Literals(["self_paced", "fixed_interval"]),
30
- /** Cadence of a fixed-interval loop; null when the model paces it. */
31
- cron: Schema.NullOr(LoopCron),
32
- /** Current loop lifecycle state. */
33
- state: Schema.Literals([
34
- "active",
35
- "paused",
36
- "finished",
37
- "failed",
38
- "cancelled",
39
- ]),
40
- /** Latest accepted command associated with this loop. */
41
- commandId: Schema.String,
42
- /** The model's stated reason for the next self-paced occurrence. */
43
- reason: Schema.NullOr(Schema.String),
44
- /** When the next occurrence is due, if one is scheduled. */
45
- nextDueAt: Schema.NullOr(Schema.Int),
46
- /** Visible explanation when loop work failed. */
47
- lastError: Schema.NullOr(Schema.String),
48
- /** Consecutive failed work outcomes; successful work resets this to zero. */
49
- consecutiveFailures: Schema.Int.pipe(Schema.check(Schema.isGreaterThanOrEqualTo(0))),
50
- });
51
13
  const StartResult = Schema.Struct({
52
14
  /** Newly started loop. */
53
15
  loop: Loop,
@@ -93,12 +55,58 @@ export const LoopProjection = Schema.Struct({
93
55
  /** Loop currently visible to Session clients. */
94
56
  loop: Loop,
95
57
  });
96
- /** Session-owned loop controls and their visible state. */
58
+ const LoopTarget = Schema.Struct({
59
+ /** Session containing the identified Loop. */
60
+ sessionId: SessionId,
61
+ /** Exact Loop identity, not whichever Loop later replaces it. */
62
+ loopId: Loop.fields.loopId,
63
+ });
64
+ /** Session-owned current-Loop controls and Agent-scoped identified-Loop controls. */
97
65
  export const loopContract = {
98
66
  /** Stable extension identity. */
99
67
  id: ExtensionId.make("botanical-session-loop"),
100
- /** Loop operations admitted by the Session owner. */
68
+ /** Loop operations admitted by their Agent or Session owner. */
101
69
  commands: {
70
+ /** Read an Agent's bounded Loop page, including each destination Session. */
71
+ list: {
72
+ /** The Agent owns the collection of its Sessions' Loops. */
73
+ scope: "agent",
74
+ /** Page strictly after a Session identity, in identity order. */
75
+ input: LoopListInput,
76
+ /** Public Loop values with Session targets, never private scheduling state. */
77
+ output: Schema.Array(Schema.Struct({
78
+ ...Loop.fields,
79
+ /** Session that owns this identified Loop. */
80
+ sessionId: SessionId,
81
+ })).pipe(Schema.check(Schema.isMaxLength(64))),
82
+ },
83
+ /** Pause an identified Loop; refuse a stale target after replacement. */
84
+ pauseLoop: {
85
+ /** The Agent owns the identified Loop and its Session. */
86
+ scope: "agent",
87
+ /** The listed Session and Loop identities must both still match. */
88
+ input: LoopTarget,
89
+ /** Return the paused Loop without cancelling accepted work. */
90
+ output: Loop,
91
+ },
92
+ /** Resume an identified Loop; refuse a stale target after replacement. */
93
+ resumeLoop: {
94
+ /** The Agent owns the identified Loop and its Session. */
95
+ scope: "agent",
96
+ /** The listed Session and Loop identities must both still match. */
97
+ input: LoopTarget,
98
+ /** Return the resumed Loop without changing accepted work. */
99
+ output: Loop,
100
+ },
101
+ /** Cancel an identified Loop's future occurrences, retaining accepted work. */
102
+ stopLoop: {
103
+ /** The Agent owns the identified Loop and its Session. */
104
+ scope: "agent",
105
+ /** The listed Session and Loop identities must both still match. */
106
+ input: LoopTarget,
107
+ /** Return the cancelled Loop; its Session and history remain. */
108
+ output: Loop,
109
+ },
102
110
  /** Open or answer the human loop controls. */
103
111
  loop: {
104
112
  /** The Session owns this loop. */
package/dist/loop/host.js CHANGED
@@ -281,6 +281,13 @@ function fire(ctx, sessionId, dueAt, now) {
281
281
  delivery: "followUp",
282
282
  },
283
283
  }));
284
+ // The Agent owner will pause this loop after flipping its archive flag.
285
+ // If this timer wins that short interval, keep the loop resumable instead
286
+ // of treating an intentional archive refusal as a permanent failed run.
287
+ if (Result.isFailure(admitted) && admitted.failure.reason === "archived") {
288
+ yield* arm(ctx, { ...loop, lastError: admitted.failure.message }, now + 30_000);
289
+ return yield* ctx.observe(sessionId);
290
+ }
284
291
  if (Result.isFailure(admitted) || admitted.success._tag === "NotReady") {
285
292
  yield* commitLoop(ctx, {
286
293
  ...loop,
@@ -493,6 +500,16 @@ function stopLoop(ctx, sessionId, reason) {
493
500
  return projected(stopped);
494
501
  });
495
502
  }
503
+ /** Match and mutate within the same extension command transaction. */
504
+ function controlIdentifiedLoop(ctx, target, action) {
505
+ return requireLoop(ctx, target.sessionId).pipe(Effect.flatMap((loop) => loop.loopId !== target.loopId
506
+ ? Effect.fail(conflict("Session loop has been replaced"))
507
+ : action === "pause"
508
+ ? pauseLoop(ctx, target.sessionId)
509
+ : action === "resume"
510
+ ? resumeLoop(ctx, target.sessionId)
511
+ : stopLoop(ctx, target.sessionId)));
512
+ }
496
513
  function cronForInterval(value, unit) {
497
514
  if (unit === "m" || unit === "min")
498
515
  return value > 59 ? undefined : `0 */${String(value)} * * * *`;
@@ -662,6 +679,15 @@ export const loopExtension = defineExtension({
662
679
  commands: {
663
680
  specs: loopContract.commands,
664
681
  handlers: (ctx) => ({
682
+ pauseLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "pause"),
683
+ resumeLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "resume"),
684
+ stopLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "stop"),
685
+ list: ({ input }) => ctx.state.loops
686
+ .page({ after: input.after, limit: input.limit ?? 64 })
687
+ .pipe(Effect.map((rows) => rows.map((row) => ({
688
+ ...projected(row),
689
+ sessionId: row.sessionId,
690
+ })))),
665
691
  startSelfPaced: ({ sessionId, input }) => start(ctx, sessionId, input, null),
666
692
  startFixedInterval: ({ sessionId, input }) => start(ctx, sessionId, input, {
667
693
  expression: input.expression,
@@ -0,0 +1,49 @@
1
+ import * as Schema from "effect/Schema";
2
+ /** A named cron cadence evaluated in one IANA time zone. */
3
+ export declare const LoopCron: Schema.Struct<{
4
+ /** Cron expression for the fixed cadence. */
5
+ readonly expression: Schema.String;
6
+ /** IANA time zone in which the expression is evaluated. */
7
+ readonly timeZone: Schema.String;
8
+ }>;
9
+ /** One Session's loop as every client sees it. */
10
+ export declare const Loop: Schema.Struct<{
11
+ /** Identity of the loop whose occurrences are being tracked. */
12
+ readonly loopId: Schema.String;
13
+ /** Whether a person or the model started this loop. */
14
+ readonly origin: Schema.Literals<readonly ["human", "model"]>;
15
+ /** Configured expiry timestamp, or null when absent. */
16
+ readonly expiresAt: Schema.NullOr<Schema.Int>;
17
+ /** Original instruction repeated for every occurrence. */
18
+ readonly prompt: Schema.String;
19
+ /** Whether the model or a fixed cron cadence schedules occurrences. */
20
+ readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
21
+ /** Cadence of a fixed-interval loop; null when the model paces it. */
22
+ readonly cron: Schema.NullOr<Schema.Struct<{
23
+ /** Cron expression for the fixed cadence. */
24
+ readonly expression: Schema.String;
25
+ /** IANA time zone in which the expression is evaluated. */
26
+ readonly timeZone: Schema.String;
27
+ }>>;
28
+ /** Current loop lifecycle state. */
29
+ readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
30
+ /** Latest accepted command associated with this loop. */
31
+ readonly commandId: Schema.String;
32
+ /** The model's stated reason for the next self-paced occurrence. */
33
+ readonly reason: Schema.NullOr<Schema.String>;
34
+ /** When the next occurrence is due, if one is scheduled. */
35
+ readonly nextDueAt: Schema.NullOr<Schema.Int>;
36
+ /** Visible explanation when loop work failed. */
37
+ readonly lastError: Schema.NullOr<Schema.String>;
38
+ /** Consecutive failed work outcomes; successful work resets this to zero. */
39
+ readonly consecutiveFailures: Schema.Int;
40
+ }>;
41
+ /** One Session's loop. */
42
+ export type Loop = Schema.Schema.Type<typeof Loop>;
43
+ /** Native bounded Loop page grammar, also used by shared continuations. */
44
+ export declare const LoopListInput: Schema.Struct<{
45
+ /** Exclusive Session cursor. */
46
+ readonly after: Schema.optionalKey<Schema.String>;
47
+ /** Maximum number of Loop rows to read. */
48
+ readonly limit: Schema.optionalKey<Schema.Int>;
49
+ }>;