@fungi.computer/shiitake 0.7.0 → 0.9.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.
Files changed (41) hide show
  1. package/README.md +28 -0
  2. package/dist/client-wire.js +10 -13
  3. package/dist/client.d.ts +6 -10
  4. package/dist/client.js +1 -0
  5. package/dist/delegation.d.ts +4 -4
  6. package/dist/fleet.d.ts +5 -1
  7. package/dist/fleet.js +5 -1
  8. package/dist/http-routes.d.ts +4 -11
  9. package/dist/http-routes.js +2 -1
  10. package/dist/internal/coordinator.d.ts +2 -1
  11. package/dist/internal/coordinator.js +10 -218
  12. package/dist/internal/observation-kernel.d.ts +21 -0
  13. package/dist/internal/observation-kernel.js +140 -4
  14. package/dist/internal/run-scope.d.ts +1 -0
  15. package/dist/internal/run-scope.js +5 -3
  16. package/dist/internal/runtime-coordinator.js +12 -7
  17. package/dist/internal/runtime-core.js +2 -1
  18. package/dist/internal/runtime-reconciliation.js +5 -2
  19. package/dist/internal/session-observation.d.ts +37 -0
  20. package/dist/internal/session-observation.js +440 -0
  21. package/dist/internal/session-status.d.ts +2 -0
  22. package/dist/internal/session-status.js +17 -1
  23. package/dist/internal/woodstock/client-projection.d.ts +3 -1
  24. package/dist/internal/woodstock/client-projection.js +12 -2
  25. package/dist/internal/woodstock/index.d.ts +7 -1
  26. package/dist/internal/woodstock/index.js +47 -4
  27. package/dist/internal/woodstock/progress.d.ts +2 -0
  28. package/dist/internal/woodstock/progress.js +5 -0
  29. package/dist/internal/woodstock/session-entry.d.ts +2 -2
  30. package/dist/remote-client.js +5 -1
  31. package/dist/server-visitor-stream.js +11 -1
  32. package/dist/session-liveness.d.ts +4 -0
  33. package/dist/session-liveness.js +4 -0
  34. package/dist/testing.d.ts +2 -0
  35. package/dist/testing.js +2 -0
  36. package/docs/api/agent-control.md +2 -2
  37. package/docs/api/client.md +28 -14
  38. package/docs/api/delegation.md +2 -2
  39. package/docs/api/fleet.md +33 -4
  40. package/docs/api/testing.md +11 -0
  41. package/package.json +5 -5
@@ -10,6 +10,7 @@ import * as Schema from "effect/Schema";
10
10
  import * as Scope from "effect/Scope";
11
11
  import * as Sink from "effect/Sink";
12
12
  import * as Stream from "effect/Stream";
13
+ import { sessionSilenceDeadlineMs } from "./session-liveness.js";
13
14
  import { parseAccepted, parseCommandSettlement, parseWithdrawResult, parseCancelResult, parseLatestPendingPrompt, parseForkedSession, parseCreatedSession, parseDeletedSession, parseExtensionOutput, parseExtensionStatus, parseExtensionStatuses, parseSessionFrame, parseSessionSnapshot, parseSessionSummaryPage, parseShiitakeError, } from "./client-wire.js";
14
15
  import { ShiitakeError } from "./errors.js";
15
16
  import { decodeClientReadOptions, decodeClientSessionCreationRequestId, decodeClientPageCursor, decodeClientSessionId, decodeClientSubscribeOptions, } from "./internal/client-boundary.js";
@@ -96,7 +97,10 @@ function remoteEvents(url, clientClosed, sources, eventSource) {
96
97
  return active;
97
98
  },
98
99
  catch: () => unavailable("Session stream could not open"),
99
- }), (active) => closeRemoteSource(active, sources)), { bufferSize: 256, strategy: "dropping" }).pipe(Stream.mapEffect(decodeRemoteEvent), Stream.interruptWhen(clientClosed.await));
100
+ }), (active) => closeRemoteSource(active, sources)), { bufferSize: 256, strategy: "dropping" }).pipe(Stream.mapEffect(decodeRemoteEvent), Stream.timeoutOrElse({
101
+ duration: sessionSilenceDeadlineMs,
102
+ orElse: () => Stream.fail(unavailable("Session feed is connected but silent; the service may be busy")),
103
+ }), Stream.interruptWhen(clientClosed.await));
100
104
  }
