@fungi.computer/shiitake 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.
Files changed (68) hide show
  1. package/README.md +1 -10
  2. package/dist/agent-control.d.ts +98 -5
  3. package/dist/agent-control.js +111 -8
  4. package/dist/client-entry.d.ts +20 -0
  5. package/dist/client-entry.js +5 -0
  6. package/dist/client-visitor.d.ts +31 -0
  7. package/dist/client-visitor.js +226 -0
  8. package/dist/client-wire.d.ts +5 -0
  9. package/dist/client-wire.js +6 -0
  10. package/dist/client.d.ts +4 -3
  11. package/dist/client.js +1 -0
  12. package/dist/delegation.d.ts +100 -77
  13. package/dist/delegation.js +73 -23
  14. package/dist/effect.d.ts +25 -0
  15. package/dist/effect.js +14 -1
  16. package/dist/extensions.d.ts +21 -2
  17. package/dist/extensions.js +1 -1
  18. package/dist/fleet.d.ts +22 -2
  19. package/dist/fleet.js +127 -36
  20. package/dist/hosted.js +3 -0
  21. package/dist/http-routes.d.ts +11 -0
  22. package/dist/internal/accepted-run-executor.js +2 -1
  23. package/dist/internal/admission-door.d.ts +5 -0
  24. package/dist/internal/admission-door.js +34 -3
  25. package/dist/internal/contracts.d.ts +14 -1
  26. package/dist/internal/coordinator.js +8 -2
  27. package/dist/internal/effect-client.js +1 -1
  28. package/dist/internal/effect-contracts.d.ts +4 -2
  29. package/dist/internal/extension-command-registry.d.ts +2 -1
  30. package/dist/internal/extension-command-registry.js +3 -1
  31. package/dist/internal/extension-runtime.d.ts +3 -1
  32. package/dist/internal/extension-runtime.js +13 -5
  33. package/dist/internal/model-acquisition.js +2 -0
  34. package/dist/internal/observation-kernel.d.ts +2 -0
  35. package/dist/internal/observation-kernel.js +17 -6
  36. package/dist/internal/run-scope.d.ts +14 -0
  37. package/dist/internal/run-scope.js +32 -9
  38. package/dist/internal/runtime-coordinator.js +8 -1
  39. package/dist/internal/runtime-reconciliation.js +119 -24
  40. package/dist/internal/woodstock/agent-reply.d.ts +5 -0
  41. package/dist/internal/woodstock/agent-reply.js +3 -0
  42. package/dist/internal/woodstock/client-projection.js +9 -1
  43. package/dist/internal/woodstock/fleet-store.d.ts +1 -0
  44. package/dist/internal/woodstock/fleet-store.js +28 -1
  45. package/dist/internal/woodstock/index.d.ts +4 -0
  46. package/dist/internal/woodstock/index.js +7 -0
  47. package/dist/internal/woodstock/session-delegator.d.ts +12 -0
  48. package/dist/internal/woodstock/session-delegator.js +44 -0
  49. package/dist/internal/woodstock/session-entry.d.ts +12 -2
  50. package/dist/internal/woodstock/session-store.d.ts +2 -0
  51. package/dist/internal/woodstock/session-store.js +20 -0
  52. package/dist/internal/woodstock/work-senders.d.ts +32 -0
  53. package/dist/internal/woodstock/work-senders.js +70 -0
  54. package/dist/remote-client.js +7 -2
  55. package/dist/server-visitor-stream.d.ts +13 -0
  56. package/dist/server-visitor-stream.js +115 -0
  57. package/dist/session-attention.d.ts +30 -0
  58. package/dist/session-attention.js +14 -0
  59. package/docs/api/agent-control.md +209 -13
  60. package/docs/api/client-entry.md +3 -0
  61. package/docs/api/client.md +136 -1
  62. package/docs/api/cloudflare.md +7 -1
  63. package/docs/api/delegation.md +234 -61
  64. package/docs/api/effect.md +16 -6
  65. package/docs/api/extensions.md +65 -4
  66. package/docs/api/fleet.md +69 -16
  67. package/docs/api/index.md +6 -4
  68. package/package.json +10 -6
