@fungi.computer/shiitake 0.2.0 → 0.3.1

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 (114) hide show
  1. package/README.md +155 -34
  2. package/dist/agent-control.d.ts +77 -5
  3. package/dist/agent-control.js +271 -65
  4. package/dist/client-entry.d.ts +15 -8
  5. package/dist/client-entry.js +7 -5
  6. package/dist/client-wire.d.ts +24 -8
  7. package/dist/client-wire.js +53 -11
  8. package/dist/client.d.ts +56 -11
  9. package/dist/client.js +1 -1
  10. package/dist/cloudflare.d.ts +42 -23
  11. package/dist/cloudflare.js +76 -54
  12. package/dist/cold-sessions.d.ts +28 -0
  13. package/dist/cold-sessions.js +1 -0
  14. package/dist/delegation.d.ts +214 -0
  15. package/dist/delegation.js +319 -0
  16. package/dist/effect.d.ts +1 -1
  17. package/dist/errors.d.ts +2 -2
  18. package/dist/errors.js +2 -2
  19. package/dist/extension-contract.d.ts +10 -2
  20. package/dist/extensions.d.ts +6 -2
  21. package/dist/fleet.d.ts +43 -9
  22. package/dist/fleet.js +88 -25
  23. package/dist/hosted.js +1 -0
  24. package/dist/http-routes.d.ts +113 -29
  25. package/dist/http-routes.js +18 -1
  26. package/dist/index.d.ts +3 -2
  27. package/dist/internal/accepted-run-executor.d.ts +5 -0
  28. package/dist/internal/accepted-run-executor.js +10 -4
  29. package/dist/internal/admission-door.d.ts +3 -0
  30. package/dist/internal/admission-door.js +12 -2
  31. package/dist/internal/client-boundary.js +7 -1
  32. package/dist/internal/compaction/compaction-slot.d.ts +36 -0
  33. package/dist/internal/compaction/compaction-slot.js +41 -0
  34. package/dist/internal/compaction/compaction.d.ts +11 -8
  35. package/dist/internal/compaction/compaction.js +62 -34
  36. package/dist/internal/compaction/session-compaction.d.ts +8 -16
  37. package/dist/internal/compaction/session-compaction.js +358 -119
  38. package/dist/internal/compaction/settings.d.ts +1 -1
  39. package/dist/internal/compaction/settings.js +5 -0
  40. package/dist/internal/compaction/utils.d.ts +19 -16
  41. package/dist/internal/compaction/utils.js +30 -84
  42. package/dist/internal/contracts.d.ts +40 -13
  43. package/dist/internal/coordinator.js +28 -10
  44. package/dist/internal/effect-client.d.ts +4 -2
  45. package/dist/internal/effect-client.js +29 -0
  46. package/dist/internal/effect-contracts.d.ts +17 -4
  47. package/dist/internal/extension-runtime.d.ts +5 -0
  48. package/dist/internal/extension-runtime.js +184 -89
  49. package/dist/internal/host-meta.d.ts +7 -0
  50. package/dist/internal/model-acquisition.js +7 -1
  51. package/dist/internal/model-preference.d.ts +4 -2
  52. package/dist/internal/model-preference.js +2 -1
  53. package/dist/internal/promise-facade.js +4 -16
  54. package/dist/internal/run-failure-reason.d.ts +10 -0
  55. package/dist/internal/run-failure-reason.js +19 -0
  56. package/dist/internal/run-scope.d.ts +4 -1
  57. package/dist/internal/run-scope.js +38 -5
  58. package/dist/internal/runtime-coordinator.d.ts +2 -1
  59. package/dist/internal/runtime-coordinator.js +65 -4
  60. package/dist/internal/runtime-core.js +1 -0
  61. package/dist/internal/runtime-reconciliation.js +42 -6
  62. package/dist/internal/session-context.d.ts +1 -2
  63. package/dist/internal/session-context.js +8 -30
  64. package/dist/internal/session-status.d.ts +2 -1
  65. package/dist/internal/session-status.js +4 -1
  66. package/dist/internal/woodstock/client-projection.d.ts +6 -5
  67. package/dist/internal/woodstock/client-projection.js +79 -53
  68. package/dist/internal/woodstock/cold-sessions.d.ts +4 -0
  69. package/dist/internal/woodstock/cold-sessions.js +90 -0
  70. package/dist/internal/woodstock/extension-store.d.ts +2 -0
  71. package/dist/internal/woodstock/extension-store.js +4 -0
  72. package/dist/internal/woodstock/fleet-store.d.ts +5 -1
  73. package/dist/internal/woodstock/fleet-store.js +17 -5
  74. package/dist/internal/woodstock/index.d.ts +11 -3
  75. package/dist/internal/woodstock/index.js +33 -14
  76. package/dist/internal/woodstock/progress.d.ts +14 -1
  77. package/dist/internal/woodstock/progress.js +97 -19
  78. package/dist/internal/woodstock/run-recovery.js +6 -4
  79. package/dist/internal/woodstock/session-attention.d.ts +1 -1
  80. package/dist/internal/woodstock/session-attention.js +2 -2
  81. package/dist/internal/woodstock/session-entry.d.ts +110 -43
  82. package/dist/internal/woodstock/session-entry.js +63 -20
  83. package/dist/internal/woodstock/session-inbox.js +2 -0
  84. package/dist/internal/woodstock/session-store.d.ts +104 -24
  85. package/dist/internal/woodstock/session-store.js +937 -246
  86. package/dist/internal/woodstock/storage-admission.d.ts +8 -8
  87. package/dist/internal/woodstock/storage-admission.js +8 -34
  88. package/dist/internal/woodstock/storage-conformance.d.ts +15 -0
  89. package/dist/internal/woodstock/storage-conformance.js +489 -0
  90. package/dist/model-preference.d.ts +2 -2
  91. package/dist/model-preference.js +2 -2
  92. package/dist/node.js +1 -1
  93. package/dist/remote-client.js +8 -1
  94. package/dist/session-attention.d.ts +8 -1
  95. package/dist/session-attention.js +6 -1
  96. package/dist/testing.d.ts +1 -1
  97. package/dist/testing.js +1 -0
  98. package/docs/api/README.md +18 -16
  99. package/docs/api/agent-control.md +171 -1
  100. package/docs/api/client-entry.md +26 -10
  101. package/docs/api/client.md +153 -37
  102. package/docs/api/cloudflare.md +76 -23
  103. package/docs/api/delegation.md +485 -0
  104. package/docs/api/effect.md +20 -2
  105. package/docs/api/extensions.md +21 -9
  106. package/docs/api/fleet.md +159 -104
  107. package/docs/api/http.md +4 -1
  108. package/docs/api/index.md +116 -20
  109. package/docs/api/internal/woodstock/storage-conformance.md +81 -0
  110. package/docs/api/model-preference.md +27 -10
  111. package/docs/api/testing.md +16 -4
  112. package/package.json +26 -14
  113. package/dist/internal/browser-sessions.d.ts +0 -31
  114. package/dist/internal/browser-sessions.js +0 -173