101
105
  function sessionUrl(baseUrl, sessionId) {
102
106
  return `${baseUrl}/sessions/${encodeURIComponent(sessionId)}`;
@@ -1,5 +1,6 @@
1
1
  import { SSEStreamingApi } from "hono/streaming";
2
2
  import { visitorSnapshot } from "./client-visitor.js";
3
+ import { encodeSessionFrame } from "./internal/observation-kernel.js";
3
4
  export function visitorStream(options) {
4
5
  const { readable, writable } = new TransformStream();
5
6
  const stream = new SSEStreamingApi(writable, readable);
@@ -43,7 +44,7 @@ export function visitorStream(options) {
43
44
  await close();
44
45
  return;
45
46
  }
46
- await stream.write(": heartbeat\n\n");
47
+ // Keep the visitor authorization/expiry check, not a second liveness clock.
47
48
  if (!ending)
48
49
  heartbeat = setTimeout(() => {
49
50
  void beat().catch((cause) => {
@@ -77,6 +78,15 @@ export function visitorStream(options) {
77
78
  for await (const frame of options.watch.changes) {
78
79
  if (ending)
79
80
  break;
81
+ if (frame.kind === "heartbeat") {
82
+ if (!(await admitted()))
83
+ break;
84
+ await stream.writeSSE({
85
+ event: "frame",
86
+ data: encodeSessionFrame(frame).data,
87
+ });
88
+ continue;
89
+ }
80
90
  if (frame.kind === "tool_output")
81
91
  continue;
82
92
  if (frame.kind === "progress" || frame.kind === "activity") {
@@ -0,0 +1,4 @@
1
+ /** Process-local liveness cadence, not a durable Session fact. */
2
+ export declare const sessionHeartbeatIntervalMs = 15000;
3
+ /** Silence loses observation; only the service owner's lease check proves death. */
4
+ export declare const sessionSilenceDeadlineMs = 45000;
@@ -0,0 +1,4 @@
1
+ /** Process-local liveness cadence, not a durable Session fact. */
2
+ export const sessionHeartbeatIntervalMs = 15_000;
3
+ /** Silence loses observation; only the service owner's lease check proves death. */
4
+ export const sessionSilenceDeadlineMs = 45_000;
package/dist/testing.d.ts CHANGED
@@ -1,6 +1,8 @@
1
1
  import { type FauxResponseStep } from "@fungi.computer/mule/testing";
2
2
  import type { ExtensionRosterV0, Json, RosteredExtensionV0 } from "./extensions.js";
3
3
  import { type ModelSource, type SessionSnapshot, type ShiitakeOwnerAgent, type ShiitakeOptions, type SqliteOwner } from "./index.js";
4
+ /** Product finalizer grace, exposed for tests that wait for durable queue settlement. */
5
+ export { runFinalizerGraceMs } from "./internal/run-scope.js";
4
6
  /** A deterministic model source for trusted tests; no provider account or I/O. */
5
7
  export declare function fauxModelSource(replies: readonly FauxResponseStep[]): ModelSource;
6
8
  /** One scripted model tool call; the scripted sandbox runs exactly this call. */
package/dist/testing.js CHANGED
@@ -7,6 +7,8 @@ import * as z from "zod";
7
7
  import { fauxAssistantMessage, fauxToolCall, } from "@earendil-works/pi-ai/providers/faux";
8
8
  import { GuestThrew } from "@fungi.computer/mycelium";
9
9
  import { Shiitake, } from "./index.js";
10
+ /** Product finalizer grace, exposed for tests that wait for durable queue settlement. */
11
+ export { runFinalizerGraceMs } from "./internal/run-scope.js";
10
12
  const settlementBudgetSchema = z.int().min(1).max(1_000).default(1_000);
11
13
  /** A deterministic model source for trusted tests; no provider account or I/O. */
12
14
  export function fauxModelSource(replies) {
@@ -471,7 +471,7 @@ function waitForAgentSettlement(
471
471
  delegator: string | null;
472
472
  terminal: SessionTerminal;
473
473
  content: string;
474
- usage: readonly Pick<AssistantMessage, "model" | "provider" | "usage">[];
474
+ usage: readonly Pick<AssistantMessage, "model" | "usage" | "provider">[];
475
475
  toolCalls: number;
476
476
  waitingOnYou: readonly Readonly<{
477
477
  itemId: string;
@@ -499,7 +499,7 @@ Await one exact durable terminal without opening a transcript observation.
499
499
  `Promise`\<`Readonly`\<\{ `acceptedSender`: `string` \| `null`; `delegator`:
500
500
  `string` \| `null`; `terminal`: [`SessionTerminal`](client.md#sessionterminal);
501
501
  `content`: `string`; `usage`: readonly `Pick`\<`AssistantMessage`, `"model"` \|
502
- `"provider"` \| `"usage"`\>[]; `toolCalls`: `number`; `waitingOnYou`: readonly
502
+ `"usage"` \| `"provider"`\>[]; `toolCalls`: `number`; `waitingOnYou`: readonly
503
503
  `Readonly`\<\{ `itemId`: `string`; `kind`: `string`; `summary`: `string`;
504
504
  \}\>[]; \}\>\>
505
505
 
@@ -409,22 +409,13 @@ Durable outcome for one accepted work item on the selected Session lineage.
409
409
  ### AgentRunningWork
410
410
 
411
411
  ```ts
412
- type AgentRunningWork =
413
- | Readonly<{
414
- kind: "session";
415
- sessionId: string;
416
- commandId: string;
417
- title: string;
418
- }>
419
- | Readonly<{
420
- kind: "host";
421
- lane: string;
422
- jobId: string;
423
- }>;
412
+ type AgentRunningWork = Readonly<{
413
+ phase:
414
+ "thinking" | "streaming" | "running_tool" | "waiting_on_you" | "cancelling";
415
+ }>;
424
416
  ```
425
417
 
426
- Blocking executor identity and Session display metadata, never messages or
427
- provider data.
418
+ The occupying work's current phase; never its identity or transcript.
428
419
 
429
420
  ---
430
421
 
@@ -687,6 +678,9 @@ Bounded Session baseline at one opaque owner cursor.
687
678
 
688
679
  ```ts
689
680
  type SessionFrame =
681
+ | Readonly<{
682
+ kind: "heartbeat";
683
+ }>
690
684
  | Readonly<{
691
685
  kind: "activity";
692
686
  activity: SessionActivity;
@@ -1058,6 +1052,26 @@ const DelegationReceiptSchema: Schema.Codec<DelegationReceipt>;
1058
1052
 
1059
1053
  A delegated send is accepted by its owner or held in durable mail custody.
1060
1054
 
1055
+ ---
1056
+
1057
+ ### sessionHeartbeatIntervalMs
1058
+
1059
+ ```ts
1060
+ const sessionHeartbeatIntervalMs: 15000 = 15_000;
1061
+ ```
1062
+
1063
+ Process-local liveness cadence, not a durable Session fact.
1064
+
1065
+ ---
1066
+
1067
+ ### sessionSilenceDeadlineMs
1068
+
1069
+ ```ts
1070
+ const sessionSilenceDeadlineMs: 45000 = 45_000;
1071
+ ```
1072
+
1073
+ Silence loses observation; only the service owner's lease check proves death.
1074
+
1061
1075
  ## Functions
1062
1076
 
1063
1077
  ### participantSnapshot()
@@ -68,7 +68,7 @@ settlement(
68
68
  delegator: string | null;
69
69
  terminal: SessionTerminal;
70
70
  content: string;
71
- usage: readonly Pick<AssistantMessage, "model" | "provider" | "usage">[];
71
+ usage: readonly Pick<AssistantMessage, "model" | "usage" | "provider">[];
72
72
  toolCalls: number;
73
73
  waitingOnYou: readonly Readonly<{
74
74
  itemId: string;
@@ -95,7 +95,7 @@ Recipient-local disclosure through the public host, never another Agent's RPC.
95
95
  `Promise`\< \| `Readonly`\<\{ `acceptedSender`: `string` \| `null`; `delegator`:
96
96
  `string` \| `null`; `terminal`: [`SessionTerminal`](client.md#sessionterminal);
97
97
  `content`: `string`; `usage`: readonly `Pick`\<`AssistantMessage`, `"model"` \|
98
- `"provider"` \| `"usage"`\>[]; `toolCalls`: `number`; `waitingOnYou`: readonly
98
+ `"usage"` \| `"provider"`\>[]; `toolCalls`: `number`; `waitingOnYou`: readonly
99
99
  `Readonly`\<\{ `itemId`: `string`; `kind`: `string`; `summary`: `string`;
100
100
  \}\>[]; \}\> \| `undefined`\>
101
101
 
package/docs/api/fleet.md CHANGED
@@ -28,9 +28,9 @@ new AgentGrantError(reason): AgentGrantError;
28
28
 
29
29
  ###### Parameters
30
30
 
31
- | Parameter | Type |
32
- | --------- | ------------------------------------------------------------------------------------- |
33
- | `reason` | `"agent"` \| `"expired"` \| `"action"` \| `"delegation_loop"` \| `"delegation_depth"` |
31
+ | Parameter | Type |
32
+ | --------- | ----------------------------------------------------------------------------------------------------------------- |
33
+ | `reason` | \| `"agent"` \| `"expired"` \| `"action"` \| `"delegation_loop"` \| `"delegation_depth"` \| `"delegator_missing"` |
34
34
 
35
35
  ###### Returns
36
36
 
@@ -47,7 +47,13 @@ Error.constructor;
47
47
  ##### reason
48
48
 
49
49
  ```ts
50
- readonly reason: "agent" | "expired" | "action" | "delegation_loop" | "delegation_depth";
50
+ readonly reason:
51
+ | "agent"
52
+ | "expired"
53
+ | "action"
54
+ | "delegation_loop"
55
+ | "delegation_depth"
56
+ | "delegator_missing";
51
57
  ```
52
58
 
53
59
  ---
@@ -554,6 +560,7 @@ const agentDelegationTaskSchema: ZodLazy<
554
560
  steer: "steer";
555
561
  }>
556
562
  >;
563
+ goal: ZodOptional<ZodUnion<readonly [ZodString, ZodLiteral<false>]>>;
557
564
  text: ZodString;
558
565
  },
559
566
  $strict
@@ -759,6 +766,28 @@ the verified reply retains the failed recipient's identity.
759
766
 
760
767
  ---
761
768
 
769
+ ### isOneWayAncestorNotice()
770
+
771
+ ```ts
772
+ function isOneWayAncestorNotice(mail): boolean;
773
+ ```
774
+
775
+ Shape check for a one-way ancestor notice, not sender provenance. The Local mail
776
+ receiver checks mesh membership before calling it. This addressed mail is still
777
+ work and may steer the parent's running turn when admitted.
778
+
779
+ #### Parameters
780
+
781
+ | Parameter | Type |
782
+ | --------- | ------------- |
783
+ | `mail` | `BirdDogMail` |
784
+
785
+ #### Returns
786
+
787
+ `boolean`
788
+
789
+ ---
790
+
762
791
  ### readOutstandingDelegationSync()
763
792
 
764
793
  ```ts
@@ -91,6 +91,17 @@ type MemoryHost = Readonly<{
91
91
 
92
92
  Explicitly driven in-process host for trusted tests and runnable examples.
93
93
 
94
+ ## Variables
95
+
96
+ ### runFinalizerGraceMs
97
+
98
+ ```ts
99
+ const runFinalizerGraceMs: 1000 = 1_000;
100
+ ```
101
+
102
+ Product finalizer grace, exposed for tests that wait for durable queue
103
+ settlement.
104
+
94
105
  ## Functions
95
106
 
96
107
  ### fauxModelSource()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/shiitake",
3
- "version": "0.7.0",
3
+ "version": "0.9.0",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "description": "Effect-native durable Session acceptance and bounded run orchestration",
6
6
  "type": "module",
@@ -89,16 +89,16 @@
89
89
  "@fungi.computer/bird-dog": "0.3.1",
90
90
  "@fungi.computer/cairn": "0.1.0",
91
91
  "@fungi.computer/carrier": "0.2.0",
92
- "@fungi.computer/knapsack": "0.4.1",
93
- "@fungi.computer/mule": "0.2.1",
94
- "@fungi.computer/mycelium": "0.3.0",
92
+ "@fungi.computer/knapsack": "0.4.3",
93
+ "@fungi.computer/mule": "0.2.2",
94
+ "@fungi.computer/mycelium": "0.3.2",
95
95
  "@fungi.computer/seam": "0.2.0",
96
96
  "@fungi.computer/watchdog": "0.1.0",
97
97
  "effect": "4.0.2",
98
98
  "zod": "4.4.3",
99
99
  "@earendil-works/pi-ai": "1.3.0",
100
100
  "@fungi.computer/gills": "0.2.0",
101
- "@fungi.computer/agar": "0.6.0"
101
+ "@fungi.computer/agar": "0.6.1"
102
102
  },
103
103
  "devDependencies": {
104
104
  "@cloudflare/workers-types": "5.20260828.1",