@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.
- package/README.md +155 -34
- package/dist/agent-control.d.ts +77 -5
- package/dist/agent-control.js +271 -65
- package/dist/client-entry.d.ts +15 -8
- package/dist/client-entry.js +7 -5
- package/dist/client-wire.d.ts +24 -8
- package/dist/client-wire.js +53 -11
- package/dist/client.d.ts +56 -11
- package/dist/client.js +1 -1
- package/dist/cloudflare.d.ts +42 -23
- package/dist/cloudflare.js +76 -54
- package/dist/cold-sessions.d.ts +28 -0
- package/dist/cold-sessions.js +1 -0
- package/dist/delegation.d.ts +214 -0
- package/dist/delegation.js +319 -0
- package/dist/effect.d.ts +1 -1
- package/dist/errors.d.ts +2 -2
- package/dist/errors.js +2 -2
- package/dist/extension-contract.d.ts +10 -2
- package/dist/extensions.d.ts +6 -2
- package/dist/fleet.d.ts +43 -9
- package/dist/fleet.js +88 -25
- package/dist/hosted.js +1 -0
- package/dist/http-routes.d.ts +113 -29
- package/dist/http-routes.js +18 -1
- package/dist/index.d.ts +3 -2
- package/dist/internal/accepted-run-executor.d.ts +5 -0
- package/dist/internal/accepted-run-executor.js +10 -4
- package/dist/internal/admission-door.d.ts +3 -0
- package/dist/internal/admission-door.js +12 -2
- package/dist/internal/client-boundary.js +7 -1
- package/dist/internal/compaction/compaction-slot.d.ts +36 -0
- package/dist/internal/compaction/compaction-slot.js +41 -0
- package/dist/internal/compaction/compaction.d.ts +11 -8
- package/dist/internal/compaction/compaction.js +62 -34
- package/dist/internal/compaction/session-compaction.d.ts +8 -16
- package/dist/internal/compaction/session-compaction.js +358 -119
- package/dist/internal/compaction/settings.d.ts +1 -1
- package/dist/internal/compaction/settings.js +5 -0
- package/dist/internal/compaction/utils.d.ts +19 -16
- package/dist/internal/compaction/utils.js +30 -84
- package/dist/internal/contracts.d.ts +40 -13
- package/dist/internal/coordinator.js +28 -10
- package/dist/internal/effect-client.d.ts +4 -2
- package/dist/internal/effect-client.js +29 -0
- package/dist/internal/effect-contracts.d.ts +17 -4
- package/dist/internal/extension-runtime.d.ts +5 -0
- package/dist/internal/extension-runtime.js +184 -89
- package/dist/internal/host-meta.d.ts +7 -0
- package/dist/internal/model-acquisition.js +7 -1
- package/dist/internal/model-preference.d.ts +4 -2
- package/dist/internal/model-preference.js +2 -1
- package/dist/internal/promise-facade.js +4 -16
- package/dist/internal/run-failure-reason.d.ts +10 -0
- package/dist/internal/run-failure-reason.js +19 -0
- package/dist/internal/run-scope.d.ts +4 -1
- package/dist/internal/run-scope.js +38 -5
- package/dist/internal/runtime-coordinator.d.ts +2 -1
- package/dist/internal/runtime-coordinator.js +65 -4
- package/dist/internal/runtime-core.js +1 -0
- package/dist/internal/runtime-reconciliation.js +42 -6
- package/dist/internal/session-context.d.ts +1 -2
- package/dist/internal/session-context.js +8 -30
- package/dist/internal/session-status.d.ts +2 -1
- package/dist/internal/session-status.js +4 -1
- package/dist/internal/woodstock/client-projection.d.ts +6 -5
- package/dist/internal/woodstock/client-projection.js +79 -53
- package/dist/internal/woodstock/cold-sessions.d.ts +4 -0
- package/dist/internal/woodstock/cold-sessions.js +90 -0
- package/dist/internal/woodstock/extension-store.d.ts +2 -0
- package/dist/internal/woodstock/extension-store.js +4 -0
- package/dist/internal/woodstock/fleet-store.d.ts +5 -1
- package/dist/internal/woodstock/fleet-store.js +17 -5
- package/dist/internal/woodstock/index.d.ts +11 -3
- package/dist/internal/woodstock/index.js +33 -14
- package/dist/internal/woodstock/progress.d.ts +14 -1
- package/dist/internal/woodstock/progress.js +97 -19
- package/dist/internal/woodstock/run-recovery.js +6 -4
- package/dist/internal/woodstock/session-attention.d.ts +1 -1
- package/dist/internal/woodstock/session-attention.js +2 -2
- package/dist/internal/woodstock/session-entry.d.ts +110 -43
- package/dist/internal/woodstock/session-entry.js +63 -20
- package/dist/internal/woodstock/session-inbox.js +2 -0
- package/dist/internal/woodstock/session-store.d.ts +104 -24
- package/dist/internal/woodstock/session-store.js +937 -246
- package/dist/internal/woodstock/storage-admission.d.ts +8 -8
- package/dist/internal/woodstock/storage-admission.js +8 -34
- package/dist/internal/woodstock/storage-conformance.d.ts +15 -0
- package/dist/internal/woodstock/storage-conformance.js +489 -0
- package/dist/model-preference.d.ts +2 -2
- package/dist/model-preference.js +2 -2
- package/dist/node.js +1 -1
- package/dist/remote-client.js +8 -1
- package/dist/session-attention.d.ts +8 -1
- package/dist/session-attention.js +6 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -0
- package/docs/api/README.md +18 -16
- package/docs/api/agent-control.md +171 -1
- package/docs/api/client-entry.md +26 -10
- package/docs/api/client.md +153 -37
- package/docs/api/cloudflare.md +76 -23
- package/docs/api/delegation.md +485 -0
- package/docs/api/effect.md +20 -2
- package/docs/api/extensions.md +21 -9
- package/docs/api/fleet.md +159 -104
- package/docs/api/http.md +4 -1
- package/docs/api/index.md +116 -20
- package/docs/api/internal/woodstock/storage-conformance.md +81 -0
- package/docs/api/model-preference.md +27 -10
- package/docs/api/testing.md +16 -4
- package/package.json +26 -14
- package/dist/internal/browser-sessions.d.ts +0 -31
- package/dist/internal/browser-sessions.js +0 -173
package/dist/cloudflare.js
CHANGED
|
@@ -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
|
|
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.
|
|
251
|
-
|
|
252
|
-
|
|
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.
|
|
295
|
-
Object.assign(base, {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
371
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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
|
-
//
|
|
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
|
+
};
|