@fungi.computer/shiitake 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +454 -2
- package/dist/agar-extension.d.ts +9 -0
- package/dist/agar-extension.js +38 -0
- package/dist/agent-control.d.ts +77 -0
- package/dist/agent-control.js +434 -0
- package/dist/client-entry.d.ts +211 -0
- package/dist/client-entry.js +101 -0
- package/dist/client-wire.d.ts +199 -0
- package/dist/client-wire.js +271 -0
- package/dist/client.d.ts +439 -0
- package/dist/client.js +4 -0
- package/dist/cloudflare.d.ts +220 -0
- package/dist/cloudflare.js +531 -0
- package/dist/effect.d.ts +42 -0
- package/dist/effect.js +20 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.js +81 -0
- package/dist/extension-client.d.ts +38 -0
- package/dist/extension-client.js +56 -0
- package/dist/extension-contract.d.ts +73 -0
- package/dist/extension-contract.js +11 -0
- package/dist/extensions.d.ts +589 -0
- package/dist/extensions.js +263 -0
- package/dist/fleet.d.ts +313 -0
- package/dist/fleet.js +540 -0
- package/dist/hosted.d.ts +133 -0
- package/dist/hosted.js +265 -0
- package/dist/http-routes.d.ts +772 -0
- package/dist/http-routes.js +242 -0
- package/dist/http.d.ts +1 -0
- package/dist/http.js +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +13 -0
- package/dist/internal/accepted-run-executor.d.ts +23 -0
- package/dist/internal/accepted-run-executor.js +129 -0
- package/dist/internal/admission-door.d.ts +75 -0
- package/dist/internal/admission-door.js +105 -0
- package/dist/internal/agent-close.d.ts +4 -0
- package/dist/internal/agent-close.js +42 -0
- package/dist/internal/browser-sessions.d.ts +31 -0
- package/dist/internal/browser-sessions.js +173 -0
- package/dist/internal/client-boundary.d.ts +262 -0
- package/dist/internal/client-boundary.js +202 -0
- package/dist/internal/compaction/compaction.d.ts +54 -0
- package/dist/internal/compaction/compaction.js +291 -0
- package/dist/internal/compaction/session-compaction.d.ts +69 -0
- package/dist/internal/compaction/session-compaction.js +330 -0
- package/dist/internal/compaction/settings.d.ts +11 -0
- package/dist/internal/compaction/settings.js +40 -0
- package/dist/internal/compaction/utils.d.ts +45 -0
- package/dist/internal/compaction/utils.js +319 -0
- package/dist/internal/contracts.d.ts +235 -0
- package/dist/internal/contracts.js +1 -0
- package/dist/internal/coordinator.d.ts +18 -0
- package/dist/internal/coordinator.js +362 -0
- package/dist/internal/document-codec.d.ts +11 -0
- package/dist/internal/document-codec.js +39 -0
- package/dist/internal/effect-client.d.ts +13 -0
- package/dist/internal/effect-client.js +102 -0
- package/dist/internal/effect-contracts.d.ts +236 -0
- package/dist/internal/effect-contracts.js +2 -0
- package/dist/internal/extension-command-registry.d.ts +11 -0
- package/dist/internal/extension-command-registry.js +29 -0
- package/dist/internal/extension-command-tools.d.ts +17 -0
- package/dist/internal/extension-command-tools.js +50 -0
- package/dist/internal/extension-context.d.ts +25 -0
- package/dist/internal/extension-context.js +35 -0
- package/dist/internal/extension-definitions.d.ts +5 -0
- package/dist/internal/extension-definitions.js +6 -0
- package/dist/internal/extension-hook.d.ts +25 -0
- package/dist/internal/extension-hook.js +46 -0
- package/dist/internal/extension-roster.d.ts +23 -0
- package/dist/internal/extension-roster.js +228 -0
- package/dist/internal/extension-runtime.d.ts +63 -0
- package/dist/internal/extension-runtime.js +1004 -0
- package/dist/internal/failure.d.ts +2 -0
- package/dist/internal/failure.js +9 -0
- package/dist/internal/host-meta.d.ts +41 -0
- package/dist/internal/host-meta.js +39 -0
- package/dist/internal/json-value.d.ts +4 -0
- package/dist/internal/json-value.js +3 -0
- package/dist/internal/model-acquisition.d.ts +21 -0
- package/dist/internal/model-acquisition.js +98 -0
- package/dist/internal/model-preference.d.ts +21 -0
- package/dist/internal/model-preference.js +20 -0
- package/dist/internal/observation-kernel.d.ts +28 -0
- package/dist/internal/observation-kernel.js +169 -0
- package/dist/internal/promise-facade.d.ts +18 -0
- package/dist/internal/promise-facade.js +172 -0
- package/dist/internal/run-scope.d.ts +27 -0
- package/dist/internal/run-scope.js +214 -0
- package/dist/internal/runtime-coordinator.d.ts +34 -0
- package/dist/internal/runtime-coordinator.js +233 -0
- package/dist/internal/runtime-core.d.ts +19 -0
- package/dist/internal/runtime-core.js +39 -0
- package/dist/internal/runtime-reconciliation.d.ts +18 -0
- package/dist/internal/runtime-reconciliation.js +162 -0
- package/dist/internal/session-context.d.ts +11 -0
- package/dist/internal/session-context.js +67 -0
- package/dist/internal/session-status.d.ts +10 -0
- package/dist/internal/session-status.js +52 -0
- package/dist/internal/woodstock/agent-reply.d.ts +25 -0
- package/dist/internal/woodstock/agent-reply.js +67 -0
- package/dist/internal/woodstock/client-projection.d.ts +29 -0
- package/dist/internal/woodstock/client-projection.js +512 -0
- package/dist/internal/woodstock/compaction-activity.d.ts +17 -0
- package/dist/internal/woodstock/compaction-activity.js +32 -0
- package/dist/internal/woodstock/cursor.d.ts +9 -0
- package/dist/internal/woodstock/cursor.js +44 -0
- package/dist/internal/woodstock/extension-store.d.ts +72 -0
- package/dist/internal/woodstock/extension-store.js +262 -0
- package/dist/internal/woodstock/fleet-store.d.ts +36 -0
- package/dist/internal/woodstock/fleet-store.js +100 -0
- package/dist/internal/woodstock/identities.d.ts +6 -0
- package/dist/internal/woodstock/identities.js +11 -0
- package/dist/internal/woodstock/index.d.ts +170 -0
- package/dist/internal/woodstock/index.js +546 -0
- package/dist/internal/woodstock/progress.d.ts +32 -0
- package/dist/internal/woodstock/progress.js +89 -0
- package/dist/internal/woodstock/run-recovery.d.ts +8 -0
- package/dist/internal/woodstock/run-recovery.js +95 -0
- package/dist/internal/woodstock/session-attention.d.ts +16 -0
- package/dist/internal/woodstock/session-attention.js +88 -0
- package/dist/internal/woodstock/session-documents.d.ts +18 -0
- package/dist/internal/woodstock/session-documents.js +51 -0
- package/dist/internal/woodstock/session-entry.d.ts +478 -0
- package/dist/internal/woodstock/session-entry.js +484 -0
- package/dist/internal/woodstock/session-grants.d.ts +24 -0
- package/dist/internal/woodstock/session-grants.js +84 -0
- package/dist/internal/woodstock/session-inbox.d.ts +56 -0
- package/dist/internal/woodstock/session-inbox.js +307 -0
- package/dist/internal/woodstock/session-store.d.ts +432 -0
- package/dist/internal/woodstock/session-store.js +2006 -0
- package/dist/internal/woodstock/storage-admission.d.ts +14 -0
- package/dist/internal/woodstock/storage-admission.js +44 -0
- package/dist/model-preference.d.ts +20 -0
- package/dist/model-preference.js +30 -0
- package/dist/node.d.ts +64 -0
- package/dist/node.js +256 -0
- package/dist/remote-client.d.ts +11 -0
- package/dist/remote-client.js +298 -0
- package/dist/session-attention.d.ts +35 -0
- package/dist/session-attention.js +22 -0
- package/dist/session-documents.d.ts +28 -0
- package/dist/session-documents.js +1 -0
- package/dist/testing.d.ts +54 -0
- package/dist/testing.js +215 -0
- package/docs/api/README.md +26 -0
- package/docs/api/agar-extension.md +40 -0
- package/docs/api/agent-control.md +151 -0
- package/docs/api/client-entry.md +344 -0
- package/docs/api/client.md +1112 -0
- package/docs/api/cloudflare.md +500 -0
- package/docs/api/effect.md +884 -0
- package/docs/api/extensions.md +2003 -0
- package/docs/api/fleet.md +734 -0
- package/docs/api/hosted.md +382 -0
- package/docs/api/http.md +111 -0
- package/docs/api/index.md +1116 -0
- package/docs/api/model-preference.md +151 -0
- package/docs/api/node.md +142 -0
- package/docs/api/testing.md +250 -0
- package/package.json +130 -3
|
@@ -0,0 +1,531 @@
|
|
|
1
|
+
import { DurableObject } from "cloudflare:workers";
|
|
2
|
+
import { fromTypedSandbox } from "@fungi.computer/mycelium/effect";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Deferred from "effect/Deferred";
|
|
5
|
+
import * as Redacted from "effect/Redacted";
|
|
6
|
+
import { WatchdogError, } from "@fungi.computer/watchdog";
|
|
7
|
+
import { composeAgentClose } from "./internal/agent-close.js";
|
|
8
|
+
import { ShiitakeError } from "./errors.js";
|
|
9
|
+
import { createShiitakeHttpRoutes, } from "./http-routes.js";
|
|
10
|
+
import { Hono } from "hono";
|
|
11
|
+
import { runShiitakePromise, toPromiseOwner, } from "./internal/effect-client.js";
|
|
12
|
+
import { adaptModelSource } from "./internal/model-acquisition.js";
|
|
13
|
+
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";
|
|
16
|
+
/**
|
|
17
|
+
* Deliver one Session's grants into a Cloudflare owner's own storage,
|
|
18
|
+
* synchronously, whether or not its runtime is open; the very next tool call
|
|
19
|
+
* reads it. A plain function, not a Durable Object method, so no other
|
|
20
|
+
* Durable Object can call it over RPC: only code running inside the owner,
|
|
21
|
+
* holding its storage, delivers grants.
|
|
22
|
+
*/
|
|
23
|
+
export function deliverSessionGrantsToStorage(storage, sessionId, delivery) {
|
|
24
|
+
return storage.transactionSync(() => {
|
|
25
|
+
prepareSessionGrants(storage);
|
|
26
|
+
return deliverSessionGrants(storage, decodeClientSessionId(sessionId), delivery);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function runtimeFailure(cause, message) {
|
|
30
|
+
return new ShiitakeError("runtime", cause, message);
|
|
31
|
+
}
|
|
32
|
+
function earliest(a, b) {
|
|
33
|
+
if (a === null)
|
|
34
|
+
return b;
|
|
35
|
+
return b === null ? a : Math.min(a, b);
|
|
36
|
+
}
|
|
37
|
+
/** Bounded backoff for a native alarm that failed outside any reconciliation. */
|
|
38
|
+
const ALARM_RETRY_BASE_MS = 1_000;
|
|
39
|
+
const ALARM_RETRY_CAP_MS = 30_000;
|
|
40
|
+
/** Exponential growth from one failed alarm attempt, never past the cap. */
|
|
41
|
+
function alarmRetryDelayMs(consecutiveFailures) {
|
|
42
|
+
return Math.min(ALARM_RETRY_BASE_MS * 2 ** (consecutiveFailures - 1), ALARM_RETRY_CAP_MS);
|
|
43
|
+
}
|
|
44
|
+
/** One native alarm protects queued and executing owner-local work. */
|
|
45
|
+
function runtimeHost(state, hostWork = [], startup) {
|
|
46
|
+
let alarm;
|
|
47
|
+
const runtime = {
|
|
48
|
+
bind: ({ reconcile, pendingWork }) => Effect.sync(() => {
|
|
49
|
+
let closed = false;
|
|
50
|
+
const isClosed = () => closed;
|
|
51
|
+
let mutationVersion = Symbol();
|
|
52
|
+
const arm = async () => {
|
|
53
|
+
const existing = await state.storage.getAlarm();
|
|
54
|
+
const recoveryAt = Date.now() + 5_000;
|
|
55
|
+
await state.storage.setAlarm(existing === null ? recoveryAt : Math.min(existing, recoveryAt));
|
|
56
|
+
};
|
|
57
|
+
/** Arm at the earliest due time (host work included), or disarm. */
|
|
58
|
+
const armAt = async (due) => {
|
|
59
|
+
if (due === null)
|
|
60
|
+
await state.storage.deleteAlarm();
|
|
61
|
+
else
|
|
62
|
+
await state.storage.setAlarm(due);
|
|
63
|
+
};
|
|
64
|
+
const unavailable = () => runtimeFailure("unavailable", "Shiitake durable wake is unavailable");
|
|
65
|
+
const persistWake = Effect.tryPromise({ try: arm, catch: unavailable });
|
|
66
|
+
const hostPass = async () => {
|
|
67
|
+
const failures = [];
|
|
68
|
+
for (const [moduleIndex, work] of hostWork.entries()) {
|
|
69
|
+
try {
|
|
70
|
+
await work.run();
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
await runShiitakePromise(Effect.logError("shiitake_reconciliation_failed", Redacted.make(error)).pipe(Effect.annotateLogs({
|
|
74
|
+
operation: "host-work.run",
|
|
75
|
+
moduleIndex,
|
|
76
|
+
failureKind: error instanceof Error ? "Error" : "NonErrorThrown",
|
|
77
|
+
})));
|
|
78
|
+
failures.push(error);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (failures.length > 0)
|
|
82
|
+
throw new AggregateError(failures, "Host work failed");
|
|
83
|
+
};
|
|
84
|
+
function pass(run) {
|
|
85
|
+
let active;
|
|
86
|
+
let rerun = false;
|
|
87
|
+
let retry = false;
|
|
88
|
+
const slot = {
|
|
89
|
+
get active() {
|
|
90
|
+
return active;
|
|
91
|
+
},
|
|
92
|
+
get rerun() {
|
|
93
|
+
return rerun;
|
|
94
|
+
},
|
|
95
|
+
get retry() {
|
|
96
|
+
return retry;
|
|
97
|
+
},
|
|
98
|
+
stop() {
|
|
99
|
+
rerun = false;
|
|
100
|
+
},
|
|
101
|
+
schedule,
|
|
102
|
+
};
|
|
103
|
+
function schedule() {
|
|
104
|
+
if (closed)
|
|
105
|
+
return;
|
|
106
|
+
if (active !== undefined) {
|
|
107
|
+
rerun = true;
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
const task = Promise.resolve().then(async () => {
|
|
111
|
+
const reconciledVersion = mutationVersion;
|
|
112
|
+
try {
|
|
113
|
+
// Recover only after owner startup commands have committed.
|
|
114
|
+
if (!(await runShiitakePromise(startup)) || isClosed())
|
|
115
|
+
return;
|
|
116
|
+
await run();
|
|
117
|
+
if (closed)
|
|
118
|
+
return;
|
|
119
|
+
retry = false;
|
|
120
|
+
// Native transactions serialize this read/disarm with acceptance.
|
|
121
|
+
await state.storage.transaction(async () => {
|
|
122
|
+
if (closed)
|
|
123
|
+
return;
|
|
124
|
+
const owned = await runShiitakePromise(pendingWork);
|
|
125
|
+
const host = hostWork.reduce((pending, work) => {
|
|
126
|
+
const next = work.pending();
|
|
127
|
+
return {
|
|
128
|
+
due: pending.due || next.due,
|
|
129
|
+
nextWakeAt: earliest(pending.nextWakeAt, next.nextWakeAt),
|
|
130
|
+
};
|
|
131
|
+
}, { due: false, nextWakeAt: null });
|
|
132
|
+
const pending = {
|
|
133
|
+
pending: owned.pending || host.due,
|
|
134
|
+
nextWakeAt: earliest(owned.nextWakeAt, host.nextWakeAt),
|
|
135
|
+
};
|
|
136
|
+
// A mutation can need reconciliation before it creates a job
|
|
137
|
+
// (for example an extension command that sets a timer). An older
|
|
138
|
+
// run cannot disarm it.
|
|
139
|
+
if (reconciledVersion !== mutationVersion ||
|
|
140
|
+
passes.some((other) => other.retry ||
|
|
141
|
+
other.rerun ||
|
|
142
|
+
(other !== slot && other.active !== undefined)) ||
|
|
143
|
+
pending.pending)
|
|
144
|
+
await arm();
|
|
145
|
+
else
|
|
146
|
+
await armAt(pending.nextWakeAt);
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
retry = true;
|
|
151
|
+
// Not an Effect here: this is a plain async callback driven by
|
|
152
|
+
// waitUntil. runShiitakePromise is the same bridge the rest of
|
|
153
|
+
// this file uses to reach the host's configured Logger.
|
|
154
|
+
// Retain the original failure without printing provider or Session
|
|
155
|
+
// data: Effect's default Logger does not redact raw Error objects.
|
|
156
|
+
await runShiitakePromise(Effect.logError("shiitake_reconciliation_failed", Redacted.make(error)).pipe(Effect.annotateLogs({
|
|
157
|
+
operation: "durable-wake.reconcile",
|
|
158
|
+
failureKind: error instanceof Error ? "Error" : "NonErrorThrown",
|
|
159
|
+
})));
|
|
160
|
+
// Keep recovery independent of another request, including failure
|
|
161
|
+
// after job settlement but before Session reconciliation finishes.
|
|
162
|
+
if (!closed)
|
|
163
|
+
await arm();
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
if (active === task)
|
|
167
|
+
active = undefined;
|
|
168
|
+
if (rerun) {
|
|
169
|
+
rerun = false;
|
|
170
|
+
schedule();
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
active = task;
|
|
175
|
+
state.waitUntil(task);
|
|
176
|
+
}
|
|
177
|
+
return slot;
|
|
178
|
+
}
|
|
179
|
+
const passes = [
|
|
180
|
+
pass(() => runShiitakePromise(reconcile)),
|
|
181
|
+
pass(hostPass),
|
|
182
|
+
];
|
|
183
|
+
function schedule() {
|
|
184
|
+
for (const slot of passes)
|
|
185
|
+
slot.schedule();
|
|
186
|
+
}
|
|
187
|
+
const requestWake = Effect.suspend(() => closed
|
|
188
|
+
? Effect.fail(runtimeFailure("closed", "Shiitake runtime is closed"))
|
|
189
|
+
: persistWake.pipe(Effect.tap(() => Effect.sync(schedule))));
|
|
190
|
+
alarm = () => runShiitakePromise(requestWake);
|
|
191
|
+
return Object.freeze({
|
|
192
|
+
commit: (mutation) => Effect.tryPromise({
|
|
193
|
+
try: () => state.storage.transaction(async () => {
|
|
194
|
+
const result = await runShiitakePromise(mutation);
|
|
195
|
+
// Invalidate before the transaction returns, including a lost
|
|
196
|
+
// commit acknowledgement. Rollback may cause one extra wake.
|
|
197
|
+
mutationVersion = Symbol();
|
|
198
|
+
await arm();
|
|
199
|
+
return result;
|
|
200
|
+
}),
|
|
201
|
+
catch: (error) => error instanceof ShiitakeError ? error : unavailable(),
|
|
202
|
+
}),
|
|
203
|
+
requestWake,
|
|
204
|
+
close: Effect.suspend(() => {
|
|
205
|
+
closed = true;
|
|
206
|
+
for (const slot of passes)
|
|
207
|
+
slot.stop();
|
|
208
|
+
return Effect.tryPromise({
|
|
209
|
+
try: async () => {
|
|
210
|
+
const active = passes.flatMap((slot) => slot.active === undefined ? [] : [slot.active]);
|
|
211
|
+
const outcomes = await Promise.allSettled(active);
|
|
212
|
+
const failures = [];
|
|
213
|
+
for (const outcome of outcomes) {
|
|
214
|
+
if (outcome.status === "rejected")
|
|
215
|
+
failures.push(outcome.reason);
|
|
216
|
+
}
|
|
217
|
+
if (failures.length > 0)
|
|
218
|
+
throw new AggregateError(failures, "Runtime close failed");
|
|
219
|
+
},
|
|
220
|
+
catch: unavailable,
|
|
221
|
+
});
|
|
222
|
+
}),
|
|
223
|
+
});
|
|
224
|
+
}),
|
|
225
|
+
};
|
|
226
|
+
return {
|
|
227
|
+
runtime,
|
|
228
|
+
alarm: () => alarm === undefined
|
|
229
|
+
? Promise.reject(runtimeFailure("unavailable", "Shiitake runtime is not bound"))
|
|
230
|
+
: alarm(),
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
function configuredTools(tools) {
|
|
234
|
+
if (tools === undefined || !("sandbox" in tools))
|
|
235
|
+
return undefined;
|
|
236
|
+
return {
|
|
237
|
+
modules: tools.modules ?? [],
|
|
238
|
+
sources: tools.sources ?? [],
|
|
239
|
+
sandbox: fromTypedSandbox(tools.sandbox),
|
|
240
|
+
access: tools.access ?? {},
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function effectOptions(state, options, runtime, browser) {
|
|
244
|
+
const tools = configuredTools(options.tools);
|
|
245
|
+
const base = {
|
|
246
|
+
store: state.storage,
|
|
247
|
+
runtime,
|
|
248
|
+
extensions: options.extensions,
|
|
249
|
+
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
|
+
};
|
|
267
|
+
}),
|
|
268
|
+
},
|
|
269
|
+
model: adaptModelSource(options.model),
|
|
270
|
+
};
|
|
271
|
+
if (options.hostJobs !== undefined) {
|
|
272
|
+
const hostJobs = options.hostJobs;
|
|
273
|
+
Object.assign(base, {
|
|
274
|
+
hostJobs: {
|
|
275
|
+
lane: hostJobs.lane,
|
|
276
|
+
open: (watchdog) => {
|
|
277
|
+
const host = hostJobs.open({
|
|
278
|
+
transactional: watchdog.transactional,
|
|
279
|
+
readJob: (jobId) => runShiitakePromise(watchdog.read(jobId)),
|
|
280
|
+
tickConcurrent: () => runShiitakePromise(watchdog.tickConcurrent()),
|
|
281
|
+
});
|
|
282
|
+
return {
|
|
283
|
+
execute: (job) => Effect.tryPromise({
|
|
284
|
+
try: () => host.execute(job),
|
|
285
|
+
catch: (error) => new WatchdogError("execution_failed", error),
|
|
286
|
+
}),
|
|
287
|
+
};
|
|
288
|
+
},
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
if (options.meta !== undefined)
|
|
293
|
+
Object.assign(base, { meta: options.meta });
|
|
294
|
+
if (options.storageBudget !== undefined)
|
|
295
|
+
Object.assign(base, { storageBudget: options.storageBudget });
|
|
296
|
+
if (options.compaction !== undefined)
|
|
297
|
+
Object.assign(base, { compaction: options.compaction });
|
|
298
|
+
return tools === undefined ? base : { ...base, tools };
|
|
299
|
+
}
|
|
300
|
+
/** Construct Shiitake over one Durable Object's SQLite and lifetime. */
|
|
301
|
+
export function makeCloudflareShiitake(state, options) {
|
|
302
|
+
const startup = Deferred.makeUnsafe();
|
|
303
|
+
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);
|
|
308
|
+
return import("./internal/runtime-core.js")
|
|
309
|
+
.then(({ openRuntimeCore }) => runShiitakePromise(openRuntimeCore(coreOptions, options.mailRoom)))
|
|
310
|
+
.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
|
+
const handle = toPromiseOwner(agent);
|
|
316
|
+
try {
|
|
317
|
+
await options.initialize?.(handle);
|
|
318
|
+
}
|
|
319
|
+
catch (cause) {
|
|
320
|
+
await runShiitakePromise(Deferred.succeed(startup, false));
|
|
321
|
+
await runShiitakePromise(close);
|
|
322
|
+
throw cause;
|
|
323
|
+
}
|
|
324
|
+
await runShiitakePromise(Deferred.succeed(startup, true));
|
|
325
|
+
return Object.freeze({
|
|
326
|
+
...handle,
|
|
327
|
+
readSettlement: (sessionId, commandId) => runShiitakePromise(readSettlement(sessionId, commandId)),
|
|
328
|
+
acceptMail: (mail, meta, reply) => {
|
|
329
|
+
if (options.mailRoom === undefined)
|
|
330
|
+
return Promise.reject(runtimeFailure("unavailable", "Addressed mail is unavailable"));
|
|
331
|
+
return runShiitakePromise(acceptMail(mail, meta, reply));
|
|
332
|
+
},
|
|
333
|
+
close: () => runShiitakePromise(close),
|
|
334
|
+
alarm: host.alarm,
|
|
335
|
+
activeSessions: () => runShiitakePromise(activeSessions),
|
|
336
|
+
abortActive: async () => {
|
|
337
|
+
for (const sessionId of await runShiitakePromise(activeSessions))
|
|
338
|
+
await runShiitakePromise(agent.session(sessionId).abort);
|
|
339
|
+
},
|
|
340
|
+
browser: {
|
|
341
|
+
fetch: (request) => browser?.fetch(request) ??
|
|
342
|
+
Promise.resolve(new Response(null, { status: 404 })),
|
|
343
|
+
clear: () => browser?.clear() ?? Promise.resolve(),
|
|
344
|
+
},
|
|
345
|
+
});
|
|
346
|
+
}, async (cause) => {
|
|
347
|
+
await runShiitakePromise(Deferred.succeed(startup, false));
|
|
348
|
+
throw cause;
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
/** Owns runtime opening, HTTP/ACP transport, inbox observation and alarm recovery. */
|
|
352
|
+
export class ShiitakeOwner {
|
|
353
|
+
ctx;
|
|
354
|
+
env;
|
|
355
|
+
constructor(ctx, env) {
|
|
356
|
+
this.ctx = ctx;
|
|
357
|
+
this.env = env;
|
|
358
|
+
}
|
|
359
|
+
agentPromise;
|
|
360
|
+
openAcp;
|
|
361
|
+
acpServer;
|
|
362
|
+
/** Consecutive native alarm failures; reset on the next successful alarm. */
|
|
363
|
+
alarmFailures = 0;
|
|
364
|
+
routes = createShiitakeHttpRoutes(async (sessionId, meta) => {
|
|
365
|
+
const agent = await this.shiitake();
|
|
366
|
+
return (meta === undefined ? agent : agent.withMeta(meta)).session(sessionId);
|
|
367
|
+
}, 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
|
+
/** Borrow this owner's runtime directly; only the host owns its lifetime. */
|
|
369
|
+
async shiitake() {
|
|
370
|
+
if (this.agentPromise === undefined) {
|
|
371
|
+
const options = this.shiitakeOptions();
|
|
372
|
+
this.openAcp = options.acp;
|
|
373
|
+
this.agentPromise = makeCloudflareShiitake(this.ctx, options);
|
|
374
|
+
}
|
|
375
|
+
try {
|
|
376
|
+
return await this.agentPromise;
|
|
377
|
+
}
|
|
378
|
+
catch (error) {
|
|
379
|
+
this.agentPromise = undefined;
|
|
380
|
+
throw error;
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
/** Stop live execution without constructing a cold owner's runtime. */
|
|
384
|
+
async abortActiveSessions() {
|
|
385
|
+
await (await this.agentPromise)?.abortActive();
|
|
386
|
+
}
|
|
387
|
+
/** Close owned resources before storage erasure; a cold owner has none. */
|
|
388
|
+
async closeShiitake() {
|
|
389
|
+
await (await this.agentPromise)?.close();
|
|
390
|
+
}
|
|
391
|
+
/** Indexed owner-local existence check; corrupt stored Sessions remain unavailable. */
|
|
392
|
+
async hasStoredSession(sessionId) {
|
|
393
|
+
await this.shiitake();
|
|
394
|
+
const inbox = readSessionInboxSummary(this.ctx.storage, sessionId);
|
|
395
|
+
if (inbox === undefined || inbox.state === "unavailable")
|
|
396
|
+
return false;
|
|
397
|
+
return ((await runShiitakePromise(readSessionSummary(this.ctx.storage, sessionId))) !== undefined);
|
|
398
|
+
}
|
|
399
|
+
/** Bounded strict-after read of this Agent's changed inbox rows. */
|
|
400
|
+
async readInboxChanges(after, limit) {
|
|
401
|
+
await this.shiitake();
|
|
402
|
+
return readSessionInboxChanges(this.ctx.storage, after, limit);
|
|
403
|
+
}
|
|
404
|
+
/** Latest inbox revision; read only after the owner has opened. */
|
|
405
|
+
readInboxRevision() {
|
|
406
|
+
return readSessionInboxChanges(this.ctx.storage, Number.MAX_SAFE_INTEGER, 0)
|
|
407
|
+
.latest;
|
|
408
|
+
}
|
|
409
|
+
/** Prune deletion deltas after every current member inbox has acknowledged them. */
|
|
410
|
+
pruneInboxTombstones(through) {
|
|
411
|
+
pruneSessionInboxTombstones(this.ctx.storage, through);
|
|
412
|
+
}
|
|
413
|
+
/** Persist a wake and run one reconciliation pass, including host work. */
|
|
414
|
+
async wakeRuntime() {
|
|
415
|
+
await (await this.shiitake()).alarm();
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Native alarms reconstruct the owner without an incoming user request.
|
|
419
|
+
* A construction or wake failure must not strand the claimed work on
|
|
420
|
+
* platform alarm retries: it is caught, logged, and explicitly re-armed
|
|
421
|
+
* with bounded backoff instead.
|
|
422
|
+
*/
|
|
423
|
+
async alarm() {
|
|
424
|
+
try {
|
|
425
|
+
await (await this.shiitake()).alarm();
|
|
426
|
+
this.alarmFailures = 0;
|
|
427
|
+
}
|
|
428
|
+
catch (error) {
|
|
429
|
+
this.alarmFailures += 1;
|
|
430
|
+
const attempt = this.alarmFailures;
|
|
431
|
+
const retryInMs = alarmRetryDelayMs(attempt);
|
|
432
|
+
await runShiitakePromise(Effect.logError("shiitake_alarm_failed").pipe(Effect.annotateLogs({
|
|
433
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
434
|
+
attempt,
|
|
435
|
+
retryInMs,
|
|
436
|
+
})));
|
|
437
|
+
try {
|
|
438
|
+
await this.ctx.storage.setAlarm(Date.now() + retryInMs);
|
|
439
|
+
}
|
|
440
|
+
catch (rearmError) {
|
|
441
|
+
// The platform's own alarm retry is the last resort if even this
|
|
442
|
+
// explicit re-arm fails; surface it rather than fail silently.
|
|
443
|
+
await runShiitakePromise(Effect.logError("shiitake_alarm_rearm_failed").pipe(Effect.annotateLogs({
|
|
444
|
+
cause: rearmError instanceof Error
|
|
445
|
+
? rearmError.message
|
|
446
|
+
: String(rearmError),
|
|
447
|
+
attempt,
|
|
448
|
+
})));
|
|
449
|
+
throw error;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
/** Serve Shiitake's complete transport without subclass routing. */
|
|
454
|
+
app;
|
|
455
|
+
/**
|
|
456
|
+
* Shiitake's whole HTTP surface (Session routes, browser and ACP) as one
|
|
457
|
+
* Hono app. A host mounts it behind its own middleware, which alone may
|
|
458
|
+
* set the `shiitakeMeta` variable.
|
|
459
|
+
*/
|
|
460
|
+
shiitakeApp() {
|
|
461
|
+
return (this.app ??= new Hono()
|
|
462
|
+
.all("/browser/*", async (context) => (await this.shiitake()).browser.fetch(context.req.raw))
|
|
463
|
+
.all("/acp", async (context) => {
|
|
464
|
+
const agent = await this.shiitake();
|
|
465
|
+
if (this.openAcp === undefined)
|
|
466
|
+
return new Response(null, { status: 404 });
|
|
467
|
+
const opening = (this.acpServer ??= this.openAcp(agent));
|
|
468
|
+
let server;
|
|
469
|
+
try {
|
|
470
|
+
server = await opening;
|
|
471
|
+
}
|
|
472
|
+
catch (error) {
|
|
473
|
+
if (this.acpServer === opening)
|
|
474
|
+
this.acpServer = undefined;
|
|
475
|
+
throw error;
|
|
476
|
+
}
|
|
477
|
+
return server.handleRequest(context.req.raw, context.get("shiitakeMeta"));
|
|
478
|
+
})
|
|
479
|
+
.route("/", this.routes)
|
|
480
|
+
// Browser and ACP failures reach the Durable Object caller unchanged,
|
|
481
|
+
// as they did before the routes shared one app.
|
|
482
|
+
.onError((error) => {
|
|
483
|
+
throw error;
|
|
484
|
+
}));
|
|
485
|
+
}
|
|
486
|
+
/** Serve one request through Shiitake's whole HTTP surface. */
|
|
487
|
+
async fetch(request) {
|
|
488
|
+
return await this.shiitakeApp().fetch(request);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
/** Native Cloudflare entry points; all runtime lifetime belongs to the owner. */
|
|
492
|
+
export class ShiitakeDO extends DurableObject {
|
|
493
|
+
#owner;
|
|
494
|
+
runtimeOwner() {
|
|
495
|
+
const options = () => this.shiitakeOptions();
|
|
496
|
+
return (this.#owner ??= new (class extends ShiitakeOwner {
|
|
497
|
+
shiitakeOptions() {
|
|
498
|
+
return options();
|
|
499
|
+
}
|
|
500
|
+
})(this.ctx, this.env));
|
|
501
|
+
}
|
|
502
|
+
shiitake() {
|
|
503
|
+
return this.runtimeOwner().shiitake();
|
|
504
|
+
}
|
|
505
|
+
abortActiveSessions() {
|
|
506
|
+
return this.runtimeOwner().abortActiveSessions();
|
|
507
|
+
}
|
|
508
|
+
closeShiitake() {
|
|
509
|
+
return this.runtimeOwner().closeShiitake();
|
|
510
|
+
}
|
|
511
|
+
readInboxChanges(after, limit) {
|
|
512
|
+
return this.runtimeOwner().readInboxChanges(after, limit);
|
|
513
|
+
}
|
|
514
|
+
readInboxRevision() {
|
|
515
|
+
return this.runtimeOwner().readInboxRevision();
|
|
516
|
+
}
|
|
517
|
+
pruneInboxTombstones(through) {
|
|
518
|
+
this.runtimeOwner().pruneInboxTombstones(through);
|
|
519
|
+
}
|
|
520
|
+
wakeRuntime() {
|
|
521
|
+
return this.runtimeOwner().wakeRuntime();
|
|
522
|
+
}
|
|
523
|
+
/** Reconcile due runtime and host work through the owner. */
|
|
524
|
+
alarm() {
|
|
525
|
+
return this.runtimeOwner().alarm();
|
|
526
|
+
}
|
|
527
|
+
/** Route an authenticated client request through the owner. */
|
|
528
|
+
fetch(request) {
|
|
529
|
+
return this.runtimeOwner().fetch(request);
|
|
530
|
+
}
|
|
531
|
+
}
|
package/dist/effect.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { CommandSettlement } from "./internal/contracts.js";
|
|
2
|
+
import type { Json as HostJson } from "./extensions.js";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import type { BirdDogMail } from "@fungi.computer/bird-dog";
|
|
5
|
+
import type { VerifiedAgentReply } from "./internal/woodstock/index.js";
|
|
6
|
+
import type { BirdDogEffect } from "@fungi.computer/bird-dog/effect";
|
|
7
|
+
import type { Accepted } from "./client.js";
|
|
8
|
+
import type { ShiitakeError } from "./errors.js";
|
|
9
|
+
import type { ShiitakeEffectOptions, ShiitakeEffectOwner } from "./internal/effect-contracts.js";
|
|
10
|
+
import type { SqliteOwner } from "./internal/contracts.js";
|
|
11
|
+
export type { AbortCommand, BranchCommand, CompactCommand, CancelCommand, CancelResult, Accepted, ForkCommand, ForkedSession, PromptCommand, PromptDelivery, ReadOptions, SessionCommand, SessionCommandHandler, SessionFrame, SessionMessage, SessionProgress, SessionSnapshot, SessionActivity, AgentRunningWork, SubscribeOptions, TooLate, WatchOptions, } from "./client.js";
|
|
12
|
+
export type { InstructionSnapshot, InstructionSource, ModelAcquisition, ModelDescription, ModelSource, RuntimeHost, RuntimePendingWork, SqliteCursor, SqliteOwner, SqliteValue, SqliteRow, GrantsDelivery, GrantsDeliveryResult, ShiitakeOptions, ToolAccess, HostMetaOptions, StandardHostMetaResult, StandardHostMetaSchema, ToolSource, } from "./internal/contracts.js";
|
|
13
|
+
export type { InstructionSourceEffect, ModelAcquisitionEffect, ModelSourceEffect, RuntimeHostEffect, ShiitakeEffectAgent, ShiitakeEffectAgentExtensions, ShiitakeEffectCommandHandler, ShiitakeEffectOptions, ShiitakeEffectOwner, ShiitakeEffectSession, ShiitakeEffectSessionExtension, ShiitakeEffectSendOptions, ShiitakeEffectWatch, ToolSourceEffect, } from "./internal/effect-contracts.js";
|
|
14
|
+
export type { SessionSummary } from "./client.js";
|
|
15
|
+
export type { BorrowedCompactionViewV0, CompactionHandoffErrorV0, CompactionHandoffResultV0, CompactionHandoffV0, ExtensionCapabilityV0, ExtensionGrantV0, ExtensionRosterV0, ExtensionSlotV0, ExtensionStatusV0, RosteredExtensionV0, } from "./extensions.js";
|
|
16
|
+
export { ShiitakeError } from "./errors.js";
|
|
17
|
+
/** Construct the canonical Effect-native Shiitake scaffold. */
|
|
18
|
+
export declare function make(options: ShiitakeEffectOptions): Effect.Effect<ShiitakeEffectOwner, ShiitakeError>;
|
|
19
|
+
/** Effect-native host composition with addressed mail kept off Session. */
|
|
20
|
+
export type ShiitakeEffectHost = Readonly<{
|
|
21
|
+
/** Exact settled command facts; available only to the composing host. */
|
|
22
|
+
readSettlement: (sessionId: string, commandId: string) => Effect.Effect<CommandSettlement | undefined, ShiitakeError>;
|
|
23
|
+
agent: ShiitakeEffectOwner;
|
|
24
|
+
/** Durably admit one addressed mail item through the host owner. */
|
|
25
|
+
acceptMail: (mail: BirdDogMail, meta?: HostJson, reply?: VerifiedAgentReply) => Effect.Effect<Accepted, ShiitakeError>;
|
|
26
|
+
}>;
|
|
27
|
+
/** Open the Effect-native host composition with addressed mail. */
|
|
28
|
+
export declare function openHost(options: ShiitakeEffectOptions, mailRoom: BirdDogEffect): Effect.Effect<ShiitakeEffectHost, ShiitakeError>;
|
|
29
|
+
export type { ModelPreference } from "./internal/model-preference.js";
|
|
30
|
+
export type { SessionSummaryPage, SessionSummaryRow } from "./client.js";
|
|
31
|
+
export type { StoredSessionSummary, StoredSessionSummaryPage, StoredSessionSummaryRow, } from "./internal/woodstock/index.js";
|
|
32
|
+
/**
|
|
33
|
+
* Enumerate saved conversations' stored facts in bounded pages, for readers
|
|
34
|
+
* that hold only the store. Run status is not stored; use the Agent's
|
|
35
|
+
* `listSessions` for it. An unreadable Session is its own `unavailable` row.
|
|
36
|
+
*/
|
|
37
|
+
export declare function readSessionSummaries(owner: SqliteOwner, after?: string): Effect.Effect<Readonly<{
|
|
38
|
+
sessions: readonly import("./internal/woodstock/session-store.js").StoredSessionSummaryRow[];
|
|
39
|
+
next: string | undefined;
|
|
40
|
+
}>, ShiitakeError, never>;
|
|
41
|
+
export { sqliteRowSchema } from "./internal/contracts.js";
|
|
42
|
+
export type { CommandSettlement } from "./internal/contracts.js";
|
package/dist/effect.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import { readSessionFactPage } from "./internal/woodstock/index.js";
|
|
3
|
+
export { ShiitakeError } from "./errors.js";
|
|
4
|
+
/** Construct the canonical Effect-native Shiitake scaffold. */
|
|
5
|
+
export function make(options) {
|
|
6
|
+
return Effect.promise(() => import("./internal/runtime-core.js")).pipe(Effect.flatMap(({ openRuntimeCore }) => openRuntimeCore(options)), Effect.map(({ agent }) => agent));
|
|
7
|
+
}
|
|
8
|
+
/** Open the Effect-native host composition with addressed mail. */
|
|
9
|
+
export function openHost(options, mailRoom) {
|
|
10
|
+
return Effect.promise(() => import("./internal/runtime-core.js")).pipe(Effect.flatMap(({ openRuntimeCore }) => openRuntimeCore(options, mailRoom)));
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Enumerate saved conversations' stored facts in bounded pages, for readers
|
|
14
|
+
* that hold only the store. Run status is not stored; use the Agent's
|
|
15
|
+
* `listSessions` for it. An unreadable Session is its own `unavailable` row.
|
|
16
|
+
*/
|
|
17
|
+
export function readSessionSummaries(owner, after) {
|
|
18
|
+
return readSessionFactPage(owner, after);
|
|
19
|
+
}
|
|
20
|
+
export { sqliteRowSchema } from "./internal/contracts.js";
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
/** Stable boundary that rejected a Shiitake operation. */
|
|
3
|
+
declare const ShiitakeErrorBoundarySchema: Schema.Literals<readonly ["contract", "extensions", "instructions", "model", "runtime", "store", "tools"]>;
|
|
4
|
+
/** Stable boundary that rejected a Shiitake operation. */
|
|
5
|
+
export type ShiitakeErrorBoundary = Schema.Schema.Type<typeof ShiitakeErrorBoundarySchema>;
|
|
6
|
+
/** Safe failure category exposed by both Shiitake facades. */
|
|
7
|
+
declare const ShiitakeErrorCauseSchema: Schema.Literals<readonly ["closed", "conflict", "incompatible", "invalid", "rejected", "unavailable", "storage_pressure", "context_too_large"]>;
|
|
8
|
+
/** Safe failure category exposed by both Shiitake facades. */
|
|
9
|
+
export type ShiitakeErrorCause = Schema.Schema.Type<typeof ShiitakeErrorCauseSchema>;
|
|
10
|
+
/** Canonical serialized Shiitake failure. */
|
|
11
|
+
export declare const ShiitakeErrorWireSchema: Schema.Struct<{
|
|
12
|
+
readonly _tag: Schema.Literal<"ShiitakeError">;
|
|
13
|
+
readonly boundary: Schema.Literals<readonly ["contract", "extensions", "instructions", "model", "runtime", "store", "tools"]>;
|
|
14
|
+
readonly cause: Schema.Literals<readonly ["closed", "conflict", "incompatible", "invalid", "rejected", "unavailable", "storage_pressure", "context_too_large"]>;
|
|
15
|
+
readonly message: Schema.String;
|
|
16
|
+
readonly requestId: Schema.optionalKey<Schema.String>;
|
|
17
|
+
}>;
|
|
18
|
+
/** Canonical serialized Shiitake failure. */
|
|
19
|
+
export type ShiitakeErrorWire = Schema.Schema.Type<typeof ShiitakeErrorWireSchema>;
|
|
20
|
+
/** Sanitized failure from a parsed Shiitake boundary. */
|
|
21
|
+
export declare class ShiitakeError extends Error {
|
|
22
|
+
/** Boundary that rejected the operation. */
|
|
23
|
+
readonly boundary: ShiitakeErrorBoundary;
|
|
24
|
+
/** Request identity recoverable when a send may have reached the owner. */
|
|
25
|
+
readonly requestId?: string | undefined;
|
|
26
|
+
/** Stable runtime tag for typed Shiitake failures. */
|
|
27
|
+
readonly _tag: "ShiitakeError";
|
|
28
|
+
/** Safe category describing why it was rejected. */
|
|
29
|
+
readonly cause: ShiitakeErrorCause;
|
|
30
|
+
/** Original cause retained only for server-side diagnosis. */
|
|
31
|
+
readonly underlying?: unknown;
|
|
32
|
+
/** Construct a sanitized boundary failure. */
|
|
33
|
+
constructor(
|
|
34
|
+
/** Boundary that rejected the operation. */
|
|
35
|
+
boundary: ShiitakeErrorBoundary,
|
|
36
|
+
/** Safe category describing why it was rejected. */
|
|
37
|
+
category: ShiitakeErrorCause,
|
|
38
|
+
/** Human-readable message safe for callers to display. */
|
|
39
|
+
message: string,
|
|
40
|
+
/** Request identity recoverable when a send may have reached the owner. */
|
|
41
|
+
requestId?: string | undefined,
|
|
42
|
+
/**
|
|
43
|
+
* The original thrown value, kept for server-side diagnosis only. It is
|
|
44
|
+
* never serialized: the wire encoder copies named fields only.
|
|
45
|
+
*/
|
|
46
|
+
cause?: unknown);
|
|
47
|
+
}
|
|
48
|
+
/** Sanitize one caught host failure for Shiitake's public wire. */
|
|
49
|
+
export declare function toShiitakeErrorWire(cause: unknown): ShiitakeErrorWire;
|
|
50
|
+
export {};
|