@@ -4,15 +4,13 @@ import * as Effect from "effect/Effect";
4
4
  import * as Deferred from "effect/Deferred";
5
5
  import * as Redacted from "effect/Redacted";
6
6
  import { WatchdogError, } from "@fungi.computer/watchdog";
7
- import { composeAgentClose } from "./internal/agent-close.js";
8
7
  import { ShiitakeError } from "./errors.js";
9
8
  import { createShiitakeHttpRoutes, } from "./http-routes.js";
10
9
  import { Hono } from "hono";
11
10
  import { runShiitakePromise, toPromiseOwner, } from "./internal/effect-client.js";
12
11
  import { adaptModelSource } from "./internal/model-acquisition.js";
13
12
  import { decodeClientSessionId } from "./internal/client-boundary.js";
14
- import { deliverSessionGrants, prepareSessionGrants, pruneSessionInboxTombstones, readSessionInboxChanges, readSessionSummary, readSessionInboxSummary, } from "./internal/woodstock/index.js";
15
- import { BrowserSessions, } from "./internal/browser-sessions.js";
13
+ import { deliverSessionGrants, prepareSessionGrants, pruneSessionInboxTombstones, readColdSessionPage, readSessionInboxChanges, readSessionSummary, readSessionInboxSummary, } from "./internal/woodstock/index.js";
16
14
  /**
17
15
  * Deliver one Session's grants into a Cloudflare owner's own storage,
18
16
  * synchronously, whether or not its runtime is open; the very next tool call
@@ -240,30 +238,16 @@ function configuredTools(tools) {
240
238
  access: tools.access ?? {},
241
239
  };
242
240
  }
243
- function effectOptions(state, options, runtime, browser) {
241
+ function effectOptions(state, options, runtime) {
244
242
  const tools = configuredTools(options.tools);
245
243
  const base = {
246
244
  store: state.storage,
247
245
  runtime,
248
246
  extensions: options.extensions,
249
247
  instructions: {
250
- load: ({ sessionId, commandId }) => Effect.gen(function* () {
251
- const lease = browser === undefined
252
- ? undefined
253
- : yield* Effect.acquireRelease(Effect.try({
254
- try: () => browser.acquire(sessionId),
255
- catch: () => new ShiitakeError("instructions", "rejected", "Browser acquisition failed"),
256
- }), (acquired) => Effect.sync(acquired.release));
257
- const snapshot = yield* Effect.tryPromise({
258
- try: (signal) => options.instructions.load({ sessionId, commandId, signal }),
259
- catch: () => new ShiitakeError("instructions", "rejected", "Instruction acquisition failed"),
260
- });
261
- return lease === undefined
262
- ? snapshot
263
- : {
264
- ...snapshot,
265
- modules: [...(snapshot.modules ?? []), ...lease.host.modules],
266
- };
248
+ load: ({ sessionId, commandId }) => Effect.tryPromise({
249
+ try: (signal) => options.instructions.load({ sessionId, commandId, signal }),
250
+ catch: () => new ShiitakeError("instructions", "rejected", "Instruction acquisition failed"),
267
251
  }),
268
252
  },
269
253
  model: adaptModelSource(options.model),
@@ -291,34 +275,58 @@ function effectOptions(state, options, runtime, browser) {
291
275
  }
292
276
  if (options.meta !== undefined)
293
277
  Object.assign(base, { meta: options.meta });
294
- if (options.storageBudget !== undefined)
295
- Object.assign(base, { storageBudget: options.storageBudget });
278
+ if (options.storagePressure !== undefined)
279
+ Object.assign(base, { storagePressure: options.storagePressure });
296
280
  if (options.compaction !== undefined)
297
281
  Object.assign(base, { compaction: options.compaction });
298
282
  return tools === undefined ? base : { ...base, tools };
299
283
  }
300
284
  /** Construct Shiitake over one Durable Object's SQLite and lifetime. */
