@fungi.computer/mycelium 0.0.0-stage → 0.0.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/LICENSE +21 -0
- package/README.md +303 -2
- package/THIRD_PARTY_NOTICES +2 -0
- package/dist/access.d.ts +129 -0
- package/dist/access.js +166 -0
- package/dist/capability-source.d.ts +44 -0
- package/dist/capability-source.js +1 -0
- package/dist/compiler.d.ts +28 -0
- package/dist/compiler.js +221 -0
- package/dist/define.d.ts +8 -0
- package/dist/define.js +7 -0
- package/dist/effect.d.ts +89 -0
- package/dist/effect.js +42 -0
- package/dist/errors.d.ts +48 -0
- package/dist/errors.js +62 -0
- package/dist/execute-tool.d.ts +22 -0
- package/dist/execute-tool.js +163 -0
- package/dist/image-collector.d.ts +47 -0
- package/dist/image-collector.js +39 -0
- package/dist/index.d.ts +149 -0
- package/dist/index.js +22 -0
- package/dist/internal/build-identity.d.ts +1 -0
- package/dist/internal/build-identity.js +15 -0
- package/dist/internal/build-identity.node.d.ts +1 -0
- package/dist/internal/build-identity.node.js +42 -0
- package/dist/internal/execution-lifecycle.d.ts +44 -0
- package/dist/internal/execution-lifecycle.js +328 -0
- package/dist/internal/mcp-principal.d.ts +14 -0
- package/dist/internal/mcp-principal.js +17 -0
- package/dist/mcp-catalog.d.ts +23 -0
- package/dist/mcp-catalog.js +110 -0
- package/dist/mcp.d.ts +92 -0
- package/dist/mcp.js +250 -0
- package/dist/operation-schema.d.ts +47 -0
- package/dist/operation-schema.js +50 -0
- package/dist/promise-facade.d.ts +3 -0
- package/dist/promise-facade.js +82 -0
- package/dist/registration.d.ts +74 -0
- package/dist/registration.js +157 -0
- package/dist/remote.d.ts +33 -0
- package/dist/remote.js +126 -0
- package/dist/runtime.d.ts +51 -0
- package/dist/runtime.js +159 -0
- package/dist/sandbox-boundary.d.ts +44 -0
- package/dist/sandbox-boundary.js +325 -0
- package/dist/sandbox-failure-event.d.ts +15 -0
- package/dist/sandbox-failure-event.js +34 -0
- package/dist/sandbox-failure.d.ts +128 -0
- package/dist/sandbox-failure.js +161 -0
- package/dist/sandbox-guest.d.ts +34 -0
- package/dist/sandbox-guest.js +131 -0
- package/dist/sandbox-wire.d.ts +76 -0
- package/dist/sandbox-wire.js +190 -0
- package/dist/sandbox.d.ts +41 -0
- package/dist/sandbox.js +1 -0
- package/dist/semaphore-transition.d.ts +7 -0
- package/dist/semaphore-transition.js +9 -0
- package/dist/source-runtime.d.ts +28 -0
- package/dist/source-runtime.js +162 -0
- package/dist/testing.d.ts +11 -0
- package/dist/testing.js +19 -0
- package/dist/workers/index.d.ts +9 -0
- package/dist/workers/index.js +90 -0
- package/docs/api/README.md +25 -0
- package/docs/api/define.md +20 -0
- package/docs/api/effect.md +245 -0
- package/docs/api/index.md +1081 -0
- package/docs/api/mcp.md +239 -0
- package/docs/api/remote.md +108 -0
- package/docs/api/sandbox-boundary.md +325 -0
- package/docs/api/sandbox-failure.md +1133 -0
- package/docs/api/sandbox-guest.md +191 -0
- package/docs/api/sandbox-wire.md +117 -0
- package/docs/api/sandbox.md +81 -0
- package/docs/api/semaphore-transition.md +40 -0
- package/docs/api/testing.md +72 -0
- package/docs/api/workers.md +55 -0
- package/package.json +132 -3
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Exit from "effect/Exit";
|
|
3
|
+
import * as Scope from "effect/Scope";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { compileSurface, } from "./compiler.js";
|
|
6
|
+
import { MyceliumDefinitionError, MyceliumSourceError, } from "./errors.js";
|
|
7
|
+
import { createExecuteDoor } from "./execute-tool.js";
|
|
8
|
+
function compareCodeUnits(left, right) {
|
|
9
|
+
return left < right ? -1 : left > right ? 1 : 0;
|
|
10
|
+
}
|
|
11
|
+
const maximumCapabilitySources = 128;
|
|
12
|
+
const sourceIdSchema = z.string().min(1).max(160);
|
|
13
|
+
const sourceSnapshotSchema = z.object({
|
|
14
|
+
version: z.string().min(1).max(160),
|
|
15
|
+
modules: z.array(z.unknown()),
|
|
16
|
+
});
|
|
17
|
+
const maximumCandidateModules = 1_000;
|
|
18
|
+
function validateSources(input) {
|
|
19
|
+
if (input.length > maximumCapabilitySources) {
|
|
20
|
+
throw new MyceliumDefinitionError("Capability source count exceeds bound");
|
|
21
|
+
}
|
|
22
|
+
const sources = [...input].sort((left, right) => compareCodeUnits(left.id, right.id));
|
|
23
|
+
const ids = new Set();
|
|
24
|
+
for (const source of sources) {
|
|
25
|
+
if (!sourceIdSchema.safeParse(source.id).success) {
|
|
26
|
+
throw new MyceliumDefinitionError("Capability source id must be non-empty and bounded");
|
|
27
|
+
}
|
|
28
|
+
if (ids.has(source.id)) {
|
|
29
|
+
throw new MyceliumDefinitionError(`Duplicate capability source id: ${source.id}`);
|
|
30
|
+
}
|
|
31
|
+
ids.add(source.id);
|
|
32
|
+
}
|
|
33
|
+
return sources;
|
|
34
|
+
}
|
|
35
|
+
function validateCandidateModuleCount(count) {
|
|
36
|
+
if (count > maximumCandidateModules) {
|
|
37
|
+
throw new MyceliumDefinitionError("Candidate module count exceeds bound");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
function validateSourceSnapshot(snapshot, existingModuleCount) {
|
|
41
|
+
const parsed = sourceSnapshotSchema.safeParse(snapshot);
|
|
42
|
+
if (!parsed.success) {
|
|
43
|
+
throw new MyceliumDefinitionError("Capability source snapshot must have a non-empty bounded version");
|
|
44
|
+
}
|
|
45
|
+
validateCandidateModuleCount(existingModuleCount + parsed.data.modules.length);
|
|
46
|
+
}
|
|
47
|
+
function acquireSourceIntoScope(source, candidateScope, cleanupFailures, invalidate, session) {
|
|
48
|
+
return Effect.uninterruptibleMask((restore) => Effect.gen(function* () {
|
|
49
|
+
const release = (acquired) => Effect.tryPromise({
|
|
50
|
+
try: () => acquired.release(),
|
|
51
|
+
catch: () => new MyceliumSourceError(source.id, "release"),
|
|
52
|
+
}).pipe(Effect.catch((failure) => Effect.sync(() => {
|
|
53
|
+
cleanupFailures.push(failure);
|
|
54
|
+
})));
|
|
55
|
+
const state = yield* Effect.try({
|
|
56
|
+
try: () => {
|
|
57
|
+
const controller = new AbortController();
|
|
58
|
+
return {
|
|
59
|
+
controller,
|
|
60
|
+
outcome: source
|
|
61
|
+
.acquire(session === undefined
|
|
62
|
+
? { signal: controller.signal, invalidate }
|
|
63
|
+
: { signal: controller.signal, invalidate, session })
|
|
64
|
+
.then((acquired) => Exit.succeed(acquired), () => Exit.fail(new MyceliumSourceError(source.id, "acquire"))),
|
|
65
|
+
};
|
|
66
|
+
},
|
|
67
|
+
catch: () => new MyceliumSourceError(source.id, "acquire"),
|
|
68
|
+
});
|
|
69
|
+
yield* Scope.addFinalizer(candidateScope, Effect.promise(() => state.outcome).pipe(Effect.flatMap((outcome) => Exit.isSuccess(outcome) ? release(outcome.value) : Effect.void)));
|
|
70
|
+
const outcome = yield* restore(Effect.promise(() => state.outcome)).pipe(Effect.onInterrupt(() => Effect.sync(() => {
|
|
71
|
+
state.controller.abort();
|
|
72
|
+
})));
|
|
73
|
+
if (Exit.isFailure(outcome)) {
|
|
74
|
+
return yield* Effect.failCause(outcome.cause);
|
|
75
|
+
}
|
|
76
|
+
return outcome.value;
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
/** Acquire one complete candidate attempt without mutating installed state. */
|
|
80
|
+
function acquireCandidateAttempt(options) {
|
|
81
|
+
return Effect.gen(function* () {
|
|
82
|
+
const sources = yield* Effect.try({
|
|
83
|
+
try: () => validateSources(options.sources),
|
|
84
|
+
catch: (cause) => cause instanceof MyceliumDefinitionError
|
|
85
|
+
? cause
|
|
86
|
+
: new MyceliumDefinitionError("Capability sources are invalid"),
|
|
87
|
+
});
|
|
88
|
+
yield* Effect.try({
|
|
89
|
+
try: () => {
|
|
90
|
+
validateCandidateModuleCount(options.modules.length);
|
|
91
|
+
},
|
|
92
|
+
catch: (cause) => cause instanceof MyceliumDefinitionError
|
|
93
|
+
? cause
|
|
94
|
+
: new MyceliumDefinitionError("Static capability modules are invalid"),
|
|
95
|
+
});
|
|
96
|
+
const candidateScope = yield* Scope.make();
|
|
97
|
+
const cleanupFailures = [];
|
|
98
|
+
let stale = false;
|
|
99
|
+
const modules = [...options.modules];
|
|
100
|
+
const sourceFrames = [];
|
|
101
|
+
const acquireAll = Effect.gen(function* () {
|
|
102
|
+
for (const source of sources) {
|
|
103
|
+
const acquired = yield* acquireSourceIntoScope(source, candidateScope, cleanupFailures, () => {
|
|
104
|
+
stale = true;
|
|
105
|
+
}, options.session);
|
|
106
|
+
yield* Effect.try({
|
|
107
|
+
try: () => {
|
|
108
|
+
validateSourceSnapshot(acquired.snapshot, modules.length);
|
|
109
|
+
},
|
|
110
|
+
catch: (cause) => cause instanceof MyceliumDefinitionError
|
|
111
|
+
? cause
|
|
112
|
+
: new MyceliumDefinitionError("Capability source snapshot is invalid"),
|
|
113
|
+
});
|
|
114
|
+
modules.push(...acquired.snapshot.modules);
|
|
115
|
+
sourceFrames.push({
|
|
116
|
+
id: source.id,
|
|
117
|
+
version: acquired.snapshot.version,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
const compiled = options.precompiled ??
|
|
121
|
+
(yield* Effect.try({
|
|
122
|
+
try: () => compileSurface(modules, sourceFrames),
|
|
123
|
+
catch: (cause) => cause instanceof MyceliumDefinitionError
|
|
124
|
+
? cause
|
|
125
|
+
: new MyceliumDefinitionError("Capability compilation failed"),
|
|
126
|
+
}));
|
|
127
|
+
const backingWork = options.backingWork.createGroup();
|
|
128
|
+
const executeDoor = createExecuteDoor(compiled.operations, compiled.catalog, options.sandbox, backingWork, compiled.moduleAliases, compiled.namespacePaths, options.session?.sessionId ?? null, options.access);
|
|
129
|
+
let closed = false;
|
|
130
|
+
const close = () => Effect.gen(function* () {
|
|
131
|
+
if (!closed) {
|
|
132
|
+
closed = true;
|
|
133
|
+
yield* backingWork.awaitIdle;
|
|
134
|
+
yield* Scope.close(candidateScope, Exit.void);
|
|
135
|
+
}
|
|
136
|
+
const cleanupFailure = cleanupFailures[0];
|
|
137
|
+
if (cleanupFailure !== undefined)
|
|
138
|
+
yield* Effect.fail(cleanupFailure);
|
|
139
|
+
});
|
|
140
|
+
return Object.freeze({
|
|
141
|
+
compiled,
|
|
142
|
+
executeDoor,
|
|
143
|
+
isStale: () => stale,
|
|
144
|
+
close,
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
return yield* acquireAll.pipe(Effect.onExit((exit) => Exit.isSuccess(exit) ? Effect.void : Scope.close(candidateScope, exit)));
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
const maximumCandidateAttempts = 2;
|
|
151
|
+
/** Acquire one non-stale candidate or fail after one bounded retry. */
|
|
152
|
+
export function acquireSourceCandidate(options) {
|
|
153
|
+
return Effect.gen(function* () {
|
|
154
|
+
for (let attempt = 0; attempt < maximumCandidateAttempts; attempt += 1) {
|
|
155
|
+
const candidate = yield* acquireCandidateAttempt(options);
|
|
156
|
+
if (!candidate.isStale())
|
|
157
|
+
return candidate;
|
|
158
|
+
yield* candidate.close();
|
|
159
|
+
}
|
|
160
|
+
return yield* Effect.fail(new MyceliumSourceError(undefined, "stale"));
|
|
161
|
+
});
|
|
162
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Sandbox, SandboxRequest, SandboxValue } from "./index.js";
|
|
2
|
+
/** A test callback receives the admitted bindings and cancellation. */
|
|
3
|
+
export type DirectSandboxCallback = (bindings: SandboxRequest["bindings"], signal: AbortSignal) => Promise<SandboxValue>;
|
|
4
|
+
/**
|
|
5
|
+
* Dispatch a known-binding callback directly in this process. NOT isolation:
|
|
6
|
+
* submitted code is ignored, and the callback retains all host privileges.
|
|
7
|
+
* Use only trusted tests and examples, never model-authored code execution.
|
|
8
|
+
*/
|
|
9
|
+
export declare function directSandbox(callback: DirectSandboxCallback): Sandbox;
|
|
10
|
+
/** A test transport that always refuses execution with the supplied message. */
|
|
11
|
+
export declare function rejectingSandbox(message: string): Sandbox;
|
package/dist/testing.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch a known-binding callback directly in this process. NOT isolation:
|
|
3
|
+
* submitted code is ignored, and the callback retains all host privileges.
|
|
4
|
+
* Use only trusted tests and examples, never model-authored code execution.
|
|
5
|
+
*/
|
|
6
|
+
export function directSandbox(callback) {
|
|
7
|
+
return {
|
|
8
|
+
execute: async (request, signal) => {
|
|
9
|
+
signal.throwIfAborted();
|
|
10
|
+
const result = await callback(request.bindings, signal);
|
|
11
|
+
signal.throwIfAborted();
|
|
12
|
+
return result;
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/** A test transport that always refuses execution with the supplied message. */
|
|
17
|
+
export function rejectingSandbox(message) {
|
|
18
|
+
return directSandbox(() => Promise.reject(new Error(message)));
|
|
19
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Sandbox } from "@fungi.computer/mycelium";
|
|
2
|
+
/** The Worker Loader binding Codemode runs guests on. */
|
|
3
|
+
export type CodemodeLoader = WorkerLoader;
|
|
4
|
+
/** Local development facts supplied by the host, never by guest code. */
|
|
5
|
+
export type CodemodeSandboxOptions = Readonly<{
|
|
6
|
+
localDevUnenforcedLimits?: readonly ("cpu" | "memory" | "output" | "cancel")[];
|
|
7
|
+
}>;
|
|
8
|
+
/** Construct a network-isolated Codemode sandbox over a Worker Loader. */
|
|
9
|
+
export declare function createCodemodeSandbox(loader: CodemodeLoader, adapter?: string, options?: CodemodeSandboxOptions): Sandbox;
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A Mycelium sandbox over Cloudflare Codemode: each `execute` call runs the
|
|
3
|
+
* model's program in a fresh Dynamic Worker (Worker Loader) with no network,
|
|
4
|
+
* and the bound operations are its only way out. For Workers hosts.
|
|
5
|
+
*/
|
|
6
|
+
import { DynamicWorkerExecutor, normalizeCode } from "@cloudflare/codemode";
|
|
7
|
+
import { BadResponse, Cancelled, DispatchLost, SourceInvalid, } from "@fungi.computer/mycelium/sandbox-failure";
|
|
8
|
+
import { sandboxBindingNames, sandboxGuestProgram, sandboxGuestResultSchema, sandboxProviderOperationName, submittedSourceLocation, } from "@fungi.computer/mycelium/sandbox-guest";
|
|
9
|
+
import { isSandboxFailure, sandboxBindingBoundary, sandboxExecutorFailure, sandboxGuestFailure, } from "@fungi.computer/mycelium/sandbox-boundary";
|
|
10
|
+
const unenforcedLimitMessages = {
|
|
11
|
+
cpu: "CPU limits are not enforced in local dev",
|
|
12
|
+
memory: "Memory limits are not enforced in local dev",
|
|
13
|
+
output: "Output limits are not enforced in local dev",
|
|
14
|
+
cancel: "Cancellation limits are not enforced in local dev",
|
|
15
|
+
};
|
|
16
|
+
const reportedUnenforcedLimits = new Set();
|
|
17
|
+
/** Construct a network-isolated Codemode sandbox over a Worker Loader. */
|
|
18
|
+
export function createCodemodeSandbox(loader, adapter = "codemode-workerd", options = {}) {
|
|
19
|
+
for (const limit of options.localDevUnenforcedLimits ?? []) {
|
|
20
|
+
const message = unenforcedLimitMessages[limit];
|
|
21
|
+
if (!reportedUnenforcedLimits.has(message)) {
|
|
22
|
+
reportedUnenforcedLimits.add(message);
|
|
23
|
+
console.warn(message);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
adapter,
|
|
28
|
+
async execute(request, signal) {
|
|
29
|
+
const startedAt = Date.now();
|
|
30
|
+
try {
|
|
31
|
+
signal.throwIfAborted();
|
|
32
|
+
const normalized = normalizeCode(request.code);
|
|
33
|
+
const location = submittedSourceLocation(normalized, request.code);
|
|
34
|
+
if (location !== null)
|
|
35
|
+
throw new SourceInvalid(location);
|
|
36
|
+
const boundary = sandboxBindingBoundary(request.bindings);
|
|
37
|
+
const withCpuBudget = (definition) => ({
|
|
38
|
+
...definition,
|
|
39
|
+
limits: {
|
|
40
|
+
...definition.limits,
|
|
41
|
+
cpuMs: Math.min(request.timeoutMs, definition.limits?.cpuMs ?? request.timeoutMs),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const executor = new DynamicWorkerExecutor({
|
|
45
|
+
loader: {
|
|
46
|
+
load: (definition) => loader.load(withCpuBudget(definition)),
|
|
47
|
+
get: (name, getCode) => loader.get(name, async () => withCpuBudget(await getCode())),
|
|
48
|
+
},
|
|
49
|
+
timeout: request.timeoutMs,
|
|
50
|
+
globalOutbound: null,
|
|
51
|
+
});
|
|
52
|
+
// Codemode has no cancellation API; keep its promise until it settles
|
|
53
|
+
// so Mycelium owns the cancellation grace.
|
|
54
|
+
const output = await executor.execute(sandboxGuestProgram(normalized, sandboxBindingNames(boundary.bindings), request.namespacePaths, sandboxProviderOperationName), Object.entries(boundary.bindings).map(([name, operations]) => ({
|
|
55
|
+
name,
|
|
56
|
+
fns: Object.fromEntries(Object.entries(operations).map(([operation, binding]) => [
|
|
57
|
+
sandboxProviderOperationName(operation),
|
|
58
|
+
binding,
|
|
59
|
+
])),
|
|
60
|
+
})));
|
|
61
|
+
signal.throwIfAborted();
|
|
62
|
+
if (output.error !== undefined)
|
|
63
|
+
throw sandboxExecutorFailure(output.error, request.timeoutMs, Date.now() - startedAt);
|
|
64
|
+
const decoded = sandboxGuestResultSchema.safeParse(output.result);
|
|
65
|
+
if (!decoded.success)
|
|
66
|
+
throw new BadResponse({
|
|
67
|
+
reason: "invalid guest envelope",
|
|
68
|
+
rawCause: decoded.error,
|
|
69
|
+
});
|
|
70
|
+
if (!decoded.data.ok)
|
|
71
|
+
throw boundary.recover(sandboxGuestFailure(decoded.data.error, request.bindings));
|
|
72
|
+
const returned = boundary.returnedFailure(decoded.data.value);
|
|
73
|
+
if (returned !== undefined)
|
|
74
|
+
throw returned;
|
|
75
|
+
return decoded.data.value;
|
|
76
|
+
}
|
|
77
|
+
catch (cause) {
|
|
78
|
+
if (signal.aborted)
|
|
79
|
+
throw new Cancelled({ by: "caller" });
|
|
80
|
+
if (isSandboxFailure(cause))
|
|
81
|
+
throw cause;
|
|
82
|
+
throw new DispatchLost({
|
|
83
|
+
elapsedMs: Date.now() - startedAt,
|
|
84
|
+
transport: adapter,
|
|
85
|
+
rawCause: cause,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
**@fungi.computer/mycelium**
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# @fungi.computer/mycelium
|
|
8
|
+
|
|
9
|
+
## Modules
|
|
10
|
+
|
|
11
|
+
| Module | Description |
|
|
12
|
+
| ----------------------------------------------- | ----------- |
|
|
13
|
+
| [define](define.md) | - |
|
|
14
|
+
| [effect](effect.md) | - |
|
|
15
|
+
| [index](index.md) | - |
|
|
16
|
+
| [mcp](mcp.md) | - |
|
|
17
|
+
| [remote](remote.md) | - |
|
|
18
|
+
| [sandbox-boundary](sandbox-boundary.md) | - |
|
|
19
|
+
| [sandbox-failure](sandbox-failure.md) | - |
|
|
20
|
+
| [sandbox-guest](sandbox-guest.md) | - |
|
|
21
|
+
| [sandbox-wire](sandbox-wire.md) | - |
|
|
22
|
+
| [sandbox](sandbox.md) | - |
|
|
23
|
+
| [semaphore-transition](semaphore-transition.md) | - |
|
|
24
|
+
| [testing](testing.md) | - |
|
|
25
|
+
| [workers](workers.md) | - |
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
[**@fungi.computer/mycelium**](README.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[@fungi.computer/mycelium](README.md) / define
|
|
8
|
+
|
|
9
|
+
# define
|
|
10
|
+
|
|
11
|
+
## Variables
|
|
12
|
+
|
|
13
|
+
### Mycelium
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
const Mycelium: Pick<MyceliumApi, "module" | "operation" | "gate">;
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
The authoring half of [MyceliumApi](index.md#myceliumapi); registrations are the
|
|
20
|
+
same handles.
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
[**@fungi.computer/mycelium**](README.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[@fungi.computer/mycelium](README.md) / effect
|
|
8
|
+
|
|
9
|
+
# effect
|
|
10
|
+
|
|
11
|
+
## Type Aliases
|
|
12
|
+
|
|
13
|
+
### Sandbox
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
type Sandbox = Readonly<{
|
|
17
|
+
execute: (request, signal) => Effect.Effect<SandboxValue, SandboxFailure>;
|
|
18
|
+
adapter?: string;
|
|
19
|
+
buildSha?: string;
|
|
20
|
+
}>;
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Effect-native host seam for sandbox execution.
|
|
24
|
+
|
|
25
|
+
Interrupting `execute` must not complete until the backing work has actually
|
|
26
|
+
settled. Mycelium bounds that wait by the acknowledgement grace and reports
|
|
27
|
+
`abort_unacknowledged` when it expires, keeping the work's source revision alive
|
|
28
|
+
until it exits. A host with Promise-shaped work adapts it with
|
|
29
|
+
[fromTypedSandbox](#fromtypedsandbox); `Effect.tryPromise` alone completes
|
|
30
|
+
interruption without awaiting the Promise and so breaks that settlement law.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
### MyceliumOptions
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
type MyceliumOptions = Readonly<{
|
|
38
|
+
modules?: readonly ModuleRegistration[];
|
|
39
|
+
sources?: readonly CapabilitySource[];
|
|
40
|
+
session?: CapabilitySession;
|
|
41
|
+
execution?: ExecutionOptions;
|
|
42
|
+
sandbox: Sandbox;
|
|
43
|
+
onSandboxFailure?: (event) => Effect.Effect<void>;
|
|
44
|
+
tools?: readonly LabelledTool[];
|
|
45
|
+
access?: AccessOptions;
|
|
46
|
+
}>;
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Inputs used to construct the canonical Effect runtime.
|
|
50
|
+
|
|
51
|
+
---
|
|
52
|
+
|
|
53
|
+
### Lease
|
|
54
|
+
|
|
55
|
+
```ts
|
|
56
|
+
type Lease = Readonly<{
|
|
57
|
+
revision: string;
|
|
58
|
+
catalog: ForageCatalog;
|
|
59
|
+
executeTool: MuleTool;
|
|
60
|
+
tools: readonly MuleTool[];
|
|
61
|
+
release: () => Effect.Effect<void, MyceliumError>;
|
|
62
|
+
}>;
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
One immutable Effect-facing capability revision.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### Runtime
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
type Runtime = Readonly<{
|
|
73
|
+
acquire: () => Effect.Effect<Lease, MyceliumError, Scope.Scope>;
|
|
74
|
+
close: () => Effect.Effect<void, MyceliumError>;
|
|
75
|
+
}>;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Warm Effect lifecycle for acquiring scope-owned run leases.
|
|
79
|
+
|
|
80
|
+
## Functions
|
|
81
|
+
|
|
82
|
+
### fromTypedSandbox()
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
function fromTypedSandbox(sandbox): Sandbox;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Adapt a Promise-shaped sandbox to the Effect seam. This is Mycelium's one
|
|
89
|
+
Promise sandbox conversion: interruption waits for the host Promise to settle,
|
|
90
|
+
while cancellation reaches the host through the abort signal.
|
|
91
|
+
|
|
92
|
+
#### Parameters
|
|
93
|
+
|
|
94
|
+
| Parameter | Type |
|
|
95
|
+
| --------- | ------------------------------- |
|
|
96
|
+
| `sandbox` | [`Sandbox`](sandbox.md#sandbox) |
|
|
97
|
+
|
|
98
|
+
#### Returns
|
|
99
|
+
|
|
100
|
+
[`Sandbox`](#sandbox)
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
### make()
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
function make(options): Effect<
|
|
108
|
+
Readonly<{
|
|
109
|
+
acquire: () => Effect<
|
|
110
|
+
Readonly<{
|
|
111
|
+
revision: string;
|
|
112
|
+
catalog: ForageCatalog;
|
|
113
|
+
executeTool: MuleTool;
|
|
114
|
+
tools: readonly MuleTool[];
|
|
115
|
+
release: () => Effect<void, MyceliumError>;
|
|
116
|
+
}>,
|
|
117
|
+
MyceliumError,
|
|
118
|
+
Scope
|
|
119
|
+
>;
|
|
120
|
+
close: () => Effect<void, MyceliumError>;
|
|
121
|
+
}>,
|
|
122
|
+
MyceliumError,
|
|
123
|
+
Scope
|
|
124
|
+
>;
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Construct the canonical scoped Effect runtime.
|
|
128
|
+
|
|
129
|
+
#### Parameters
|
|
130
|
+
|
|
131
|
+
| Parameter | Type |
|
|
132
|
+
| --------- | ------------------------------------- |
|
|
133
|
+
| `options` | [`MyceliumOptions`](#myceliumoptions) |
|
|
134
|
+
|
|
135
|
+
#### Returns
|
|
136
|
+
|
|
137
|
+
`Effect`\<`Readonly`\<\{ `acquire`: () => `Effect`\<`Readonly`\<\{ `revision`:
|
|
138
|
+
`string`; `catalog`: `ForageCatalog`; `executeTool`: `MuleTool`; `tools`:
|
|
139
|
+
readonly `MuleTool`[]; `release`: () => `Effect`\<`void`,
|
|
140
|
+
[`MyceliumError`](index.md#myceliumerror)\>; \}\>,
|
|
141
|
+
[`MyceliumError`](index.md#myceliumerror), `Scope`\>; `close`: () =>
|
|
142
|
+
`Effect`\<`void`, [`MyceliumError`](index.md#myceliumerror)\>; \}\>,
|
|
143
|
+
[`MyceliumError`](index.md#myceliumerror), `Scope`\>
|
|
144
|
+
|
|
145
|
+
## References
|
|
146
|
+
|
|
147
|
+
### CapabilitySession
|
|
148
|
+
|
|
149
|
+
Re-exports [CapabilitySession](index.md#capabilitysession)
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### CapabilitySource
|
|
154
|
+
|
|
155
|
+
Re-exports [CapabilitySource](index.md#capabilitysource)
|
|
156
|
+
|
|
157
|
+
---
|
|
158
|
+
|
|
159
|
+
### ModuleRegistration
|
|
160
|
+
|
|
161
|
+
Re-exports [ModuleRegistration](index.md#moduleregistration)
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
### SandboxBinding
|
|
166
|
+
|
|
167
|
+
Re-exports [SandboxBinding](sandbox.md#sandboxbinding)
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
### SandboxRequest
|
|
172
|
+
|
|
173
|
+
Re-exports [SandboxRequest](sandbox.md#sandboxrequest)
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
### ExecutionOptions
|
|
178
|
+
|
|
179
|
+
Re-exports [ExecutionOptions](index.md#executionoptions)
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
### Access
|
|
184
|
+
|
|
185
|
+
Re-exports [Access](index.md#access)
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
### AccessContext
|
|
190
|
+
|
|
191
|
+
Re-exports [AccessContext](index.md#accesscontext)
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
### AccessLabel
|
|
196
|
+
|
|
197
|
+
Re-exports [AccessLabel](index.md#accesslabel)
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### AccessOptions
|
|
202
|
+
|
|
203
|
+
Re-exports [AccessOptions](index.md#accessoptions)
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
### AccessRefusal
|
|
208
|
+
|
|
209
|
+
Re-exports [AccessRefusal](index.md#accessrefusal)
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
### AccessRefusalReason
|
|
214
|
+
|
|
215
|
+
Re-exports [AccessRefusalReason](index.md#accessrefusalreason)
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
### ConfirmRequest
|
|
220
|
+
|
|
221
|
+
Re-exports [ConfirmRequest](index.md#confirmrequest)
|
|
222
|
+
|
|
223
|
+
---
|
|
224
|
+
|
|
225
|
+
### Grant
|
|
226
|
+
|
|
227
|
+
Re-exports [Grant](index.md#grant)
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
### Grants
|
|
232
|
+
|
|
233
|
+
Re-exports [Grants](index.md#grants)
|
|
234
|
+
|
|
235
|
+
---
|
|
236
|
+
|
|
237
|
+
### LabelledTool
|
|
238
|
+
|
|
239
|
+
Re-exports [LabelledTool](index.md#labelledtool)
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
### ToolPolicy
|
|
244
|
+
|
|
245
|
+
Re-exports [ToolPolicy](index.md#toolpolicy)
|