@fungi.computer/shiitake-extensions 0.4.0 → 0.5.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.
- package/README.md +2 -3
- package/dist/goal/host.js +3 -1
- package/dist/loop/contract.d.ts +136 -2
- package/dist/loop/contract.js +45 -2
- package/dist/loop/host.js +23 -0
- package/dist/roster/conversation-agents.d.ts +11 -2
- package/dist/roster/conversation-agents.js +16 -6
- package/dist/schedules.d.ts +178 -0
- package/dist/schedules.js +182 -0
- package/docs/api/README.md +1 -0
- package/docs/api/goal/contract.md +1 -1
- package/docs/api/loop/contract.md +43 -31
- package/docs/api/roster/conversation-agents.md +19 -1
- package/docs/api/schedules.md +481 -0
- package/docs/api/subagents/host.md +0 -1
- package/package.json +8 -4
package/README.md
CHANGED
|
@@ -112,9 +112,8 @@ paused and `null` while active. The closed kinds are `person`, `blocked`,
|
|
|
112
112
|
text, never a discriminator. Only blocked/stalled goals emit `goal-blocked` or
|
|
113
113
|
`goal-stalled` attention, kept out of the main inbox with `inbox: false`.
|
|
114
114
|
Questions and these two Goal kinds ask for a person in Herdr activity;
|
|
115
|
-
person-paused, cancelled and failed goals do not.
|
|
116
|
-
|
|
117
|
-
superseded representation.
|
|
115
|
+
person-paused, cancelled and failed goals do not. The current Goal state is
|
|
116
|
+
version 7. Superseded preview Goal rows are not migrated to this representation.
|
|
118
117
|
|
|
119
118
|
Loop tools are offered in every run. `loop.get`, `loop.start` and `loop.stop`
|
|
120
119
|
work from any run of the Session, and the model may start a loop itself.
|
package/dist/goal/host.js
CHANGED
|
@@ -208,7 +208,9 @@ function continueIfIdle(ctx, goal, requestId) {
|
|
|
208
208
|
})
|
|
209
209
|
.pipe(Effect.map((admitted) => admitted._tag === "Accepted"
|
|
210
210
|
? { ...goal, trackedWorkId: admitted.commandId }
|
|
211
|
-
: goal), Effect.catchTag("AdmissionError", (error) =>
|
|
211
|
+
: goal), Effect.catchTag("AdmissionError", (error) => error.reason === "archived"
|
|
212
|
+
? Clock.currentTimeMillis.pipe(Effect.flatMap((now) => ctx.timers.set(waitTimerKey(goal.sessionId), now + ctx.config.waitCheckMs)), Effect.as(goal))
|
|
213
|
+
: Effect.succeed(paused(goal, "failed", error.message))));
|
|
212
214
|
}
|
|
213
215
|
/**
|
|
214
216
|
* Advance one Session's goal from one settled run. Any successful run in
|
package/dist/loop/contract.d.ts
CHANGED
|
@@ -93,12 +93,146 @@ export declare const LoopProjection: Schema.Struct<{
|
|
|
93
93
|
readonly consecutiveFailures: Schema.Int;
|
|
94
94
|
}>;
|
|
95
95
|
}>;
|
|
96
|
-
/** Session-owned
|
|
96
|
+
/** Session-owned current-Loop controls and Agent-scoped identified-Loop controls. */
|
|
97
97
|
export declare const loopContract: {
|
|
98
98
|
/** Stable extension identity. */
|
|
99
99
|
readonly id: string & import("effect/Brand").Brand<"ExtensionId">;
|
|
100
|
-
/** Loop operations admitted by
|
|
100
|
+
/** Loop operations admitted by their Agent or Session owner. */
|
|
101
101
|
readonly commands: {
|
|
102
|
+
/** Read an Agent's bounded Loop page, including each destination Session. */
|
|
103
|
+
readonly list: {
|
|
104
|
+
/** The Agent owns the collection of its Sessions' Loops. */
|
|
105
|
+
readonly scope: "agent";
|
|
106
|
+
/** Page strictly after a Session identity, in identity order. */
|
|
107
|
+
readonly input: Schema.Struct<{
|
|
108
|
+
/** Exclusive Session cursor. */
|
|
109
|
+
readonly after: Schema.optionalKey<Schema.String>;
|
|
110
|
+
/** Maximum number of Loop rows to read. */
|
|
111
|
+
readonly limit: Schema.optionalKey<Schema.Int>;
|
|
112
|
+
}>;
|
|
113
|
+
/** Public Loop values with Session targets, never private scheduling state. */
|
|
114
|
+
readonly output: Schema.$Array<Schema.Struct<{
|
|
115
|
+
/** Session that owns this identified Loop. */
|
|
116
|
+
readonly sessionId: Schema.String;
|
|
117
|
+
/** Identity of the loop whose occurrences are being tracked. */
|
|
118
|
+
readonly loopId: Schema.String;
|
|
119
|
+
/** Whether a person or the model started this loop. */
|
|
120
|
+
readonly origin: Schema.Literals<readonly ["human", "model"]>;
|
|
121
|
+
/** Configured expiry timestamp, or null when absent. */
|
|
122
|
+
readonly expiresAt: Schema.NullOr<Schema.Int>;
|
|
123
|
+
/** Original instruction repeated for every occurrence. */
|
|
124
|
+
readonly prompt: Schema.String;
|
|
125
|
+
/** Whether the model or a fixed cron cadence schedules occurrences. */
|
|
126
|
+
readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
|
|
127
|
+
/** Cadence of a fixed-interval loop; null when the model paces it. */
|
|
128
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
129
|
+
/** Cron expression for the fixed cadence. */
|
|
130
|
+
readonly expression: Schema.String;
|
|
131
|
+
/** IANA time zone in which the expression is evaluated. */
|
|
132
|
+
readonly timeZone: Schema.String;
|
|
133
|
+
}>>;
|
|
134
|
+
/** Current loop lifecycle state. */
|
|
135
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
|
|
136
|
+
/** Latest accepted command associated with this loop. */
|
|
137
|
+
readonly commandId: Schema.String;
|
|
138
|
+
/** The model's stated reason for the next self-paced occurrence. */
|
|
139
|
+
readonly reason: Schema.NullOr<Schema.String>;
|
|
140
|
+
/** When the next occurrence is due, if one is scheduled. */
|
|
141
|
+
readonly nextDueAt: Schema.NullOr<Schema.Int>;
|
|
142
|
+
/** Visible explanation when loop work failed. */
|
|
143
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
144
|
+
/** Consecutive failed work outcomes; successful work resets this to zero. */
|
|
145
|
+
readonly consecutiveFailures: Schema.Int;
|
|
146
|
+
}>>;
|
|
147
|
+
};
|
|
148
|
+
/** Pause an identified Loop; refuse a stale target after replacement. */
|
|
149
|
+
readonly pauseLoop: {
|
|
150
|
+
/** The Agent owns the identified Loop and its Session. */
|
|
151
|
+
readonly scope: "agent";
|
|
152
|
+
/** The listed Session and Loop identities must both still match. */
|
|
153
|
+
readonly input: Schema.Struct<{
|
|
154
|
+
/** Session containing the identified Loop. */
|
|
155
|
+
readonly sessionId: Schema.String;
|
|
156
|
+
/** Exact Loop identity, not whichever Loop later replaces it. */
|
|
157
|
+
readonly loopId: Schema.String;
|
|
158
|
+
}>;
|
|
159
|
+
/** Return the paused Loop without cancelling accepted work. */
|
|
160
|
+
readonly output: Schema.Struct<{
|
|
161
|
+
/** Identity of the loop whose occurrences are being tracked. */
|
|
162
|
+
readonly loopId: Schema.String;
|
|
163
|
+
/** Whether a person or the model started this loop. */
|
|
164
|
+
readonly origin: Schema.Literals<readonly ["human", "model"]>;
|
|
165
|
+
/** Configured expiry timestamp, or null when absent. */
|
|
166
|
+
readonly expiresAt: Schema.NullOr<Schema.Int>;
|
|
167
|
+
/** Original instruction repeated for every occurrence. */
|
|
168
|
+
readonly prompt: Schema.String;
|
|
169
|
+
/** Whether the model or a fixed cron cadence schedules occurrences. */
|
|
170
|
+
readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
|
|
171
|
+
/** Cadence of a fixed-interval loop; null when the model paces it. */
|
|
172
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
173
|
+
/** Cron expression for the fixed cadence. */
|
|
174
|
+
readonly expression: Schema.String;
|
|
175
|
+
/** IANA time zone in which the expression is evaluated. */
|
|
176
|
+
readonly timeZone: Schema.String;
|
|
177
|
+
}>>;
|
|
178
|
+
/** Current loop lifecycle state. */
|
|
179
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
|
|
180
|
+
/** Latest accepted command associated with this loop. */
|
|
181
|
+
readonly commandId: Schema.String;
|
|
182
|
+
/** The model's stated reason for the next self-paced occurrence. */
|
|
183
|
+
readonly reason: Schema.NullOr<Schema.String>;
|
|
184
|
+
/** When the next occurrence is due, if one is scheduled. */
|
|
185
|
+
readonly nextDueAt: Schema.NullOr<Schema.Int>;
|
|
186
|
+
/** Visible explanation when loop work failed. */
|
|
187
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
188
|
+
/** Consecutive failed work outcomes; successful work resets this to zero. */
|
|
189
|
+
readonly consecutiveFailures: Schema.Int;
|
|
190
|
+
}>;
|
|
191
|
+
};
|
|
192
|
+
/** Cancel an identified Loop's future occurrences, retaining accepted work. */
|
|
193
|
+
readonly stopLoop: {
|
|
194
|
+
/** The Agent owns the identified Loop and its Session. */
|
|
195
|
+
readonly scope: "agent";
|
|
196
|
+
/** The listed Session and Loop identities must both still match. */
|
|
197
|
+
readonly input: Schema.Struct<{
|
|
198
|
+
/** Session containing the identified Loop. */
|
|
199
|
+
readonly sessionId: Schema.String;
|
|
200
|
+
/** Exact Loop identity, not whichever Loop later replaces it. */
|
|
201
|
+
readonly loopId: Schema.String;
|
|
202
|
+
}>;
|
|
203
|
+
/** Return the cancelled Loop; its Session and history remain. */
|
|
204
|
+
readonly output: Schema.Struct<{
|
|
205
|
+
/** Identity of the loop whose occurrences are being tracked. */
|
|
206
|
+
readonly loopId: Schema.String;
|
|
207
|
+
/** Whether a person or the model started this loop. */
|
|
208
|
+
readonly origin: Schema.Literals<readonly ["human", "model"]>;
|
|
209
|
+
/** Configured expiry timestamp, or null when absent. */
|
|
210
|
+
readonly expiresAt: Schema.NullOr<Schema.Int>;
|
|
211
|
+
/** Original instruction repeated for every occurrence. */
|
|
212
|
+
readonly prompt: Schema.String;
|
|
213
|
+
/** Whether the model or a fixed cron cadence schedules occurrences. */
|
|
214
|
+
readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
|
|
215
|
+
/** Cadence of a fixed-interval loop; null when the model paces it. */
|
|
216
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
217
|
+
/** Cron expression for the fixed cadence. */
|
|
218
|
+
readonly expression: Schema.String;
|
|
219
|
+
/** IANA time zone in which the expression is evaluated. */
|
|
220
|
+
readonly timeZone: Schema.String;
|
|
221
|
+
}>>;
|
|
222
|
+
/** Current loop lifecycle state. */
|
|
223
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
|
|
224
|
+
/** Latest accepted command associated with this loop. */
|
|
225
|
+
readonly commandId: Schema.String;
|
|
226
|
+
/** The model's stated reason for the next self-paced occurrence. */
|
|
227
|
+
readonly reason: Schema.NullOr<Schema.String>;
|
|
228
|
+
/** When the next occurrence is due, if one is scheduled. */
|
|
229
|
+
readonly nextDueAt: Schema.NullOr<Schema.Int>;
|
|
230
|
+
/** Visible explanation when loop work failed. */
|
|
231
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
232
|
+
/** Consecutive failed work outcomes; successful work resets this to zero. */
|
|
233
|
+
readonly consecutiveFailures: Schema.Int;
|
|
234
|
+
}>;
|
|
235
|
+
};
|
|
102
236
|
/** Open or answer the human loop controls. */
|
|
103
237
|
readonly loop: {
|
|
104
238
|
/** The Session owns this loop. */
|
package/dist/loop/contract.js
CHANGED
|
@@ -8,6 +8,7 @@ import { CatalogStep } from "../internal/catalog.js";
|
|
|
8
8
|
*/
|
|
9
9
|
const Prompt = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(256 * 1024)));
|
|
10
10
|
const RequestId = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(200)));
|
|
11
|
+
const SessionId = Schema.String.pipe(Schema.check(Schema.isMinLength(1)), Schema.check(Schema.isMaxLength(256)));
|
|
11
12
|
/** A named cron cadence evaluated in one IANA time zone. */
|
|
12
13
|
export const LoopCron = Schema.Struct({
|
|
13
14
|
/** Cron expression for the fixed cadence. */
|
|
@@ -93,12 +94,54 @@ export const LoopProjection = Schema.Struct({
|
|
|
93
94
|
/** Loop currently visible to Session clients. */
|
|
94
95
|
loop: Loop,
|
|
95
96
|
});
|
|
96
|
-
|
|
97
|
+
const LoopTarget = Schema.Struct({
|
|
98
|
+
/** Session containing the identified Loop. */
|
|
99
|
+
sessionId: SessionId,
|
|
100
|
+
/** Exact Loop identity, not whichever Loop later replaces it. */
|
|
101
|
+
loopId: Loop.fields.loopId,
|
|
102
|
+
});
|
|
103
|
+
/** Session-owned current-Loop controls and Agent-scoped identified-Loop controls. */
|
|
97
104
|
export const loopContract = {
|
|
98
105
|
/** Stable extension identity. */
|
|
99
106
|
id: ExtensionId.make("botanical-session-loop"),
|
|
100
|
-
/** Loop operations admitted by
|
|
107
|
+
/** Loop operations admitted by their Agent or Session owner. */
|
|
101
108
|
commands: {
|
|
109
|
+
/** Read an Agent's bounded Loop page, including each destination Session. */
|
|
110
|
+
list: {
|
|
111
|
+
/** The Agent owns the collection of its Sessions' Loops. */
|
|
112
|
+
scope: "agent",
|
|
113
|
+
/** Page strictly after a Session identity, in identity order. */
|
|
114
|
+
input: Schema.Struct({
|
|
115
|
+
/** Exclusive Session cursor. */
|
|
116
|
+
after: Schema.optionalKey(SessionId),
|
|
117
|
+
/** Maximum number of Loop rows to read. */
|
|
118
|
+
limit: Schema.optionalKey(Schema.Int.pipe(Schema.check(Schema.isBetween({ minimum: 1, maximum: 64 })))),
|
|
119
|
+
}),
|
|
120
|
+
/** Public Loop values with Session targets, never private scheduling state. */
|
|
121
|
+
output: Schema.Array(Schema.Struct({
|
|
122
|
+
...Loop.fields,
|
|
123
|
+
/** Session that owns this identified Loop. */
|
|
124
|
+
sessionId: SessionId,
|
|
125
|
+
})).pipe(Schema.check(Schema.isMaxLength(64))),
|
|
126
|
+
},
|
|
127
|
+
/** Pause an identified Loop; refuse a stale target after replacement. */
|
|
128
|
+
pauseLoop: {
|
|
129
|
+
/** The Agent owns the identified Loop and its Session. */
|
|
130
|
+
scope: "agent",
|
|
131
|
+
/** The listed Session and Loop identities must both still match. */
|
|
132
|
+
input: LoopTarget,
|
|
133
|
+
/** Return the paused Loop without cancelling accepted work. */
|
|
134
|
+
output: Loop,
|
|
135
|
+
},
|
|
136
|
+
/** Cancel an identified Loop's future occurrences, retaining accepted work. */
|
|
137
|
+
stopLoop: {
|
|
138
|
+
/** The Agent owns the identified Loop and its Session. */
|
|
139
|
+
scope: "agent",
|
|
140
|
+
/** The listed Session and Loop identities must both still match. */
|
|
141
|
+
input: LoopTarget,
|
|
142
|
+
/** Return the cancelled Loop; its Session and history remain. */
|
|
143
|
+
output: Loop,
|
|
144
|
+
},
|
|
102
145
|
/** Open or answer the human loop controls. */
|
|
103
146
|
loop: {
|
|
104
147
|
/** 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,14 @@ 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
|
+
: stopLoop(ctx, target.sessionId)));
|
|
510
|
+
}
|
|
496
511
|
function cronForInterval(value, unit) {
|
|
497
512
|
if (unit === "m" || unit === "min")
|
|
498
513
|
return value > 59 ? undefined : `0 */${String(value)} * * * *`;
|
|
@@ -662,6 +677,14 @@ export const loopExtension = defineExtension({
|
|
|
662
677
|
commands: {
|
|
663
678
|
specs: loopContract.commands,
|
|
664
679
|
handlers: (ctx) => ({
|
|
680
|
+
pauseLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "pause"),
|
|
681
|
+
stopLoop: ({ input }) => controlIdentifiedLoop(ctx, input, "stop"),
|
|
682
|
+
list: ({ input }) => ctx.state.loops
|
|
683
|
+
.page({ after: input.after, limit: input.limit ?? 64 })
|
|
684
|
+
.pipe(Effect.map((rows) => rows.map((row) => ({
|
|
685
|
+
...projected(row),
|
|
686
|
+
sessionId: row.sessionId,
|
|
687
|
+
})))),
|
|
665
688
|
startSelfPaced: ({ sessionId, input }) => start(ctx, sessionId, input, null),
|
|
666
689
|
startFixedInterval: ({ sessionId, input }) => start(ctx, sessionId, input, {
|
|
667
690
|
expression: input.expression,
|
|
@@ -6,14 +6,24 @@ import type { SubagentSource } from "../subagents/host.js";
|
|
|
6
6
|
/** Host-pack creation admission; attachments/model selection retain their own owners. */
|
|
7
7
|
export declare function assertOrdinaryAgentCreation(input: Parameters<NonNullable<AgentControlDirectory["create"]>>[0]): void;
|
|
8
8
|
/** The directory a conversation sends through; opening a recipient only needs its Sessions' extension doors. */
|
|
9
|
-
type SendingDirectory = Omit<AgentControlDirectory, "open"> & Readonly<{
|
|
9
|
+
export type SendingDirectory = Omit<AgentControlDirectory, "open"> & Readonly<{
|
|
10
|
+
/** Open the recipient's Session extension door for goal adoption. */
|
|
10
11
|
open: (agentId: string, signal: AbortSignal) => Promise<Readonly<{
|
|
12
|
+
/** Recipient Agent with a Session extension door. */
|
|
11
13
|
agent: Readonly<{
|
|
14
|
+
/** Address a recipient Session without loading its conversation. */
|
|
12
15
|
session: (sessionId: string) => Pick<ShiitakeSession, "extension">;
|
|
13
16
|
}>;
|
|
17
|
+
/** Release the acquired recipient without stopping its work. */
|
|
14
18
|
release: () => Promise<void>;
|
|
15
19
|
}>>;
|
|
16
20
|
}>;
|
|
21
|
+
/** Adopt the first accepted turn once, even when the sender was offline at delivery. */
|
|
22
|
+
export declare function adoptDelegatedGoal(session: Pick<ShiitakeSession, "extension">, input: Readonly<{
|
|
23
|
+
text: string;
|
|
24
|
+
goal: string | false | undefined;
|
|
25
|
+
commandId: string;
|
|
26
|
+
}>): Promise<void>;
|
|
17
27
|
/**
|
|
18
28
|
* This host's own record of the Agents each conversation created or sent
|
|
19
29
|
* accepted work to, written as its Agent-control directory accepts them
|
|
@@ -35,4 +45,3 @@ export declare function oysterAgentExtensions(source: SubagentSource): Readonly<
|
|
|
35
45
|
roster: readonly import("@fungi.computer/shiitake").RosteredExtensionV0[];
|
|
36
46
|
grants: readonly import("@fungi.computer/shiitake").ExtensionGrantV0[];
|
|
37
47
|
}>;
|
|
38
|
-
export {};
|
|
@@ -37,6 +37,18 @@ function laneObjective(text, goal) {
|
|
|
37
37
|
.map((line) => line.trim())
|
|
38
38
|
.find((line) => line !== "") ?? text.trim()).slice(0, 4_000);
|
|
39
39
|
}
|
|
40
|
+
/** Adopt the first accepted turn once, even when the sender was offline at delivery. */
|
|
41
|
+
export async function adoptDelegatedGoal(session, input) {
|
|
42
|
+
if (input.goal === false)
|
|
43
|
+
return;
|
|
44
|
+
await bindSessionExtension(session, goalContract).call("set", {
|
|
45
|
+
objective: laneObjective(input.text, input.goal),
|
|
46
|
+
expectedRevision: null,
|
|
47
|
+
requestId: `lane-goal:${input.commandId}`,
|
|
48
|
+
// The delegated prompt is already admitted; never enqueue it twice.
|
|
49
|
+
adoptCommandId: input.commandId,
|
|
50
|
+
});
|
|
51
|
+
}
|
|
40
52
|
/**
|
|
41
53
|
* This host's own record of the Agents each conversation created or sent
|
|
42
54
|
* accepted work to, written as its Agent-control directory accepts them
|
|
@@ -99,12 +111,10 @@ export function createConversationAgents(storage) {
|
|
|
99
111
|
sessionId !== undefined) {
|
|
100
112
|
const opened = await directory.open(task.agentId, signal);
|
|
101
113
|
try {
|
|
102
|
-
await
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
// The send is the lane's first turn; never repeat it.
|
|
107
|
-
adoptCommandId: accepted.commandId,
|
|
114
|
+
await adoptDelegatedGoal(opened.agent.session(sessionId), {
|
|
115
|
+
text: task.text,
|
|
116
|
+
goal: task.goal,
|
|
117
|
+
commandId: accepted.commandId,
|
|
108
118
|
});
|
|
109
119
|
}
|
|
110
120
|
finally {
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { ShiitakeAgent } from "@fungi.computer/shiitake";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
/** Exclusive native key within one Agent's Almanac-then-Loop traversal. */
|
|
5
|
+
export declare const agentScheduleCursorSchema: z.ZodObject<{
|
|
6
|
+
agentId: z.ZodString;
|
|
7
|
+
kind: z.ZodUnion<readonly [z.ZodLiteral<"almanac">, z.ZodLiteral<"loop">]>;
|
|
8
|
+
after: z.ZodOptional<z.ZodString>;
|
|
9
|
+
}, z.core.$strict>;
|
|
10
|
+
/** One bounded read; a full native page conservatively carries continuation. */
|
|
11
|
+
export declare const agentScheduleListInputSchema: z.ZodObject<{
|
|
12
|
+
after: z.ZodOptional<z.ZodObject<{
|
|
13
|
+
agentId: z.ZodString;
|
|
14
|
+
kind: z.ZodUnion<readonly [z.ZodLiteral<"almanac">, z.ZodLiteral<"loop">]>;
|
|
15
|
+
after: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, z.core.$strict>>;
|
|
17
|
+
limit: z.ZodDefault<z.ZodNumber>;
|
|
18
|
+
}, z.core.$strict>;
|
|
19
|
+
/** Content-bearing read projection, decoded by the retained native contracts. */
|
|
20
|
+
export declare const agentScheduleRowSchema: Schema.Union<readonly [Schema.Struct<{
|
|
21
|
+
/** Agent that owns this Almanac schedule. */
|
|
22
|
+
readonly agentId: Schema.String;
|
|
23
|
+
/** Identifies the native Almanac schedule representation. */
|
|
24
|
+
readonly kind: Schema.Literal<"almanac">;
|
|
25
|
+
/** Retained Almanac row, including its instruction and lifecycle state. */
|
|
26
|
+
readonly schedule: Schema.Struct<{
|
|
27
|
+
readonly id: Schema.String;
|
|
28
|
+
readonly sessionId: Schema.String;
|
|
29
|
+
readonly prompt: Schema.String;
|
|
30
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
31
|
+
readonly expression: Schema.String;
|
|
32
|
+
readonly timeZone: Schema.String;
|
|
33
|
+
}>>;
|
|
34
|
+
readonly nextDueAt: Schema.Int;
|
|
35
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "cancelled", "finished"]>;
|
|
36
|
+
readonly lastCommandId: Schema.NullOr<Schema.String>;
|
|
37
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
38
|
+
readonly attempt: Schema.Int;
|
|
39
|
+
}>;
|
|
40
|
+
}>, Schema.Struct<{
|
|
41
|
+
/** Agent that owns this Session's Loop. */
|
|
42
|
+
readonly agentId: Schema.String;
|
|
43
|
+
/** Identifies the native Loop representation. */
|
|
44
|
+
readonly kind: Schema.Literal<"loop">;
|
|
45
|
+
/** Retained Loop row with the Session identity used to address its owner. */
|
|
46
|
+
readonly schedule: Schema.Struct<{
|
|
47
|
+
/** Session containing this exact Loop. */
|
|
48
|
+
readonly sessionId: Schema.String;
|
|
49
|
+
readonly loopId: Schema.String;
|
|
50
|
+
readonly origin: Schema.Literals<readonly ["human", "model"]>;
|
|
51
|
+
readonly expiresAt: Schema.NullOr<Schema.Int>;
|
|
52
|
+
readonly prompt: Schema.String;
|
|
53
|
+
readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
|
|
54
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
55
|
+
readonly expression: Schema.String;
|
|
56
|
+
readonly timeZone: Schema.String;
|
|
57
|
+
}>>;
|
|
58
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
|
|
59
|
+
readonly commandId: Schema.String;
|
|
60
|
+
readonly reason: Schema.NullOr<Schema.String>;
|
|
61
|
+
readonly nextDueAt: Schema.NullOr<Schema.Int>;
|
|
62
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
63
|
+
readonly consecutiveFailures: Schema.Int;
|
|
64
|
+
}>;
|
|
65
|
+
}>]>;
|
|
66
|
+
/** One Agent's retained schedule, including its native content. */
|
|
67
|
+
export type AgentScheduleRow = typeof agentScheduleRowSchema.Type;
|
|
68
|
+
/** Exact listed identity; a Loop target never selects its later replacement. */
|
|
69
|
+
export declare const agentScheduleTargetSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
70
|
+
kind: z.ZodLiteral<"almanac">;
|
|
71
|
+
agentId: z.ZodString;
|
|
72
|
+
scheduleId: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
73
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
74
|
+
kind: z.ZodLiteral<"loop">;
|
|
75
|
+
agentId: z.ZodString;
|
|
76
|
+
sessionId: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
77
|
+
loopId: z.ZodString & z.ZodType<string, string, z.core.$ZodTypeInternals<string, string>>;
|
|
78
|
+
}, z.core.$strict>], "kind">;
|
|
79
|
+
/** Identity to admit before acquiring the corresponding Agent owner. */
|
|
80
|
+
export type AgentScheduleTarget = z.output<typeof agentScheduleTargetSchema>;
|
|
81
|
+
/** A bounded content-bearing page; owner failures reject rather than look empty. */
|
|
82
|
+
export declare const agentSchedulePageSchema: Schema.Struct<{
|
|
83
|
+
/** At most 64 retained rows, ordered Almanac first and then Loop. */
|
|
84
|
+
readonly items: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
85
|
+
/** Agent that owns this Almanac schedule. */
|
|
86
|
+
readonly agentId: Schema.String;
|
|
87
|
+
/** Identifies the native Almanac schedule representation. */
|
|
88
|
+
readonly kind: Schema.Literal<"almanac">;
|
|
89
|
+
/** Retained Almanac row, including its instruction and lifecycle state. */
|
|
90
|
+
readonly schedule: Schema.Struct<{
|
|
91
|
+
readonly id: Schema.String;
|
|
92
|
+
readonly sessionId: Schema.String;
|
|
93
|
+
readonly prompt: Schema.String;
|
|
94
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
95
|
+
readonly expression: Schema.String;
|
|
96
|
+
readonly timeZone: Schema.String;
|
|
97
|
+
}>>;
|
|
98
|
+
readonly nextDueAt: Schema.Int;
|
|
99
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "cancelled", "finished"]>;
|
|
100
|
+
readonly lastCommandId: Schema.NullOr<Schema.String>;
|
|
101
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
102
|
+
readonly attempt: Schema.Int;
|
|
103
|
+
}>;
|
|
104
|
+
}>, Schema.Struct<{
|
|
105
|
+
/** Agent that owns this Session's Loop. */
|
|
106
|
+
readonly agentId: Schema.String;
|
|
107
|
+
/** Identifies the native Loop representation. */
|
|
108
|
+
readonly kind: Schema.Literal<"loop">;
|
|
109
|
+
/** Retained Loop row with the Session identity used to address its owner. */
|
|
110
|
+
readonly schedule: Schema.Struct<{
|
|
111
|
+
/** Session containing this exact Loop. */
|
|
112
|
+
readonly sessionId: Schema.String;
|
|
113
|
+
readonly loopId: Schema.String;
|
|
114
|
+
readonly origin: Schema.Literals<readonly ["human", "model"]>;
|
|
115
|
+
readonly expiresAt: Schema.NullOr<Schema.Int>;
|
|
116
|
+
readonly prompt: Schema.String;
|
|
117
|
+
readonly mode: Schema.Literals<readonly ["self_paced", "fixed_interval"]>;
|
|
118
|
+
readonly cron: Schema.NullOr<Schema.Struct<{
|
|
119
|
+
readonly expression: Schema.String;
|
|
120
|
+
readonly timeZone: Schema.String;
|
|
121
|
+
}>>;
|
|
122
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
|
|
123
|
+
readonly commandId: Schema.String;
|
|
124
|
+
readonly reason: Schema.NullOr<Schema.String>;
|
|
125
|
+
readonly nextDueAt: Schema.NullOr<Schema.Int>;
|
|
126
|
+
readonly lastError: Schema.NullOr<Schema.String>;
|
|
127
|
+
readonly consecutiveFailures: Schema.Int;
|
|
128
|
+
}>;
|
|
129
|
+
}>]>>;
|
|
130
|
+
/** Exclusive continuation on a full page, or null when both kinds are exhausted. */
|
|
131
|
+
readonly next: Schema.NullOr<Schema.Struct<{
|
|
132
|
+
/** Agent whose traversal the next request must continue. */
|
|
133
|
+
readonly agentId: Schema.String;
|
|
134
|
+
/** Native owner to continue within that Agent. */
|
|
135
|
+
readonly kind: Schema.Literals<readonly ["almanac", "loop"]>;
|
|
136
|
+
/** Exclusive schedule ID or Session ID; absent starts the native kind. */
|
|
137
|
+
readonly after: Schema.optionalKey<Schema.String>;
|
|
138
|
+
}>>;
|
|
139
|
+
}>;
|
|
140
|
+
/** One Agent's page, with no directory fan-out or availability policy. */
|
|
141
|
+
export type AgentSchedulePage = typeof agentSchedulePageSchema.Type;
|
|
142
|
+
/** Manage-only result: exact target and native state, never prompt or history. */
|
|
143
|
+
export declare const agentScheduleControlReceiptSchema: Schema.Union<readonly [Schema.Struct<{
|
|
144
|
+
/** Agent whose Almanac owner completed the transition. */
|
|
145
|
+
readonly agentId: Schema.String;
|
|
146
|
+
/** Identifies the controlled native Almanac schedule. */
|
|
147
|
+
readonly kind: Schema.Literal<"almanac">;
|
|
148
|
+
/** Identity of the schedule that was paused or cancelled. */
|
|
149
|
+
readonly scheduleId: Schema.String;
|
|
150
|
+
/** Native lifecycle state returned after the transition. */
|
|
151
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "cancelled", "finished"]>;
|
|
152
|
+
}>, Schema.Struct<{
|
|
153
|
+
/** Agent whose Loop owner completed the transition. */
|
|
154
|
+
readonly agentId: Schema.String;
|
|
155
|
+
/** Identifies the controlled native Loop. */
|
|
156
|
+
readonly kind: Schema.Literal<"loop">;
|
|
157
|
+
/** Session containing the controlled Loop. */
|
|
158
|
+
readonly sessionId: Schema.String;
|
|
159
|
+
/** Exact Loop identity checked by the native transition. */
|
|
160
|
+
readonly loopId: Schema.String;
|
|
161
|
+
/** Native lifecycle state returned after the transition. */
|
|
162
|
+
readonly state: Schema.Literals<readonly ["active", "paused", "finished", "failed", "cancelled"]>;
|
|
163
|
+
}>]>;
|
|
164
|
+
/** Content-free acknowledgement of the native owner's completed transition. */
|
|
165
|
+
export type AgentScheduleControlReceipt = typeof agentScheduleControlReceiptSchema.Type;
|
|
166
|
+
/**
|
|
167
|
+
* Read one already-admitted Agent, without scanning Sessions or draining pages.
|
|
168
|
+
* The caller owns Agent, home and resource authorization and the owner's lifetime.
|
|
169
|
+
*/
|
|
170
|
+
export declare function readAgentSchedulePage(agentId: string, owner: Pick<ShiitakeAgent, "extensions">, input?: z.input<typeof agentScheduleListInputSchema>): Promise<AgentSchedulePage>;
|
|
171
|
+
/**
|
|
172
|
+
* Explicit content-returning control for callers admitted to both read and manage.
|
|
173
|
+
* In particular, private Local retains its native-row reply. The supplied owner
|
|
174
|
+
* must already be admitted for target.agentId; this helper grants no authority.
|
|
175
|
+
*/
|
|
176
|
+
export declare function controlAgentScheduleWithContent(owner: Pick<ShiitakeAgent, "extensions">, input: AgentScheduleTarget, action: "pause" | "delete"): Promise<AgentScheduleRow>;
|
|
177
|
+
/** Control an already-admitted owner; manage-only callers receive no read content. */
|
|
178
|
+
export declare function controlAgentSchedule(owner: Pick<ShiitakeAgent, "extensions">, target: AgentScheduleTarget, action: "pause" | "delete"): Promise<AgentScheduleControlReceipt>;
|