@@ -282,10 +282,16 @@ export function parseForkedSession(value) {
282
282
  /** Exact command facts shared by Session clients and host fleet transports. */
283
283
  export const commandSettlementSchema = Schema.Struct({
284
284
  acceptedSender: Schema.NullOr(Schema.String),
285
+ delegator: Schema.NullOr(Schema.String),
285
286
  terminal: SessionTerminalSchema,
286
287
  content: Schema.String,
287
288
  usage: Schema.Array(Schema.Struct({ provider: Schema.String, model: Schema.String, usage })),
288
289
  toolCalls: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
290
+ waitingOnYou: Schema.Array(Schema.Struct({
291
+ itemId: Schema.String,
292
+ kind: Schema.String,
293
+ summary: Schema.String,
294
+ })).check(Schema.isMaxLength(8)),
289
295
  });
290
296
  /** A timeout is null on the JSON wire and undefined at the client boundary. */
291
297
  export function parseCommandSettlement(value) {
package/dist/client.d.ts CHANGED
@@ -5,12 +5,13 @@ export { type SessionAttention } from "./session-attention.js";
5
5
  import type { SandboxFailureEvent } from "@fungi.computer/mycelium";
6
6
  import type { ModelPreference } from "./internal/model-preference.js";
7
7
  import type { Message } from "@fungi.computer/mule/effect";
8
- import type { ExtensionSlotV0, ExtensionStatusV0, Json } from "./extensions.js";
8
+ import type { ExtensionCommandCallerV0, ExtensionSlotV0, ExtensionStatusV0, Json } from "./extensions.js";
9
9
  import type { AbortCommand, BranchCommand, CompactCommand, OperatorCommand, TitleCommand, CancelCommand, ForkCommand, PromptCommand, PromptDelivery, SessionCommand } from "./internal/client-boundary.js";
10
10
  export { createShiitakeClient, type ShiitakeClientOptions, } from "./remote-client.js";
11
11
  export { bindAgentExtension, bindSessionExtension, type BoundAgentExtensionV0, type BoundCallV0, type BoundSessionExtensionV0, type ExtensionViewV0, type ScopedCommandsV0, } from "./extension-client.js";
12
12
  export { AcceptedSchema, DelegationReceiptSchema, HeldSchema, parseAccepted, parseDelegationReceipt, parseCancelResult, parseLatestPendingPrompt, parseWithdrawResult, parseForkedSession, parseSessionFrame, parseSessionSnapshot, parseSessionSummaryPage, parseShiitakeError, } from "./client-wire.js";
13
13
  export type { AbortCommand, BranchCommand, CompactCommand, CancelCommand, ForkCommand, OperatorCommand, PromptCommand, PromptDelivery, SessionCommand, TitleCommand, } from "./internal/client-boundary.js";
14
+ export { participantSnapshot, visitorPendingPrompt, visitorSnapshot, visitorView, type ParticipantPolicy, type VisitorPendingPrompt, type VisitorView, } from "./client-visitor.js";
14
15
  /** Semantic acknowledgement returned after one durable acceptance commit. */
15
16
  export type Accepted = Readonly<{
16
17
  /** Indicates that the owner transaction committed. */
@@ -185,8 +186,8 @@ export type SessionActivity = Readonly<{
185
186
  export type SessionExtensionSlots = Readonly<Record<string, ExtensionSlotV0>>;
186
187
  /** Generic Session-scope extension commands. */
187
188
  export type SessionExtensionControls = Readonly<{
188
- /** Call one Session-scope command with its encoded input; resolves the encoded output. */
189
- call: (command: string, input: Json) => Promise<Json>;
189
+ /** Call one Session-scope command with its encoded input and optional host caller. */
190
+ call: (command: string, input: Json, caller?: ExtensionCommandCallerV0) => Promise<Json>;
190
191
  }>;
191
192
  /** Generic Agent-scope extension controls. */
192
193
  export type AgentExtensionControls = Readonly<{
package/dist/client.js CHANGED
@@ -2,3 +2,4 @@ export {} from "./session-attention.js";
2
2
  export { createShiitakeClient, } from "./remote-client.js";
3
3
  export { bindAgentExtension, bindSessionExtension, } from "./extension-client.js";
4
4
  export { AcceptedSchema, DelegationReceiptSchema, HeldSchema, parseAccepted, parseDelegationReceipt, parseCancelResult, parseLatestPendingPrompt, parseWithdrawResult, parseForkedSession, parseSessionFrame, parseSessionSnapshot, parseSessionSummaryPage, parseShiitakeError, } from "./client-wire.js";
5
+ export { participantSnapshot, visitorPendingPrompt, visitorSnapshot, visitorView, } from "./client-visitor.js";
@@ -1,7 +1,7 @@
1
1
  import type { WatchdogSqliteOwner } from "@fungi.computer/watchdog";
2
2
  import * as Schema from "effect/Schema";
3
3
  import { type BirdDogEffect } from "@fungi.computer/bird-dog/effect";
4
- import type { BirdDogMail } from "@fungi.computer/bird-dog";
4
+ import { type BirdDogMail } from "@fungi.computer/bird-dog";
5
5
  import { type PostRoute, type PostRuntime, type PostEnvelope, type PostDeliveryResult } from "@fungi.computer/carrier/post";
6
6
  import { type Accepted, type DelegationReceipt, type CancelResult } from "./client.js";
7
7
  import type { CommandSettlement, ShiitakeHost, VerifiedAgentReply } from "./index.js";
@@ -34,15 +34,15 @@ export declare class AgentDelegation {
34
34
  private scope;
35
35
  /** Recipient-local disclosure through the public host, never another Agent's RPC. */
36
36
  settlement(sender: DelegationIdentity, sessionId: string, commandId: string, host: Pick<ShiitakeHost, "readSettlement">): Promise<CommandSettlement | undefined>;
37
- /** Delegate work to an in-scope Agent: steer its Session, or start fleet correspondence. */
37
+ /** Delegate work to an in-scope Agent through fleet correspondence; a steer rides the mail. */
38
38
  send(input: AgentDelegationInput, sourceSessionId: string, signal: AbortSignal, invocation?: AgentDelegationInvocation): Promise<DelegationReceipt>;
39
39
  /** Resolve this sender's exact request, then let the recipient guard pending work. */
40
40
  recall(input: AgentRecallInput, sourceSessionId: string, signal: AbortSignal): Promise<CancelResult>;
41
41
  /**
42
42
  * A reply-less envelope is only ever BirdDog's reply to work this Agent
43
43
  * sent. Admit it only after the fleet authenticates it against that frozen
44
- * mail; the line is then authored by the replying Agent, never by whoever
45
- * settled or cancelled the work, and its meta carries the verified reply.
44
+ * mail. A recipient-left reply remains Agent-authored; a recipient-offline
45
+ * reply is Hub-authored. Its meta carries only the authenticated reply.
46
46
  */
47
47
  private authenticatedReply;
48
48
  private parseAddressedMail;
@@ -50,6 +50,8 @@ export declare class AgentDelegation {
50
50
  receive(raw: PostEnvelope): Promise<PostDeliveryResult>;
51
51
  private recordAcceptedNotice;
52
52
  private acceptAdmitted;
53
+ /** Admit local outbox exhaustion through the same Fleet/system reply gate. */
54
+ localUndeliverable(original: BirdDogMail): Promise<PostDeliveryResult>;
53
55
  }
54
56
  /** A current correspondent no longer has disclosure authority. */
55
57
  export declare class AgentDisclosureRefused extends Error {
@@ -61,15 +63,9 @@ export type AgentReplySettlement = (mail: BirdDogMail) => Promise<CommandSettlem
61
63
  export declare function agentMailRoute(namespace: PostRoute<never, never>["namespace"], replySettlement: AgentReplySettlement): PostRoute<import("@fungi.computer/seam/machine-link-protocol").AgentMailAddress, {
62
64
  readonly key: string;
63
65
  readonly content: string;
64
- readonly createdAt: number;
65
- readonly from: {
66
- readonly kind: "agent";
67
- readonly agentId: string;
68
- readonly sessionId: string;
69
- };
70
66
  readonly to: {
71
- readonly kind: "agent";
72
67
  readonly agentId: string;
68
+ readonly kind: "agent";
73
69
  readonly sessionId?: string;
74
70
  };
75
71
  readonly replyTo: readonly {
@@ -77,34 +73,39 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
77
73
  readonly agentId: string;
78
74
  readonly sessionId: string;
79
75
  }[];
76
+ readonly createdAt: number;
77
+ readonly from: {
78
+ readonly kind: "agent";
79
+ readonly agentId: string;
80
+ readonly sessionId: string;
81
+ };
80
82
  readonly meta?: Schema.Json;
81
83
  readonly reply?: {
82
84
  readonly commandId: string;
83
85
  readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
84
86
  readonly diagnostic?: string;
85
- } | {
86
- readonly outcome: "undeliverable";
87
- readonly reason: "recipient_offline" | "recipient_left";
87
+ readonly waitingOnYou?: readonly {
88
+ readonly itemId: string;
89
+ readonly kind: string;
90
+ readonly summary: string;
91
+ }[];
88
92
  } | {
89
93
  readonly outcome: "accepted";
90
94
  readonly commandId: string;
95
+ } | {
96
+ readonly outcome: "undeliverable";
97
+ readonly reason: "recipient_left";
91
98
  };
92
99
  } | {
93
100
  readonly key: string;
94
101
  readonly reply: {
95
102
  readonly outcome: "undeliverable";
96
- readonly reason: "recipient_offline" | "recipient_left";
103
+ readonly reason: "recipient_offline";
97
104
  };
98
105
  readonly content: string;
99
- readonly createdAt: number;
100
- readonly from: {
101
- readonly kind: "agent";
102
- readonly agentId: string;
103
- readonly sessionId?: string;
104
- };
105
106
  readonly to: {
106
- readonly kind: "agent";
107
107
  readonly agentId: string;
108
+ readonly kind: "agent";
108
109
  readonly sessionId?: string;
109
110
  };
110
111
  readonly replyTo: readonly {
@@ -112,19 +113,18 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
112
113
  readonly agentId: string;
113
114
  readonly sessionId: string;
114
115
  }[];
116
+ readonly createdAt: number;
117
+ readonly from: {
118
+ readonly kind: "system";
119
+ readonly systemId: "hub";
120
+ };
115
121
  readonly meta?: Schema.Json;
116
122
  }, {
117
123
  readonly key: string;
118
124
  readonly content: string;
119
- readonly createdAt: number;
120
- readonly from: {
121
- readonly kind: "agent";
122
- readonly agentId: string;
123
- readonly sessionId: string;
124
- };
125
125
  readonly to: {
126
- readonly kind: "agent";
127
126
  readonly agentId: string;
127
+ readonly kind: "agent";
128
128
  readonly sessionId?: string;
129
129
  };
130
130
  readonly replyTo: readonly {
@@ -132,34 +132,39 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
132
132
  readonly agentId: string;
133
133
  readonly sessionId: string;
134
134
  }[];
135
+ readonly createdAt: number;
136
+ readonly from: {
137
+ readonly kind: "agent";
138
+ readonly agentId: string;
139
+ readonly sessionId: string;
140
+ };
135
141
  readonly meta?: Schema.Json;
136
142
  readonly reply?: {
137
143
  readonly commandId: string;
138
144
  readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
139
145
  readonly diagnostic?: string;
140
- } | {
141
- readonly outcome: "undeliverable";
142
- readonly reason: "recipient_offline" | "recipient_left";
146
+ readonly waitingOnYou?: readonly {
147
+ readonly itemId: string;
148
+ readonly kind: string;
149
+ readonly summary: string;
150
+ }[];
143
151
  } | {
144
152
  readonly outcome: "accepted";
145
153
  readonly commandId: string;
154
+ } | {
155
+ readonly outcome: "undeliverable";
156
+ readonly reason: "recipient_left";
146
157
  };
147
158
  } | {
148
159
  readonly key: string;
149
160
  readonly reply: {
150
161
  readonly outcome: "undeliverable";
151
- readonly reason: "recipient_offline" | "recipient_left";
162
+ readonly reason: "recipient_offline";
152
163
  };
153
164
  readonly content: string;
154
- readonly createdAt: number;
155
- readonly from: {
156
- readonly kind: "agent";
157
- readonly agentId: string;
158
- readonly sessionId?: string;
159
- };
160
165
  readonly to: {
161
- readonly kind: "agent";
162
166
  readonly agentId: string;
167
+ readonly kind: "agent";
163
168
  readonly sessionId?: string;
164
169
  };
165
170
  readonly replyTo: readonly {
@@ -167,19 +172,18 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
167
172
  readonly agentId: string;
168
173
  readonly sessionId: string;
169
174
  }[];
175
+ readonly createdAt: number;
176
+ readonly from: {
177
+ readonly kind: "system";
178
+ readonly systemId: "hub";
179
+ };
170
180
  readonly meta?: Schema.Json;
171
181
  }, import("@fungi.computer/seam/machine-link-protocol").AgentMailAddress, {
172
182
  readonly key: string;
173
183
  readonly content: string;
174
- readonly createdAt: number;
175
- readonly from: {
176
- readonly kind: "agent";
177
- readonly agentId: string;
178
- readonly sessionId: string;
179
- };
180
184
  readonly to: {
181
- readonly kind: "agent";
182
185
  readonly agentId: string;
186
+ readonly kind: "agent";
183
187
  readonly sessionId?: string;
184
188
  };
185
189
  readonly replyTo: readonly {
@@ -187,34 +191,39 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
187
191
  readonly agentId: string;
188
192
  readonly sessionId: string;
189
193
  }[];
194
+ readonly createdAt: number;
195
+ readonly from: {
196
+ readonly kind: "agent";
197
+ readonly agentId: string;
198
+ readonly sessionId: string;
199
+ };
190
200
  readonly meta?: Schema.Json;
191
201
  readonly reply?: {
192
202
  readonly commandId: string;
193
203
  readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
194
204
  readonly diagnostic?: string;
195
- } | {
196
- readonly outcome: "undeliverable";
197
- readonly reason: "recipient_offline" | "recipient_left";
205
+ readonly waitingOnYou?: readonly {
206
+ readonly itemId: string;
207
+ readonly kind: string;
208
+ readonly summary: string;
209
+ }[];
198
210
  } | {
199
211
  readonly outcome: "accepted";
200
212
  readonly commandId: string;
213
+ } | {
214
+ readonly outcome: "undeliverable";
215
+ readonly reason: "recipient_left";
201
216
  };
202
217
  } | {
203
218
  readonly key: string;
204
219
  readonly reply: {
205
220
  readonly outcome: "undeliverable";
206
- readonly reason: "recipient_offline" | "recipient_left";
221
+ readonly reason: "recipient_offline";
207
222
  };
208
223
  readonly content: string;
209
- readonly createdAt: number;
210
- readonly from: {
211
- readonly kind: "agent";
212
- readonly agentId: string;
213
- readonly sessionId?: string;
214
- };
215
224
  readonly to: {
216
- readonly kind: "agent";
217
225
  readonly agentId: string;
226
+ readonly kind: "agent";
218
227
  readonly sessionId?: string;
219
228
  };
220
229
  readonly replyTo: readonly {
@@ -222,19 +231,18 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
222
231
  readonly agentId: string;
223
232
  readonly sessionId: string;
224
233
  }[];
234
+ readonly createdAt: number;
235
+ readonly from: {
236
+ readonly kind: "system";
237
+ readonly systemId: "hub";
238
+ };
225
239
  readonly meta?: Schema.Json;
226
240
  }, {
227
241
  readonly key: string;
228
242
  readonly content: string;
229
- readonly createdAt: number;
230
- readonly from: {
231
- readonly kind: "agent";
232
- readonly agentId: string;
233
- readonly sessionId: string;
234
- };
235
243
  readonly to: {
236
- readonly kind: "agent";
237
244
  readonly agentId: string;
245
+ readonly kind: "agent";
238
246
  readonly sessionId?: string;
239
247
  };
240
248
  readonly replyTo: readonly {
@@ -242,34 +250,39 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
242
250
  readonly agentId: string;
243
251
  readonly sessionId: string;
244
252
  }[];
253
+ readonly createdAt: number;
254
+ readonly from: {
255
+ readonly kind: "agent";
256
+ readonly agentId: string;
257
+ readonly sessionId: string;
258
+ };
245
259
  readonly meta?: Schema.Json;
246
260
  readonly reply?: {
247
261
  readonly commandId: string;
248
262
  readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
249
263
  readonly diagnostic?: string;
250
- } | {
251
- readonly outcome: "undeliverable";
252
- readonly reason: "recipient_offline" | "recipient_left";
264
+ readonly waitingOnYou?: readonly {
265
+ readonly itemId: string;
266
+ readonly kind: string;
267
+ readonly summary: string;
268
+ }[];
253
269
  } | {
254
270
  readonly outcome: "accepted";
255
271
  readonly commandId: string;
272
+ } | {
273
+ readonly outcome: "undeliverable";
274
+ readonly reason: "recipient_left";
256
275
  };
257
276
  } | {
258
277
  readonly key: string;
259
278
  readonly reply: {
260
279
  readonly outcome: "undeliverable";
261
- readonly reason: "recipient_offline" | "recipient_left";
280
+ readonly reason: "recipient_offline";
262
281
  };
263
282
  readonly content: string;
264
- readonly createdAt: number;
265
- readonly from: {
266
- readonly kind: "agent";
267
- readonly agentId: string;
268
- readonly sessionId?: string;
269
- };
270
283
  readonly to: {
271
- readonly kind: "agent";
272
284
  readonly agentId: string;
285
+ readonly kind: "agent";
273
286
  readonly sessionId?: string;
274
287
  };
275
288
  readonly replyTo: readonly {
@@ -277,6 +290,11 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
277
290
  readonly agentId: string;
278
291
  readonly sessionId: string;
279
292
  }[];
293
+ readonly createdAt: number;
294
+ readonly from: {
295
+ readonly kind: "system";
296
+ readonly systemId: "hub";
297
+ };
280
298
  readonly meta?: Schema.Json;
281
299
  }> & Omit<Readonly<{
282
300
  addressKind: string;
@@ -295,7 +313,7 @@ export declare function agentMailRoute(namespace: PostRoute<never, never>["names
295
313
  /** The host's one Post lane, as Agent mail borrows it. */
296
314
  export type AgentMailPost = Pick<PostRuntime<{
297
315
  agentMail: ReturnType<typeof agentMailRoute>;
298
- }>, "send" | "read" | "nextWake">;
316
+ }>, "send" | "read" | "nextWake" | "deadLetters">;
299
317
  /** Recipient-owned replies and receipt-bearing submissions over the host's one Post lane. */
300
318
  export declare class AgentMail {
301
319
  private readonly deps;
@@ -305,16 +323,21 @@ export declare class AgentMail {
305
323
  identity: () => DelegationIdentity | null | Promise<DelegationIdentity | null>;
306
324
  /** Only a typed disclosure refusal becomes undefined; missing settled facts must fail. */
307
325
  replySettlement: AgentReplySettlement;
326
+ /** Route a terminal reply for this sender through its Fleet admission. */
327
+ onUndeliverable: (original: BirdDogMail, reply: BirdDogMail) => Promise<PostDeliveryResult>;
308
328
  drain: () => Promise<void>;
309
329
  wake: () => Promise<void>;
310
330
  }>);
311
331
  private envelope;
312
332
  /** Submit one mail and return recipient acceptance or relay-held custody. */
313
333
  send(mail: BirdDogMail): Promise<DelegationReceipt>;
334
+ /** Reconcile exhausted original outbox mail into one local system reply. */
335
+ stageUndeliverableReplies(): Promise<void>;
314
336
  /** Stage the acceptance reply through this Post owner without leaving the transaction. */
315
337
  stageAcceptedNotice(mail: BirdDogMail, scopeId: string): void;
316
338
  /** BirdDog's mail room: disclosed settlement replies fan out over Post. */
317
339
  mailRoom(): BirdDogEffect & {
340
+ /** Stage acceptance through this Post owner within the caller's transaction. */
318
341
  stageAcceptedNotice: (mail: BirdDogMail, scopeId: string) => void;
319
342
  };
320
343
  }
@@ -3,12 +3,13 @@
3
3
  * addressed Agent mail over Carrier Post, and the Agent grammar a host hands
4
4
  * to Oyster's machine link as ports. Oyster core never imports this engine.
5
5
  */
6
- import { commandSettlementSchema, createAgentDirectory, createFleetCorrespondence, agentDelegationRequestKey, delegationProvenance, delegationReplyMeta, delegationSendMeta, } from "./fleet.js";
6
+ import { commandSettlementSchema, createAgentDirectory, createFleetCorrespondence, agentDelegationRequestKey, delegationProvenance, delegationReplyMeta, delegationSendMeta, settlementReadableBy, } from "./fleet.js";
7
7
  import * as Schema from "effect/Schema";
8
8
  import { agentMailAddressSchema } from "@fungi.computer/seam/machine-link-protocol";
9
9
  import { BirdDogMailSchema, BirdDogError, settlementReplies, } from "@fungi.computer/bird-dog/effect";
10
10
  import * as Effect from "effect/Effect";
11
11
  import { messageAuthor } from "@fungi.computer/agar/agents";
12
+ import { undeliverableReply } from "@fungi.computer/bird-dog";
12
13
  import { PostEnvelopeSchema, definePostRoute, } from "@fungi.computer/carrier/post";
13
14
  import { parseDelegationReceipt, } from "./client.js";
14
15
  import { decodeClientSessionCreationRequest } from "./internal/client-boundary.js";
@@ -43,11 +44,11 @@ export class AgentDelegation {
43
44
  !scope.agents.some(({ agentId }) => agentId === sender.agentId))
44
45
  throw new AgentDisclosureRefused();
45
46
  const facts = await host.readSettlement(sessionId, commandId);
46
- if (facts !== undefined && facts.acceptedSender !== sender.agentId)
47
+ if (facts !== undefined && !settlementReadableBy(facts, sender.agentId))
47
48
  throw new AgentDisclosureRefused();
48
49
  return facts;
49
50
  }
50
- /** Delegate work to an in-scope Agent: steer its Session, or start fleet correspondence. */
51
+ /** Delegate work to an in-scope Agent through fleet correspondence; a steer rides the mail. */
51
52
  async send(input, sourceSessionId, signal, invocation) {
52
53
  if (invocation === undefined)
53
54
  throw new Error("Delegation requires a tool invocation");
@@ -65,18 +66,6 @@ export class AgentDelegation {
65
66
  requestId: input.requestId,
66
67
  });
67
68
  signal.throwIfAborted();
68
- if (input.delivery === "steer") {
69
- const opened = await this.deps.directory().open(input.agentId, signal);
70
- try {
71
- return await opened.agent.session(input.sessionId).send(input.text, {
72
- requestId,
73
- delivery: "steer",
74
- });
75
- }
76
- finally {
77
- await opened.release();
78
- }
79
- }
80
69
  const provenance = await delegationProvenance({
81
70
  agentId: scope.agentId,
82
71
  sessionId: sourceSessionId,
@@ -92,6 +81,7 @@ export class AgentDelegation {
92
81
  }, {
93
82
  agentId: input.agentId,
94
83
  sessionId: input.sessionId,
84
+ delivery: input.delivery,
95
85
  text: input.text,
96
86
  requestId,
97
87
  });
@@ -135,8 +125,8 @@ export class AgentDelegation {
135
125
  /**
136
126
  * A reply-less envelope is only ever BirdDog's reply to work this Agent
137
127
  * sent. Admit it only after the fleet authenticates it against that frozen
138
- * mail; the line is then authored by the replying Agent, never by whoever
139
- * settled or cancelled the work, and its meta carries the verified reply.
128
+ * mail. A recipient-left reply remains Agent-authored; a recipient-offline
129
+ * reply is Hub-authored. Its meta carries only the authenticated reply.
140
130
  */
141
131
  async authenticatedReply(mail) {
142
132
  const delegation = this.fleet().authenticateReply(mail);
@@ -173,19 +163,21 @@ export class AgentDelegation {
173
163
  let authenticated;
174
164
  const valid = async () => {
175
165
  const scope = await this.scope(new AbortController().signal);
176
- const frozenUndeliverable = authenticated?.reply.outcome === "undeliverable" &&
177
- authenticated.reply.agentId === mail.from.agentId;
166
+ const sender = mail.from;
167
+ const authenticatedUndeliverable = authenticated?.reply.outcome === "undeliverable";
178
168
  return (address.scopeId === scope.scopeId &&
179
169
  address.agentId === scope.agentId &&
180
170
  mail.to.agentId === scope.agentId &&
181
171
  envelope.key === mail.key &&
182
- (frozenUndeliverable ||
183
- scope.agents.some(({ agentId }) => agentId === mail.from.agentId)) &&
172
+ (authenticatedUndeliverable ||
173
+ (sender.kind === "agent" &&
174
+ scope.agents.some(({ agentId }) => agentId === sender.agentId))) &&
184
175
  mail.replyTo.every(({ agentId }) => scope.agents.some((agent) => agent.agentId === agentId)) &&
185
176
  (mail.replyTo.length === 0 ||
186
177
  (mail.replyTo.length === 1 &&
187
- mail.replyTo[0]?.agentId === mail.from.agentId &&
188
- mail.replyTo[0].sessionId === mail.from.sessionId)));
178
+ sender.kind === "agent" &&
179
+ mail.replyTo[0]?.agentId === sender.agentId &&
180
+ mail.replyTo[0].sessionId === sender.sessionId)));
189
181
  };
190
182
  if (mail.replyTo.length === 0)
191
183
  authenticated = await this.authenticatedReply(mail);
@@ -215,12 +207,37 @@ export class AgentDelegation {
215
207
  this.deps.stageAcceptedNotice(notice, scopeId);
216
208
  };
217
209
  const receipt = await this.deps.accept(admitted.mail, admitted.reply, stageAcceptedNotice);
210
+ if (admitted.reply?.outcome === "undeliverable" &&
211
+ admitted.mail.from.kind === "system") {
212
+ this.fleet().recordUndeliverableReply(admitted.mail.key.slice(0, -":reply:0".length));
213
+ }
218
214
  const sessionId = admitted.mail.to.sessionId ?? receipt.sessionId;
219
215
  return {
220
216
  status: "accepted",
221
217
  receipt: sessionId === undefined ? receipt : { ...receipt, sessionId },
222
218
  };
223
219
  }
220
+ /** Admit local outbox exhaustion through the same Fleet/system reply gate. */
221
+ async localUndeliverable(original) {
222
+ const identity = await this.deps.identity();
223
+ if (identity === null)
224
+ return "refused";
225
+ let reply;
226
+ try {
227
+ reply = undeliverableReply(original, Date.now());
228
+ }
229
+ catch {
230
+ return "refused";
231
+ }
232
+ if (!this.fleet().recordLocalUndeliverable(original, reply))
233
+ return "refused";
234
+ return await this.receive({
235
+ key: reply.key,
236
+ kind: "agentMail",
237
+ address: { scopeId: identity.scopeId, agentId: identity.agentId },
238
+ event: reply,
239
+ });
240
+ }
224
241
  }
225
242
  /** A current correspondent no longer has disclosure authority. */
226
243
  export class AgentDisclosureRefused extends Error {
@@ -284,6 +301,39 @@ export class AgentMail {
284
301
  throw new Error(`Agent delivery ${row.reason}`);
285
302
  throw new Error("Agent did not return a delegated work receipt");
286
303
  }
304
+ /** Reconcile exhausted original outbox mail into one local system reply. */
305
+ async stageUndeliverableReplies() {
306
+ const identity = await this.deps.identity();
307
+ if (identity === null)
308
+ return;
309
+ const post = this.deps.post();
310
+ let cursor;
311
+ do {
312
+ const page = post.deadLetters(64, cursor);
313
+ for (const letter of page.letters) {
314
+ if (letter.reason !== "exhausted" ||
315
+ letter.envelope.kind !== "agentMail")
316
+ continue;
317
+ const envelope = Schema.decodeUnknownOption(PostEnvelopeSchema)(letter.envelope);
318
+ if (envelope._tag === "None" || envelope.value.kind !== "agentMail")
319
+ continue;
320
+ const original = Schema.decodeUnknownOption(BirdDogMailSchema)(envelope.value.event);
321
+ const address = Schema.decodeUnknownOption(agentMailAddressSchema)(envelope.value.address);
322
+ if (original._tag === "None" ||
323
+ address._tag === "None" ||
324
+ original.value.key !== envelope.value.key ||
325
+ original.value.reply !== undefined ||
326
+ original.value.from.kind !== "agent" ||
327
+ original.value.from.agentId !== identity.agentId ||
328
+ address.value.scopeId !== identity.scopeId ||
329
+ address.value.agentId !== original.value.to.agentId)
330
+ continue;
331
+ const reply = undeliverableReply(original.value, Date.now());
332
+ await this.deps.onUndeliverable(original.value, reply);
333
+ }
334
+ cursor = page.nextCursor;
335
+ } while (cursor !== undefined);
336
+ }
287
337
  /** Stage the acceptance reply through this Post owner without leaving the transaction. */
288
338
  stageAcceptedNotice(mail, scopeId) {
289
339
  this.deps.post().send({
package/dist/effect.d.ts CHANGED
@@ -38,5 +38,30 @@ export declare function readSessionSummaries(owner: SqliteOwner, after?: string)
38
38
  sessions: readonly import("./internal/woodstock/session-store.js").StoredSessionSummaryRow[];
39
39
  next: string | undefined;
40
40
  }>, ShiitakeError, never>;
41
+ /**
42
+ * One page of saved conversations with their stored run state (needs_you,
43
+ * running, errored, done), in tier then newest-activity order, read from the
44
+ * store alone: no Agent runtime starts. The state is as the runtime last wrote
45
+ * it, so it can lag work a stopped runtime left behind.
46
+ */
47
+ export declare function readStoredSessionStates(owner: SqliteOwner, after?: string): Effect.Effect<Readonly<{
48
+ sessions: readonly import("./client.js").SessionSummaryRow[];
49
+ next: string | undefined;
50
+ }>, ShiitakeError, never>;
51
+ /** One saved conversation's open attention items, read from the store alone. */
52
+ export declare function readStoredAttention(owner: SqliteOwner, sessionId: string): Effect.Effect<readonly {
53
+ readonly id: string;
54
+ readonly kind: string;
55
+ readonly summary: string;
56
+ readonly since: number;
57
+ readonly extensionId: string;
58
+ readonly expiresAt?: number | undefined;
59
+ readonly inbox?: false | undefined;
60
+ readonly waitingOn?: {
61
+ readonly agentId: string;
62
+ readonly sessionId: string;
63
+ readonly name: string;
64
+ } | undefined;
65
+ }[], ShiitakeError, never>;
41
66
  export { sqliteRowSchema } from "./internal/contracts.js";
42
67
  export type { CommandSettlement } from "./internal/contracts.js";
package/dist/effect.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as Effect from "effect/Effect";
2
- import { readSessionFactPage } from "./internal/woodstock/index.js";
2
+ import { readSessionFactPage, readSessionInbox, readStoredSessionAttention, } from "./internal/woodstock/index.js";
3
3
  export { ShiitakeError } from "./errors.js";
4
4
  /** Construct the canonical Effect-native Shiitake scaffold. */
5
5
  export function make(options) {
@@ -17,4 +17,17 @@ export function openHost(options, mailRoom) {
17
17
  export function readSessionSummaries(owner, after) {
18
18
  return readSessionFactPage(owner, after);
19
19
  }
20
+ /**
21
+ * One page of saved conversations with their stored run state (needs_you,
22
+ * running, errored, done), in tier then newest-activity order, read from the
23
+ * store alone: no Agent runtime starts. The state is as the runtime last wrote
24
+ * it, so it can lag work a stopped runtime left behind.
25
+ */
26
+ export function readStoredSessionStates(owner, after) {
27
+ return readSessionInbox(owner, after);
28
+ }
29
+ /** One saved conversation's open attention items, read from the store alone. */
30
+ export function readStoredAttention(owner, sessionId) {
31
+ return readStoredSessionAttention(owner, sessionId);
32
+ }
20
33
  export { sqliteRowSchema } from "./internal/contracts.js";