@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,236 @@
|
|
|
1
|
+
import type { HostMetaOptions } from "./host-meta.js";
|
|
2
|
+
import type { ExtensionRosterV0 } from "../extensions.js";
|
|
3
|
+
import type { Api, AssistantMessage, Model, MuleStreamFunction, RetryPolicy } from "@fungi.computer/mule/effect";
|
|
4
|
+
import type { CapabilitySource, ExecutionOptions, ModuleRegistration } from "@fungi.computer/mycelium";
|
|
5
|
+
import type { GrantsDelivery, GrantsDeliveryResult, ToolAccess } from "./contracts.js";
|
|
6
|
+
import type { Sandbox } from "@fungi.computer/mycelium/effect";
|
|
7
|
+
import * as Effect from "effect/Effect";
|
|
8
|
+
import * as Stream from "effect/Stream";
|
|
9
|
+
import type * as Scope from "effect/Scope";
|
|
10
|
+
import type { WatchdogError } from "@fungi.computer/watchdog";
|
|
11
|
+
import type { WatchdogExecutionDecision, WatchdogRunningJob, ConcurrentWatchdogRuntimeEffect } from "@fungi.computer/watchdog/effect";
|
|
12
|
+
import type { AbortCommand, Accepted, BranchCommand, OperatorCommand, TitleCommand, CancelCommand, CancelResult, ForkCommand, ForkedSession, CompactCommand, PromptCommand, PromptDelivery, ReadOptions, SessionCommand, SessionFrame, SessionSnapshot, SessionSummaryPage, SubscribeOptions, WatchOptions } from "../client.js";
|
|
13
|
+
import type { ShiitakeError } from "../errors.js";
|
|
14
|
+
import type { ExtensionStatusV0, Json } from "../extensions.js";
|
|
15
|
+
import type { InstructionSnapshot, ModelDescription, RuntimePendingWork, SqliteOwner, StorageBudget, CompactionOptions } from "./contracts.js";
|
|
16
|
+
import type { ModelPreference } from "./model-preference.js";
|
|
17
|
+
/** Effect-native acquired Pi model and finalizer. */
|
|
18
|
+
export type ModelAcquisitionEffect = Readonly<{
|
|
19
|
+
/** Exact Pi model selected for this run. */
|
|
20
|
+
model: Model<Api>;
|
|
21
|
+
/** Optional explicit Pi stream function for custom providers and tests. */
|
|
22
|
+
stream?: MuleStreamFunction;
|
|
23
|
+
/** Provider’s bounded Retry-After for a clean HTTP refusal, if reported. */
|
|
24
|
+
retryAfterMs?: (message: AssistantMessage) => number | undefined;
|
|
25
|
+
/** Effect finalizer for acquired model resources. */
|
|
26
|
+
release: Effect.Effect<void, ShiitakeError>;
|
|
27
|
+
}>;
|
|
28
|
+
/** Effect-native model acquisition owner. */
|
|
29
|
+
export type ModelSourceEffect = Readonly<{
|
|
30
|
+
/** Acquire one selection and its request-scoped egress. */
|
|
31
|
+
acquire: (input: Readonly<{
|
|
32
|
+
sessionId: string;
|
|
33
|
+
preference: ModelPreference | null;
|
|
34
|
+
}>) => Effect.Effect<ModelAcquisitionEffect, ShiitakeError>;
|
|
35
|
+
/** Read the would-be selection's context window; absent leaves it unknown. */
|
|
36
|
+
describe?: (input: Readonly<{
|
|
37
|
+
sessionId: string;
|
|
38
|
+
preference: ModelPreference | null;
|
|
39
|
+
}>) => Effect.Effect<ModelDescription, ShiitakeError>;
|
|
40
|
+
}>;
|
|
41
|
+
/** Effect-native instruction snapshot owner. */
|
|
42
|
+
export type InstructionSourceEffect = Readonly<{
|
|
43
|
+
/** Load the session's bounded instruction snapshot. */
|
|
44
|
+
load: (input: Readonly<{
|
|
45
|
+
sessionId: string;
|
|
46
|
+
commandId: string;
|
|
47
|
+
}>) => Effect.Effect<InstructionSnapshot, ShiitakeError, Scope.Scope>;
|
|
48
|
+
}>;
|
|
49
|
+
/** Effect-native Mycelium construction inputs. */
|
|
50
|
+
export type ToolSourceEffect = Readonly<{
|
|
51
|
+
/** Host-owned limit for one scoped tool invocation. */
|
|
52
|
+
execution?: ExecutionOptions;
|
|
53
|
+
/** Mycelium module descriptors visible in the run scope. */
|
|
54
|
+
modules: readonly ModuleRegistration[];
|
|
55
|
+
/** Dynamic host capability projections acquired by Mycelium. */
|
|
56
|
+
sources: readonly CapabilitySource[];
|
|
57
|
+
/**
|
|
58
|
+
* Effect-native sandbox boundary for scoped capabilities. Adapt
|
|
59
|
+
* Promise-shaped work with Mycelium's `fromTypedSandbox`.
|
|
60
|
+
*/
|
|
61
|
+
sandbox: Sandbox;
|
|
62
|
+
/**
|
|
63
|
+
* The Agent-wide access defaults for every tool of the run, as data. A
|
|
64
|
+
* Session's grants the host delivered with the owner's `grants.deliver` override
|
|
65
|
+
* the default key by key. Mycelium reads them at every call; Shiitake never
|
|
66
|
+
* interprets them. Absent is full access.
|
|
67
|
+
*/
|
|
68
|
+
access?: ToolAccess;
|
|
69
|
+
}>;
|
|
70
|
+
/** Effect-native owner for scheduling the opaque durable reconciler. */
|
|
71
|
+
export type RuntimeHostEffect = Readonly<{
|
|
72
|
+
/** Bind the one repeatable zero-input reconciliation program. */
|
|
73
|
+
bind: (input: Readonly<{
|
|
74
|
+
reconcile: Effect.Effect<void, ShiitakeError>;
|
|
75
|
+
pendingWork: Effect.Effect<RuntimePendingWork, ShiitakeError>;
|
|
76
|
+
}>) => Effect.Effect<Readonly<{
|
|
77
|
+
/** Commit owner mutations together with the host wake guarantee. No external I/O. */
|
|
78
|
+
commit: <A>(mutation: Effect.Effect<A, ShiitakeError>) => Effect.Effect<A, ShiitakeError>;
|
|
79
|
+
/** Request one later reconciliation without running it inline. */
|
|
80
|
+
requestWake: Effect.Effect<void, ShiitakeError>;
|
|
81
|
+
/** Stop callbacks and release the bound host registration. */
|
|
82
|
+
close: Effect.Effect<void, ShiitakeError>;
|
|
83
|
+
}>, ShiitakeError>;
|
|
84
|
+
}>;
|
|
85
|
+
/** Validated construction bag for owned Effect composition. */
|
|
86
|
+
export type ShiitakeEffectOptions = Readonly<{
|
|
87
|
+
/**
|
|
88
|
+
* The schema of the opaque metadata this host attaches to prompts and
|
|
89
|
+
* operator lines. Shiitake checks, stores and returns it; it never reads it.
|
|
90
|
+
*/
|
|
91
|
+
meta?: HostMetaOptions;
|
|
92
|
+
/** Native owner storage and synchronous transaction capability. */
|
|
93
|
+
store: SqliteOwner;
|
|
94
|
+
/** Disk budget for `store`; absent never refuses for storage pressure. */
|
|
95
|
+
storageBudget?: StorageBudget;
|
|
96
|
+
/** Compaction budgets; absent uses Pi's defaults for every model. */
|
|
97
|
+
compaction?: CompactionOptions;
|
|
98
|
+
/** One host lane in Shiitake's existing Watchdog, opened before recovery. */
|
|
99
|
+
hostJobs?: Readonly<{
|
|
100
|
+
lane: string;
|
|
101
|
+
/** Open the host executor before persisted work is recovered. */
|
|
102
|
+
open: (runtime: ConcurrentWatchdogRuntimeEffect) => Readonly<{
|
|
103
|
+
/** Execute a job claimed for this host lane. */
|
|
104
|
+
execute: (job: WatchdogRunningJob) => Effect.Effect<WatchdogExecutionDecision, WatchdogError>;
|
|
105
|
+
}>;
|
|
106
|
+
}>;
|
|
107
|
+
/** Effect-native Pi model owner. */
|
|
108
|
+
model: ModelSourceEffect;
|
|
109
|
+
/** Effect-native instruction snapshot owner. */
|
|
110
|
+
instructions: InstructionSourceEffect;
|
|
111
|
+
/** Effect-native scoped capability inputs, omitted when no tools exist. */
|
|
112
|
+
tools?: ToolSourceEffect;
|
|
113
|
+
/** Runtime owner that schedules the opaque durable reconciler. */
|
|
114
|
+
runtime: RuntimeHostEffect;
|
|
115
|
+
/**
|
|
116
|
+
* The host's explicit extension roster and grants. Required: a host with no
|
|
117
|
+
* extensions passes `{ roster: [], grants: [] }`.
|
|
118
|
+
*/
|
|
119
|
+
extensions: ExtensionRosterV0;
|
|
120
|
+
/**
|
|
121
|
+
* Pi's bounded retry policy around each live assistant call. Omitted
|
|
122
|
+
* means `piCodingAgentRetryDefaults` (Pi coding-agent's own numbers).
|
|
123
|
+
*/
|
|
124
|
+
retry?: RetryPolicy;
|
|
125
|
+
/**
|
|
126
|
+
* Maximum silence between live provider stream events, in milliseconds.
|
|
127
|
+
* Omitted means `piHttpIdleTimeoutMs` (Pi coding-agent's own default).
|
|
128
|
+
*/
|
|
129
|
+
modelStreamIdleTimeoutMs?: number;
|
|
130
|
+
}>;
|
|
131
|
+
/** Effect-native race-safe watch result. */
|
|
132
|
+
export type ShiitakeEffectWatch = Readonly<{
|
|
133
|
+
/** Race-safe durable baseline. */
|
|
134
|
+
snapshot: SessionSnapshot;
|
|
135
|
+
/** Live frames after the baseline boundary. */
|
|
136
|
+
changes: Stream.Stream<SessionFrame, ShiitakeError>;
|
|
137
|
+
/** Effect finalizer for the live observation. */
|
|
138
|
+
close: Effect.Effect<void, ShiitakeError>;
|
|
139
|
+
}>;
|
|
140
|
+
/** Effect-native addressable Session handle. */
|
|
141
|
+
export type ShiitakeEffectCommandHandler = {
|
|
142
|
+
/** Accept one durable prompt command. */
|
|
143
|
+
(input: PromptCommand | CompactCommand): Effect.Effect<Accepted, ShiitakeError>;
|
|
144
|
+
/** Cancel one accepted command, or report that it is too late. */
|
|
145
|
+
(input: CancelCommand): Effect.Effect<CancelResult, ShiitakeError>;
|
|
146
|
+
/** Abort the active run, select a lineage leaf, or record an operator line. */
|
|
147
|
+
(input: AbortCommand | BranchCommand | OperatorCommand | TitleCommand): Effect.Effect<undefined, ShiitakeError>;
|
|
148
|
+
/** Fork one complete entry lineage into a new Session. */
|
|
149
|
+
(input: ForkCommand): Effect.Effect<ForkedSession, ShiitakeError>;
|
|
150
|
+
/** Execute an already-decoded command union. */
|
|
151
|
+
(input: SessionCommand): Effect.Effect<Accepted | CancelResult | ForkedSession | undefined, ShiitakeError>;
|
|
152
|
+
};
|
|
153
|
+
/** Delivery intent and an optional private retry key for Effect-native sending. */
|
|
154
|
+
export type ShiitakeEffectSendOptions = Readonly<{
|
|
155
|
+
/** Images retained alongside text in the accepted user message. */
|
|
156
|
+
images?: PromptCommand["images"];
|
|
157
|
+
delivery?: PromptDelivery;
|
|
158
|
+
requestId?: string;
|
|
159
|
+
}>;
|
|
160
|
+
/** Effect-native addressable Session handle. */
|
|
161
|
+
export type ShiitakeEffectSession = Readonly<{
|
|
162
|
+
/** Execute one retained type-discriminated Session command. */
|
|
163
|
+
command: ShiitakeEffectCommandHandler;
|
|
164
|
+
/** Cancel the running turn and all queued prompts, retaining their text. */
|
|
165
|
+
abort: Effect.Effect<void, ShiitakeError>;
|
|
166
|
+
/** Send text with one generated or explicitly supplied request identity. */
|
|
167
|
+
send: (text: string, options?: ShiitakeEffectSendOptions) => Effect.Effect<Accepted, ShiitakeError>;
|
|
168
|
+
/** Cancel exactly the accepted work named by its owner-issued identity. */
|
|
169
|
+
cancel: (input: {
|
|
170
|
+
commandId: string;
|
|
171
|
+
onlyIfPending?: boolean;
|
|
172
|
+
}) => Effect.Effect<CancelResult, ShiitakeError>;
|
|
173
|
+
/** Address one rostered extension's Session-scope commands. */
|
|
174
|
+
extension: (extensionId: string) => ShiitakeEffectSessionExtension;
|
|
175
|
+
/** Lineage-local selection used when the next run acquires its model. */
|
|
176
|
+
modelPreference: Readonly<{
|
|
177
|
+
/** Read the saved override; null selects the Agent default. */
|
|
178
|
+
read: Effect.Effect<ModelPreference | null, ShiitakeError>;
|
|
179
|
+
/** Save an override without starting a provider call. */
|
|
180
|
+
set: (preference: ModelPreference | null) => Effect.Effect<void, ShiitakeError>;
|
|
181
|
+
}>;
|
|
182
|
+
/** Read a bounded durable baseline. */
|
|
183
|
+
read: (input?: ReadOptions) => Effect.Effect<SessionSnapshot, ShiitakeError>;
|
|
184
|
+
/** Subscribe to strict-after replay and live frames. */
|
|
185
|
+
subscribe: (input: SubscribeOptions) => Stream.Stream<SessionFrame, ShiitakeError>;
|
|
186
|
+
/** Open a race-safe baseline plus live changes resource. */
|
|
187
|
+
watch: (input?: WatchOptions) => Effect.Effect<ShiitakeEffectWatch, ShiitakeError>;
|
|
188
|
+
}>;
|
|
189
|
+
/** Effect-native Session-scope extension commands. */
|
|
190
|
+
export type ShiitakeEffectSessionExtension = Readonly<{
|
|
191
|
+
/** Run one command with its encoded input; succeeds with the encoded output. */
|
|
192
|
+
call: (command: string, input: Json) => Effect.Effect<Json, ShiitakeError>;
|
|
193
|
+
}>;
|
|
194
|
+
/** Effect-native Agent-scope extension controls. */
|
|
195
|
+
export type ShiitakeEffectAgentExtensions = Readonly<{
|
|
196
|
+
/** Every rostered extension and whether it is running. */
|
|
197
|
+
list: Effect.Effect<readonly ExtensionStatusV0[], ShiitakeError>;
|
|
198
|
+
/** Resume a stopped extension; it replays its settled backlog once. */
|
|
199
|
+
resume: (extensionId: string) => Effect.Effect<ExtensionStatusV0, ShiitakeError>;
|
|
200
|
+
/** Run one Agent-scope command with its encoded input. */
|
|
201
|
+
call: (extensionId: string, command: string, input: Json) => Effect.Effect<Json, ShiitakeError>;
|
|
202
|
+
}>;
|
|
203
|
+
/** Effect-native durable harness. */
|
|
204
|
+
export type ShiitakeEffectAgent = Readonly<{
|
|
205
|
+
/** Return the Session identity reserved for this request ID. */
|
|
206
|
+
createSession: (requestId: string) => Effect.Effect<string, ShiitakeError>;
|
|
207
|
+
/** Permanently delete one idle Session; false when it does not exist. */
|
|
208
|
+
deleteSession: (sessionId: string) => Effect.Effect<boolean, ShiitakeError>;
|
|
209
|
+
/** Read one bounded page of existing conversations through the store owner. */
|
|
210
|
+
listSessions: (after?: string) => Effect.Effect<SessionSummaryPage, ShiitakeError>;
|
|
211
|
+
/** List, resume and call rostered extensions. */
|
|
212
|
+
extensions: ShiitakeEffectAgentExtensions;
|
|
213
|
+
/** Address a session without performing I/O. */
|
|
214
|
+
session: (sessionId: string) => ShiitakeEffectSession;
|
|
215
|
+
/** Effect finalizer for the owned harness. */
|
|
216
|
+
close: Effect.Effect<void, ShiitakeError>;
|
|
217
|
+
}>;
|
|
218
|
+
/**
|
|
219
|
+
* The in-process owner of a durable harness. Only the host holds it, so only
|
|
220
|
+
* the host can write a Session's grants or attach metadata; no HTTP or
|
|
221
|
+
* remote client can.
|
|
222
|
+
*/
|
|
223
|
+
export type ShiitakeEffectOwner = ShiitakeEffectAgent & Readonly<{
|
|
224
|
+
/** Each Session's delivered tool grants, read at every call. */
|
|
225
|
+
grants: Readonly<{
|
|
226
|
+
/** Store one versioned delivery; versions only move forward. */
|
|
227
|
+
deliver: (sessionId: string, delivery: GrantsDelivery) => Effect.Effect<GrantsDeliveryResult, ShiitakeError>;
|
|
228
|
+
/** One Session's newest delivery; null when the host delivered none. */
|
|
229
|
+
read: (sessionId: string) => Effect.Effect<GrantsDelivery | null, ShiitakeError>;
|
|
230
|
+
}>;
|
|
231
|
+
/**
|
|
232
|
+
* The same Agent whose prompts and operator lines carry `meta`, checked
|
|
233
|
+
* against the host's metadata schema and stored beside each message.
|
|
234
|
+
*/
|
|
235
|
+
withMeta: (meta: Json) => ShiitakeEffectAgent;
|
|
236
|
+
}>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import type { AdmissionError, CommandHandlersV0, CommandsV0, ExtensionCommandError, ExtensionRead, ExtensionStateError, ExtensionTx, Json } from "../extensions.js";
|
|
5
|
+
/** A parsed invocation retains its typed handler until the transaction runs. */
|
|
6
|
+
export type RegisteredExtensionCommandV0 = (frame: Readonly<{
|
|
7
|
+
sessionId: string | null;
|
|
8
|
+
input: Json;
|
|
9
|
+
}>) => Result.Result<() => Effect.Effect<Json, ExtensionCommandError | ExtensionStateError | AdmissionError, ExtensionTx | ExtensionRead>, Schema.SchemaError>;
|
|
10
|
+
/** Capture each declared command's schemas and matching handler at activation. */
|
|
11
|
+
export declare function registerExtensionCommands<C extends CommandsV0>(specs: C, handlers: CommandHandlersV0<C>): ReadonlyMap<string, RegisteredExtensionCommandV0>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Result from "effect/Result";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import { invokeTransactionHook } from "./extension-hook.js";
|
|
5
|
+
import { JsonValueSchema } from "./json-value.js";
|
|
6
|
+
const sessionSchemas = {
|
|
7
|
+
agent: Schema.Null,
|
|
8
|
+
session: Schema.String,
|
|
9
|
+
};
|
|
10
|
+
function bindCommand(spec, handler) {
|
|
11
|
+
const session = sessionSchemas[spec.scope];
|
|
12
|
+
const decodeSession = Schema.decodeUnknownResult(session);
|
|
13
|
+
const decodeInput = Schema.decodeUnknownResult(spec.input, {
|
|
14
|
+
onExcessProperty: "error",
|
|
15
|
+
});
|
|
16
|
+
return (frame) => Result.flatMap(decodeSession(frame.sessionId), (sessionId) => Result.map(decodeInput(frame.input), (input) => () => invokeTransactionHook(() => handler({ sessionId, input })).pipe(Effect.flatMap((output) => Schema.encodeEffect(spec.output)(output).pipe(Effect.flatMap(Schema.decodeUnknownEffect(JsonValueSchema)), Effect.orDie)))));
|
|
17
|
+
}
|
|
18
|
+
/** Capture each declared command's schemas and matching handler at activation. */
|
|
19
|
+
export function registerExtensionCommands(specs, handlers) {
|
|
20
|
+
const registry = new Map();
|
|
21
|
+
for (const name of Object.keys(handlers)) {
|
|
22
|
+
const spec = specs[name];
|
|
23
|
+
const handler = handlers[name];
|
|
24
|
+
if (spec === undefined || handler === undefined)
|
|
25
|
+
continue;
|
|
26
|
+
registry.set(name, bindCommand(spec, handler));
|
|
27
|
+
}
|
|
28
|
+
return registry;
|
|
29
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OperationRegistration } from "@fungi.computer/mycelium";
|
|
2
|
+
import type { CommandsV0, ExtensionContextV0, Json, RunIdentityV0 } from "../extensions.js";
|
|
3
|
+
import type { RegisteredExtensionCommandV0 } from "./extension-command-registry.js";
|
|
4
|
+
/** How one command appears to the model when exposed as a tool. */
|
|
5
|
+
export type CommandToolOptionsV0 = Readonly<{
|
|
6
|
+
/** Discovery text for the model. */
|
|
7
|
+
description: string;
|
|
8
|
+
}>;
|
|
9
|
+
/** Expose declared commands as model tools, bound to the current run's Session. */
|
|
10
|
+
export type CommandToolsV0<C extends CommandsV0> = Readonly<{
|
|
11
|
+
/** The named command as one Mycelium operation running the same handler. */
|
|
12
|
+
tool: (name: keyof C & string, options: CommandToolOptionsV0) => OperationRegistration;
|
|
13
|
+
}>;
|
|
14
|
+
/** Build the model-facing tool for each command, bound to one run. */
|
|
15
|
+
export declare function commandTools<C extends CommandsV0>(specs: C | undefined, registered: () => ReadonlyMap<string, RegisteredExtensionCommandV0>, transact: ExtensionContextV0<Readonly<Record<never, never>>, Json>["transact"], run: RunIdentityV0,
|
|
16
|
+
/** Whether the host granted `commands`; the model door matches the member door. */
|
|
17
|
+
granted: boolean): CommandToolsV0<C>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
// The runtime-free entry keeps extensions bundleable into hosted isolates.
|
|
2
|
+
import { Mycelium } from "@fungi.computer/mycelium/define";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Result from "effect/Result";
|
|
5
|
+
import * as Schema from "effect/Schema";
|
|
6
|
+
import { ShiitakeError } from "../errors.js";
|
|
7
|
+
import { JsonValueSchema } from "./json-value.js";
|
|
8
|
+
const decodeJson = Schema.decodeUnknownEffect(JsonValueSchema);
|
|
9
|
+
/** Build the model-facing tool for each command, bound to one run. */
|
|
10
|
+
export function commandTools(specs, registered, transact, run,
|
|
11
|
+
/** Whether the host granted `commands`; the model door matches the member door. */
|
|
12
|
+
granted) {
|
|
13
|
+
return Object.freeze({
|
|
14
|
+
tool: (name, options) => {
|
|
15
|
+
const spec = specs?.[name];
|
|
16
|
+
if (spec === undefined)
|
|
17
|
+
throw new Error(`Extension declares no command named ${name}`);
|
|
18
|
+
// Mycelium owns the model-facing JSON (the codec's JSON form); the
|
|
19
|
+
// command door owns its wire form. Cross between them through the
|
|
20
|
+
// command's own codecs, then run the same registered handler.
|
|
21
|
+
const encodeInput = Schema.encodeUnknownEffect(spec.input);
|
|
22
|
+
const decodeOutput = Schema.decodeUnknownEffect(spec.output);
|
|
23
|
+
// A command is a write and declares no idempotency, so its tool is
|
|
24
|
+
// never replayed: replay is always "unsafe".
|
|
25
|
+
const commandOperation = Mycelium.operation({
|
|
26
|
+
description: options.description,
|
|
27
|
+
replay: "unsafe",
|
|
28
|
+
input: spec.input,
|
|
29
|
+
output: spec.output,
|
|
30
|
+
execute: (input) => Effect.runPromise(Effect.gen(function* () {
|
|
31
|
+
if (!granted)
|
|
32
|
+
return yield* Effect.fail(new ShiitakeError("extensions", "unavailable", "Extension is unavailable"));
|
|
33
|
+
const command = registered().get(name);
|
|
34
|
+
if (command === undefined)
|
|
35
|
+
return yield* Effect.die(new Error(`Command ${name} has no handler`));
|
|
36
|
+
const wire = yield* encodeInput(input).pipe(Effect.flatMap(decodeJson));
|
|
37
|
+
const invocation = command({
|
|
38
|
+
sessionId: spec.scope === "session" ? run.sessionId : null,
|
|
39
|
+
input: wire,
|
|
40
|
+
});
|
|
41
|
+
if (Result.isFailure(invocation))
|
|
42
|
+
return yield* Effect.fail(invocation.failure);
|
|
43
|
+
const output = yield* transact(invocation.success());
|
|
44
|
+
return yield* decodeOutput(output);
|
|
45
|
+
})),
|
|
46
|
+
});
|
|
47
|
+
return commandOperation;
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { EmptyExtensionFieldsV0, CollectionSpecV0, CollectionsV0, CollectionV0, ExtensionContextV0, Json, StateHandleV0, UpdateCollectionV0 } from "../extensions.js";
|
|
2
|
+
import type { DocumentsV0, DocumentSpecV0, DocumentHandleV0, DocumentHandlesV0 } from "../session-documents.js";
|
|
3
|
+
/** Core retains only these erased results; the author retains each concrete factory. */
|
|
4
|
+
export type CollectionBindingV0 = Readonly<{
|
|
5
|
+
read: Omit<CollectionV0<unknown>, "put"> & Pick<CollectionV0<never>, "put">;
|
|
6
|
+
update: Omit<UpdateCollectionV0<unknown>, "put"> & Pick<UpdateCollectionV0<never>, "put">;
|
|
7
|
+
}>;
|
|
8
|
+
/** State operations capture their typed declaration before entering core. */
|
|
9
|
+
export type ExtensionRuntimePortV0 = Readonly<{
|
|
10
|
+
context: Omit<ExtensionContextV0<EmptyExtensionFieldsV0, Json, EmptyExtensionFieldsV0>, "config" | "state" | "documents">;
|
|
11
|
+
/** Build read/write operations for the declaring collection and schema. */
|
|
12
|
+
collection: <A, I>(name: string, spec: CollectionSpecV0<A, I>) => CollectionV0<A>;
|
|
13
|
+
/** Build synchronous operations guarded by the owner's state transaction. */
|
|
14
|
+
updateCollection: <A, I>(name: string, spec: CollectionSpecV0<A, I>) => UpdateCollectionV0<A>;
|
|
15
|
+
/** Build a Session document handle using its own codec and byte bound. */
|
|
16
|
+
document: <A, I>(name: string, spec: DocumentSpecV0<A, I>) => DocumentHandleV0<A>;
|
|
17
|
+
/** Execute a synchronous mutation in the declaring extension's transaction. */
|
|
18
|
+
update: <A>(body: () => A) => A;
|
|
19
|
+
/** Publish a Session only after its state mutation commits. */
|
|
20
|
+
observeUpdate: (sessionId: string) => void;
|
|
21
|
+
}>;
|
|
22
|
+
/** Each collection factory is new even when two names share the same declaration. */
|
|
23
|
+
export declare function bindExtensionState<S extends CollectionsV0>(collections: S, port: ExtensionRuntimePortV0): StateHandleV0<S>;
|
|
24
|
+
/** Capture the document codec before handing its name to the runtime. */
|
|
25
|
+
export declare function bindExtensionDocuments<D extends DocumentsV0>(documents: D, port: ExtensionRuntimePortV0): DocumentHandlesV0<D>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import * as Struct from "effect/Struct";
|
|
2
|
+
import { invokeSyncHandler } from "./extension-hook.js";
|
|
3
|
+
function invokeNamedFactories(factories) {
|
|
4
|
+
const names = new WeakMap();
|
|
5
|
+
for (const [name, factory] of Object.entries(factories))
|
|
6
|
+
names.set(factory, name);
|
|
7
|
+
return Struct.map(factories, Struct.lambda((factory) => {
|
|
8
|
+
const name = names.get(factory);
|
|
9
|
+
if (name === undefined)
|
|
10
|
+
throw new Error("Extension handle factory is not registered");
|
|
11
|
+
return factory(name);
|
|
12
|
+
}));
|
|
13
|
+
}
|
|
14
|
+
/** Each collection factory is new even when two names share the same declaration. */
|
|
15
|
+
export function bindExtensionState(collections, port) {
|
|
16
|
+
const factories = Struct.map(collections, Struct.lambda((spec) => (name) => spec.bind(port, name)));
|
|
17
|
+
const bindings = invokeNamedFactories(factories);
|
|
18
|
+
const state = Struct.map(bindings, Struct.lambda((binding) => binding.read));
|
|
19
|
+
const updateState = Object.freeze({
|
|
20
|
+
...Struct.map(bindings, Struct.lambda((binding) => binding.update)),
|
|
21
|
+
observe: port.observeUpdate,
|
|
22
|
+
});
|
|
23
|
+
// A separate frozen view: `read` must not be able to write.
|
|
24
|
+
const readState = Object.freeze(Struct.map(bindings, Struct.lambda((binding) => Object.freeze({ get: binding.update.get, page: binding.update.page }))));
|
|
25
|
+
return Object.freeze({
|
|
26
|
+
...state,
|
|
27
|
+
/** Execute a synchronous mutation in the declaring extension's transaction. */
|
|
28
|
+
update: (handler) => port.update(() => invokeSyncHandler(handler, updateState)),
|
|
29
|
+
read: (handler) => port.update(() => invokeSyncHandler(handler, readState)),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
/** Capture the document codec before handing its name to the runtime. */
|
|
33
|
+
export function bindExtensionDocuments(documents, port) {
|
|
34
|
+
return Object.freeze(invokeNamedFactories(Struct.map(documents, Struct.lambda((spec) => (name) => port.document(name, spec)))));
|
|
35
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AnyExtensionDefinitionV0, RosteredExtensionV0 } from "../extensions.js";
|
|
2
|
+
/** The typed reader remains usable across two loaded copies of Shiitake. */
|
|
3
|
+
export declare const definitionReader: unique symbol;
|
|
4
|
+
/** Read the definition captured when the author registered this roster entry. */
|
|
5
|
+
export declare function readDefinition(rostered: RosteredExtensionV0): AnyExtensionDefinitionV0 | undefined;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The typed reader remains usable across two loaded copies of Shiitake. */
|
|
2
|
+
export const definitionReader = Symbol.for("@fungi.computer/shiitake/extension-definition-reader");
|
|
3
|
+
/** Read the definition captured when the author registered this roster entry. */
|
|
4
|
+
export function readDefinition(rostered) {
|
|
5
|
+
return rostered[definitionReader]?.();
|
|
6
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Option from "effect/Option";
|
|
3
|
+
declare const ExtensionHookError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & {
|
|
4
|
+
readonly _tag: "ExtensionHookError";
|
|
5
|
+
} & Readonly<A>;
|
|
6
|
+
/** An outside handler rejected or threw before Shiitake could use its result. */
|
|
7
|
+
export declare class ExtensionHookError extends ExtensionHookError_base<{
|
|
8
|
+
cause: unknown;
|
|
9
|
+
}> {
|
|
10
|
+
}
|
|
11
|
+
/** Lift an outside handler once, outside any synchronous write transaction. */
|
|
12
|
+
export declare function invokeExtensionHook<A, E = never, R = never>(handler: () => A | Promise<A> | Effect.Effect<A, E, R>): Effect.Effect<A, E | ExtensionHookError, R>;
|
|
13
|
+
/** A write callback must resolve before the owner commits its SQLite transaction. */
|
|
14
|
+
export type SyncResult<A> = A extends Option.Option<unknown> ? A : A extends Promise<unknown> | Effect.Effect<unknown, unknown, unknown> ? never : A;
|
|
15
|
+
/** Public state-update shape: infer the return *before* rejecting async results. */
|
|
16
|
+
export type StateUpdate<Tx> = <A>(handler: (tx: Tx) => SyncResult<A>) => A;
|
|
17
|
+
/** Raised before SQLite commits when an untyped handler returns async work. */
|
|
18
|
+
export declare class AsyncExtensionTransactionError extends Error {
|
|
19
|
+
constructor();
|
|
20
|
+
}
|
|
21
|
+
/** Reject a runtime-invalid handler before the surrounding transaction commits. */
|
|
22
|
+
export declare function invokeSyncHandler<Tx, A>(handler: (tx: Tx) => A, tx: Tx): A;
|
|
23
|
+
/** Adapt a synchronous callback or a synchronously executed Effect to the owner transaction. */
|
|
24
|
+
export declare function invokeTransactionHook<A, E, R>(handler: () => A | Effect.Effect<A, E, R>): Effect.Effect<A, E, R>;
|
|
25
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import * as Data from "effect/Data";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import * as Option from "effect/Option";
|
|
4
|
+
/** An outside handler rejected or threw before Shiitake could use its result. */
|
|
5
|
+
export class ExtensionHookError extends Data.TaggedError("ExtensionHookError") {
|
|
6
|
+
}
|
|
7
|
+
/** Lift an outside handler once, outside any synchronous write transaction. */
|
|
8
|
+
export function invokeExtensionHook(handler) {
|
|
9
|
+
return Effect.suspend(() => {
|
|
10
|
+
const result = handler();
|
|
11
|
+
if (Effect.isEffect(result))
|
|
12
|
+
return result;
|
|
13
|
+
return Effect.tryPromise({
|
|
14
|
+
try: () => Promise.resolve(result),
|
|
15
|
+
catch: (cause) => new ExtensionHookError({ cause }),
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
/** Raised before SQLite commits when an untyped handler returns async work. */
|
|
20
|
+
export class AsyncExtensionTransactionError extends Error {
|
|
21
|
+
constructor() {
|
|
22
|
+
super("Extension transaction handler must return synchronously");
|
|
23
|
+
this.name = "AsyncExtensionTransactionError";
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Reject a runtime-invalid handler before the surrounding transaction commits. */
|
|
27
|
+
export function invokeSyncHandler(handler, tx) {
|
|
28
|
+
const value = handler(tx);
|
|
29
|
+
if (value instanceof Promise ||
|
|
30
|
+
(Effect.isEffect(value) && !Option.isOption(value)))
|
|
31
|
+
throw new AsyncExtensionTransactionError();
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
/** Adapt a synchronous callback or a synchronously executed Effect to the owner transaction. */
|
|
35
|
+
export function invokeTransactionHook(handler) {
|
|
36
|
+
return Effect.suspend(() => {
|
|
37
|
+
const result = handler();
|
|
38
|
+
if (result instanceof Promise)
|
|
39
|
+
throw new AsyncExtensionTransactionError();
|
|
40
|
+
if (Option.isOption(result))
|
|
41
|
+
return Effect.succeed(result);
|
|
42
|
+
if (Effect.isEffect(result))
|
|
43
|
+
return result;
|
|
44
|
+
return Effect.succeed(result);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DocumentsV0 } from "../session-documents.js";
|
|
2
|
+
import * as Effect from "effect/Effect";
|
|
3
|
+
import { ShiitakeError } from "../errors.js";
|
|
4
|
+
import type { AnyExtensionDefinitionV0, ExtensionCapabilityV0, ExtensionFingerprint, ExtensionId, ExtensionManifestV0, ExtensionRosterV0, ExtensionRevision } from "../extensions.js";
|
|
5
|
+
/** One validated roster member with its core-derived identity. */
|
|
6
|
+
export type AdmittedExtensionV0 = Readonly<{
|
|
7
|
+
id: ExtensionId;
|
|
8
|
+
manifest: ExtensionManifestV0;
|
|
9
|
+
definition: AnyExtensionDefinitionV0;
|
|
10
|
+
documents: DocumentsV0;
|
|
11
|
+
grants: ReadonlySet<ExtensionCapabilityV0>;
|
|
12
|
+
revision: ExtensionRevision;
|
|
13
|
+
fingerprint: ExtensionFingerprint;
|
|
14
|
+
}>;
|
|
15
|
+
/** Validate a host roster and grants, then derive each revision and fingerprint. */
|
|
16
|
+
export declare function admitExtensionRosterV0(input: ExtensionRosterV0 | undefined): Effect.Effect<readonly AdmittedExtensionV0[], ShiitakeError>;
|
|
17
|
+
/**
|
|
18
|
+
* Hex digest of the core run protocol a run is admitted under, plus the
|
|
19
|
+
* captured Files direct-tool names. It changes when core's
|
|
20
|
+
* run-contract semantics change or the Files tool set changes, never with a
|
|
21
|
+
* roster: the branded Files names are captured separately from fingerprints.
|
|
22
|
+
*/
|
|
23
|
+
export declare function coreProtocolDigest(fileToolNames: readonly string[]): Effect.Effect<string, ShiitakeError>;
|