301
- export function makeCloudflareShiitake(state, options) {
285
+ /**
286
+ * The state with its storage named for Woodstock's refusals after the
287
+ * Durable Object's id, when it has one. Its owner and every reader of it
288
+ * share this one storage object, so the name travels with the owner.
289
+ */
290
+ function namedState(state) {
291
+ const { id, storage } = state;
292
+ if (id === undefined || storage.storeName !== undefined)
293
+ return state;
294
+ return {
295
+ id,
296
+ waitUntil: (task) => {
297
+ state.waitUntil(task);
298
+ },
299
+ storage: {
300
+ sql: storage.sql,
301
+ transactionSync: (operation) => storage.transactionSync(operation),
302
+ transaction: (body) => storage.transaction(body),
303
+ getAlarm: (alarmOptions) => storage.getAlarm(alarmOptions),
304
+ setAlarm: (time, alarmOptions) => storage.setAlarm(time, alarmOptions),
305
+ deleteAlarm: (alarmOptions) => storage.deleteAlarm(alarmOptions),
306
+ storeName: `Durable Object ${id.toString()}`,
307
+ },
308
+ };
309
+ }
310
+ /**
311
+ * Open Shiitake over one Durable Object's storage. It resolves once the runtime
312
+ * is started and `initialize` has run; if `initialize` throws, the runtime is
313
+ * closed and the error is rethrown.
314
+ */
315
+ export function makeCloudflareShiitake(unnamed, options) {
316
+ const state = namedState(unnamed);
302
317
  const startup = Deferred.makeUnsafe();
303
318
  const host = runtimeHost(state, options.hostWork, Deferred.await(startup));
304
- const browser = options.browser === undefined
305
- ? undefined
306
- : new BrowserSessions(options.browser, async (sessionId) => (await runShiitakePromise(readSessionSummary(state.storage, sessionId))) !== undefined);
307
- const coreOptions = effectOptions(state, options, host.runtime, browser);
319
+ const coreOptions = effectOptions(state, options, host.runtime);
308
320
  return import("./internal/runtime-core.js")
309
321
  .then(({ openRuntimeCore }) => runShiitakePromise(openRuntimeCore(coreOptions, options.mailRoom)))
310
322
  .then(async ({ agent, activeSessions, acceptMail, readSettlement }) => {
311
- const close = composeAgentClose(Effect.tryPromise({
312
- try: () => browser?.close() ?? Promise.resolve(),
313
- catch: () => runtimeFailure("unavailable", "Browser teardown failed"),
314
- }), agent.close);
315
323
  const handle = toPromiseOwner(agent);
316
324
  try {
317
325
  await options.initialize?.(handle);
318
326
  }
319
327
  catch (cause) {
320
328
  await runShiitakePromise(Deferred.succeed(startup, false));
321
- await runShiitakePromise(close);
329
+ await runShiitakePromise(agent.close);
322
330
  throw cause;
323
331
  }
324
332
  await runShiitakePromise(Deferred.succeed(startup, true));
@@ -330,18 +338,12 @@ export function makeCloudflareShiitake(state, options) {
330
338
  return Promise.reject(runtimeFailure("unavailable", "Addressed mail is unavailable"));
331
339
  return runShiitakePromise(acceptMail(mail, meta, reply));
332
340
  },
333
- close: () => runShiitakePromise(close),
334
341
  alarm: host.alarm,
335
342
  activeSessions: () => runShiitakePromise(activeSessions),
336
343
  abortActive: async () => {
337
344
  for (const sessionId of await runShiitakePromise(activeSessions))
338
345
  await runShiitakePromise(agent.session(sessionId).abort);
339
346
  },
340
- browser: {
341
- fetch: (request) => browser?.fetch(request) ??
342
- Promise.resolve(new Response(null, { status: 404 })),
343
- clear: () => browser?.clear() ?? Promise.resolve(),
344
- },
345
347
  });
346
348
  }, async (cause) => {
347
349
  await runShiitakePromise(Deferred.succeed(startup, false));
@@ -358,6 +360,11 @@ export class ShiitakeOwner {
358
360
  }
359
361
  agentPromise;
360
362
  openAcp;
363
+ #named;
364
+ /** This owner's state, its storage named once for Woodstock's refusals. */
365
+ get named() {
366
+ return (this.#named ??= namedState(this.ctx));
367
+ }
361
368
  acpServer;
362
369
  /** Consecutive native alarm failures; reset on the next successful alarm. */
363
370
  alarmFailures = 0;
@@ -367,11 +374,13 @@ export class ShiitakeOwner {
367
374
  }, async (after) => (await this.shiitake()).listSessions(after), async (requestId) => (await this.shiitake()).createSession(requestId), async (sessionId) => (await this.shiitake()).deleteSession(sessionId), async () => (await this.shiitake()).extensions);
368
375
  /** Borrow this owner's runtime directly; only the host owns its lifetime. */
369
376
  async shiitake() {
370
- if (this.agentPromise === undefined) {
371
- const options = this.shiitakeOptions();
377
+ // Publish the flight before loading options: concurrent cold requests
378
+ // share both first-use imports and the runtime they configure.
379
+ this.agentPromise ??= Promise.resolve().then(async () => {
380
+ const options = await this.shiitakeOptions();
372
381
  this.openAcp = options.acp;
373
- this.agentPromise = makeCloudflareShiitake(this.ctx, options);
374
- }
382
+ return makeCloudflareShiitake(this.named, options);
383
+ });
375
384
  try {
376
385
  return await this.agentPromise;
377
386
  }
@@ -391,24 +400,32 @@ export class ShiitakeOwner {
391
400
  /** Indexed owner-local existence check; corrupt stored Sessions remain unavailable. */
392
401
  async hasStoredSession(sessionId) {
393
402
  await this.shiitake();
394
- const inbox = readSessionInboxSummary(this.ctx.storage, sessionId);
403
+ const inbox = readSessionInboxSummary(this.named.storage, sessionId);
395
404
  if (inbox === undefined || inbox.state === "unavailable")
396
405
  return false;
397
- return ((await runShiitakePromise(readSessionSummary(this.ctx.storage, sessionId))) !== undefined);
406
+ return ((await runShiitakePromise(readSessionSummary(this.named.storage, sessionId))) !== undefined);
398
407
  }
399
408
  /** Bounded strict-after read of this Agent's changed inbox rows. */
400
409
  async readInboxChanges(after, limit) {
401
410
  await this.shiitake();
402
- return readSessionInboxChanges(this.ctx.storage, after, limit);
411
+ return readSessionInboxChanges(this.named.storage, after, limit);
412
+ }
413
+ /**
414
+ * One bounded, read-only page of Sessions with stored bytes, last activity
415
+ * and an idle flag, coldest first. The store keeper's only view of cold
416
+ * Sessions; it carries no SQL, transaction or write.
417
+ */
418
+ async readColdSessions(request) {
419
+ await this.shiitake();
420
+ return await runShiitakePromise(readColdSessionPage(this.named.storage, request));
403
421
  }
404
422
  /** Latest inbox revision; read only after the owner has opened. */
405
423
  readInboxRevision() {
406
- return readSessionInboxChanges(this.ctx.storage, Number.MAX_SAFE_INTEGER, 0)
407
- .latest;
424
+ return readSessionInboxChanges(this.named.storage, Number.MAX_SAFE_INTEGER, 0).latest;
408
425
  }
409
426
  /** Prune deletion deltas after every current member inbox has acknowledged them. */
410
427
  pruneInboxTombstones(through) {
411
- pruneSessionInboxTombstones(this.ctx.storage, through);
428
+ pruneSessionInboxTombstones(this.named.storage, through);
412
429
  }
413
430
  /** Persist a wake and run one reconciliation pass, including host work. */
414
431
  async wakeRuntime() {
@@ -453,13 +470,12 @@ export class ShiitakeOwner {
453
470
  /** Serve Shiitake's complete transport without subclass routing. */
454
471
  app;
455
472
  /**
456
- * Shiitake's whole HTTP surface (Session routes, browser and ACP) as one
473
+ * Shiitake's whole HTTP surface (Session routes and ACP) as one
457
474
  * Hono app. A host mounts it behind its own middleware, which alone may
458
475
  * set the `shiitakeMeta` variable.
459
476
  */
460
477
  shiitakeApp() {
461
478
  return (this.app ??= new Hono()
462
- .all("/browser/*", async (context) => (await this.shiitake()).browser.fetch(context.req.raw))
463
479
  .all("/acp", async (context) => {
464
480
  const agent = await this.shiitake();
465
481
  if (this.openAcp === undefined)
@@ -477,7 +493,7 @@ export class ShiitakeOwner {
477
493
  return server.handleRequest(context.req.raw, context.get("shiitakeMeta"));
478
494
  })
479
495
  .route("/", this.routes)
480
- // Browser and ACP failures reach the Durable Object caller unchanged,
496
+ // ACP failures reach the Durable Object caller unchanged,
481
497
  // as they did before the routes shared one app.
482
498
  .onError((error) => {
483
499
  throw error;
@@ -508,12 +524,18 @@ export class ShiitakeDO extends DurableObject {
508
524
  closeShiitake() {
509
525
  return this.runtimeOwner().closeShiitake();
510
526
  }
527
+ hasStoredSession(sessionId) {
528
+ return this.runtimeOwner().hasStoredSession(sessionId);
529
+ }
511
530
  readInboxChanges(after, limit) {
512
531
  return this.runtimeOwner().readInboxChanges(after, limit);
513
532
  }
514
533
  readInboxRevision() {
515
534
  return this.runtimeOwner().readInboxRevision();
516
535
  }
536
+ readColdSessions(request) {
537
+ return this.runtimeOwner().readColdSessions(request);
538
+ }
517
539
  pruneInboxTombstones(through) {
518
540
  this.runtimeOwner().pruneInboxTombstones(through);
519
541
  }
@@ -524,8 +546,8 @@ export class ShiitakeDO extends DurableObject {
524
546
  alarm() {
525
547
  return this.runtimeOwner().alarm();
526
548
  }
527
- /** Route an authenticated client request through the owner. */
549
+ /** Route an authenticated client request through the host's routes, then the owner. */
528
550
  fetch(request) {
529
- return this.runtimeOwner().fetch(request);
551
+ return this.hostFetch?.(request) ?? this.runtimeOwner().fetch(request);
530
552
  }
531
553
  }
@@ -0,0 +1,28 @@
1
+ /** One Session as the store keeper sees it: what it holds and how cold it is. */
2
+ export type ColdSessionRow = Readonly<{
3
+ sessionId: string;
4
+ /**
5
+ * Bytes of the Session's stored payloads: conversation entries, accepted
6
+ * commands, open attention and tool grants. Measured from the stored rows
7
+ * on every read, never from a counter.
8
+ */
9
+ bytes: number;
10
+ /** Milliseconds since the epoch of the Session's latest conversation or run activity. */
11
+ lastActivityAt: number;
12
+ /**
13
+ * True only when no run is queued or live and no extension attention waits
14
+ * on a person: the Session is settled. Anything else is not idle.
15
+ */
16
+ idle: boolean;
17
+ }>;
18
+ /** One bounded page of Sessions, coldest first. */
19
+ export type ColdSessionPage = Readonly<{
20
+ sessions: readonly ColdSessionRow[];
21
+ /** Pass as `after` to read the next page; absent on the last page. */
22
+ next?: string;
23
+ }>;
24
+ /** A page request: `limit` is a whole number from 1 to 200 (default 50). */
25
+ export type ColdSessionPageRequest = Readonly<{
26
+ limit?: number;
27
+ after?: string;
28
+ }>;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,214 @@
1
+ import type { WatchdogSqliteOwner } from "@fungi.computer/watchdog";
2
+ import * as Schema from "effect/Schema";
3
+ import { type BirdDogEffect } from "@fungi.computer/bird-dog/effect";
4
+ import type { BirdDogMail } from "@fungi.computer/bird-dog";
5
+ import { type PostRoute, type PostRuntime, type PostEnvelope, type PostDeliveryResult } from "@fungi.computer/carrier/post";
6
+ import { type Accepted, type CancelResult } from "./client.js";
7
+ import type { CommandSettlement, ShiitakeHost, VerifiedAgentReply } from "./index.js";
8
+ import type { AgentControlDirectory, AgentDelegationInput, AgentDelegationInvocation, AgentRecallInput } from "./agent-control.js";
9
+ /** Shiitake host-pack identity; core consumes OysterAgents, never this engine. */
10
+ export type DelegationIdentity = Readonly<{
11
+ scopeId: string;
12
+ agentId: string;
13
+ }>;
14
+ /** Host-owned identity and admission around BirdDog's ordinary envelope. */
15
+ export declare class AgentDelegation {
16
+ private readonly deps;
17
+ constructor(deps: Readonly<{
18
+ storage: WatchdogSqliteOwner;
19
+ expiresAt: () => number;
20
+ identity: () => DelegationIdentity | null | Promise<DelegationIdentity | null>;
21
+ directory: () => AgentControlDirectory;
22
+ deliver: (mail: BirdDogMail) => Promise<Accepted>;
23
+ prepare: (mail: BirdDogMail) => Promise<void>;
24
+ /** Admit mail; `reply` is present only for an authenticated reply. */
25
+ accept: (mail: BirdDogMail, reply?: VerifiedAgentReply) => Promise<Accepted>;
26
+ }>);
27
+ private fleetOwner;
28
+ private fleet;
29
+ private scope;
30
+ private requestKey;
31
+ /** Recipient-local disclosure through the public host, never another Agent's RPC. */
32
+ settlement(sender: DelegationIdentity, sessionId: string, commandId: string, host: Pick<ShiitakeHost, "readSettlement">): Promise<CommandSettlement | undefined>;
33
+ /** Delegate work to an in-scope Agent: steer its Session, or start fleet correspondence. */
34
+ send(input: AgentDelegationInput, sourceSessionId: string, signal: AbortSignal, invocation?: AgentDelegationInvocation): Promise<Accepted>;
35
+ /** Resolve this sender's exact request, then let the recipient guard pending work. */
36
+ recall(input: AgentRecallInput, sourceSessionId: string, signal: AbortSignal): Promise<CancelResult>;
37
+ /**
38
+ * A reply-less envelope is only ever BirdDog's reply to work this Agent
39
+ * sent. Admit it only after the fleet authenticates it against that frozen
40
+ * mail; the line is then authored by the replying Agent, never by whoever
41
+ * settled or cancelled the work, and its meta carries the verified reply.
42
+ */
43
+ private authenticatedReply;
44
+ /** Admit one addressed Agent mail for this Agent, or refuse it. */
45
+ receive(raw: PostEnvelope): Promise<PostDeliveryResult>;
46
+ }
47
+ /** A current correspondent no longer has disclosure authority. */
48
+ export declare class AgentDisclosureRefused extends Error {
49
+ constructor();
50
+ }
51
+ /** Undefined is an explicit disclosure refusal; missing facts and read errors must fail. */
52
+ export type AgentReplySettlement = (mail: BirdDogMail) => Promise<CommandSettlement | undefined>;
53
+ /** Current disclosure admission runs at every transport attempt, including frozen retries. */
54
+ export declare function agentMailRoute(namespace: PostRoute<never, never>["namespace"], replySettlement: AgentReplySettlement): PostRoute<import("@fungi.computer/seam/machine-link-protocol").AgentMailAddress, {
55
+ readonly key: string;
56
+ readonly content: string;
57
+ readonly createdAt: number;
58
+ readonly from: {
59
+ readonly kind: "agent";
60
+ readonly agentId: string;
61
+ readonly sessionId: string;
62
+ };
63
+ readonly to: {
64
+ readonly kind: "agent";
65
+ readonly agentId: string;
66
+ readonly sessionId: string;
67
+ };
68
+ readonly replyTo: readonly {
69
+ readonly kind: "agent";
70
+ readonly agentId: string;
71
+ readonly sessionId: string;
72
+ }[];
73
+ readonly meta?: Schema.Json;
74
+ readonly reply?: {
75
+ readonly commandId: string;
76
+ readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
77
+ readonly diagnostic?: string;
78
+ };
79
+ }, {
80
+ readonly key: string;
81
+ readonly content: string;
82
+ readonly createdAt: number;
83
+ readonly from: {
84
+ readonly kind: "agent";
85
+ readonly agentId: string;
86
+ readonly sessionId: string;
87
+ };
88
+ readonly to: {
89
+ readonly kind: "agent";
90
+ readonly agentId: string;
91
+ readonly sessionId: string;
92
+ };
93
+ readonly replyTo: readonly {
94
+ readonly kind: "agent";
95
+ readonly agentId: string;
96
+ readonly sessionId: string;
97
+ }[];
98
+ readonly meta?: Schema.Json;
99
+ readonly reply?: {
100
+ readonly commandId: string;
101
+ readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
102
+ readonly diagnostic?: string;
103
+ };
104
+ }, import("@fungi.computer/seam/machine-link-protocol").AgentMailAddress, {
105
+ readonly key: string;
106
+ readonly content: string;
107
+ readonly createdAt: number;
108
+ readonly from: {
109
+ readonly kind: "agent";
110
+ readonly agentId: string;
111
+ readonly sessionId: string;
112
+ };
113
+ readonly to: {
114
+ readonly kind: "agent";
115
+ readonly agentId: string;
116
+ readonly sessionId: string;
117
+ };
118
+ readonly replyTo: readonly {
119
+ readonly kind: "agent";
120
+ readonly agentId: string;
121
+ readonly sessionId: string;
122
+ }[];
123
+ readonly meta?: Schema.Json;
124
+ readonly reply?: {
125
+ readonly commandId: string;
126
+ readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
127
+ readonly diagnostic?: string;
128
+ };
129
+ }, {
130
+ readonly key: string;
131
+ readonly content: string;
132
+ readonly createdAt: number;
133
+ readonly from: {
134
+ readonly kind: "agent";
135
+ readonly agentId: string;
136
+ readonly sessionId: string;
137
+ };
138
+ readonly to: {
139
+ readonly kind: "agent";
140
+ readonly agentId: string;
141
+ readonly sessionId: string;
142
+ };
143
+ readonly replyTo: readonly {
144
+ readonly kind: "agent";
145
+ readonly agentId: string;
146
+ readonly sessionId: string;
147
+ }[];
148
+ readonly meta?: Schema.Json;
149
+ readonly reply?: {
150
+ readonly commandId: string;
151
+ readonly outcome: "completed" | "failed" | "cancelled" | "interrupted" | "outcome_unknown";
152
+ readonly diagnostic?: string;
153
+ };
154
+ }> & Omit<Readonly<{
155
+ addressKind: string;
156
+ address: Schema.Codec<unknown, unknown>;
157
+ event: Schema.Codec<unknown, unknown>;
158
+ encodeEnvelope: (envelope: PostEnvelope) => PostEnvelope;
159
+ parseDelivery: (envelope: PostEnvelope) => PostEnvelope;
160
+ prepareEnvelope?: ((envelope: PostEnvelope, signal: AbortSignal) => Promise<PostEnvelope>) | undefined;
161
+ recordDelivered?: ((envelope: PostEnvelope) => void) | undefined;
162
+ nameOf: (envelope: Pick<PostEnvelope, "address">) => string;
163
+ namespace: PostRoute<never, never>["namespace"];
164
+ recordCursor?: ((envelope: PostEnvelope, cursor: number) => void) | undefined;
165
+ recordRefused?: ((envelope: PostEnvelope) => void) | undefined;
166
+ }>, "event" | "address">;
167
+ /** The host's one Post lane, as Agent mail borrows it. */
168
+ export type AgentMailPost = Pick<PostRuntime<{
169
+ agentMail: ReturnType<typeof agentMailRoute>;
170
+ }>, "send" | "read" | "nextWake">;
171
+ /** Recipient-owned replies and receipt-bearing submissions over the host's one Post lane. */
172
+ export declare class AgentMail {
173
+ private readonly deps;
174
+ constructor(deps: Readonly<{
175
+ storage: WatchdogSqliteOwner;
176
+ post: () => AgentMailPost;
177
+ identity: () => DelegationIdentity | null | Promise<DelegationIdentity | null>;
178
+ /** Only a typed disclosure refusal becomes undefined; missing settled facts must fail. */
179
+ replySettlement: AgentReplySettlement;
180
+ drain: () => Promise<void>;
181
+ wake: () => Promise<void>;
182
+ }>);
183
+ private envelope;
184
+ /** Submit one mail and return the recipient's Accepted receipt. */
185
+ send(mail: BirdDogMail): Promise<Accepted>;
186
+ /** BirdDog's mail room: disclosed settlement replies fan out over Post. */
187
+ mailRoom(): BirdDogEffect;
188
+ }
189
+ /**
190
+ * The Agent wire decoders a host lends Oyster's machine-link client, so the
191
+ * device link routes Agent work without owning Shiitake's grammar.
192
+ */
193
+ export declare const machineAgentCodecs: {
194
+ /** The Session-creation intent, or null when the body is not one. */
195
+ readonly sessionCreation: (body: Schema.Json) => Readonly<{
196
+ requestId: string;
197
+ }> | null;
198
+ /** One serialized settlement from a hosted or machine-homed Agent. */
199
+ readonly settlement: (encoded: string) => CommandSettlement;
200
+ /** Throws unless an acknowledgment carries a well-formed Accepted receipt. */
201
+ readonly accepted: (receipt: Schema.Json) => void;
202
+ };
203
+ /**
204
+ * Machine-homed Agent identities in the ordinary directory over the
205
+ * enrollment's own store: one Team identity per enrollment receipt, reserved
206
+ * without opening a hosted Agent. The enrolling member is the grant actor.
207
+ */
208
+ export declare function machineAgentReservations(sql: WatchdogSqliteOwner["sql"]): (reservation: Readonly<{
209
+ memberId: string;
210
+ requestId: string;
211
+ name: string;
212
+ }>) => {
213
+ agentId: import("./fleet.js").AgentId;
214
+ };