@fungi.computer/mule 0.0.2 → 0.1.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/docs/api/index.md CHANGED
@@ -24,15 +24,16 @@ Pi's model stream function, supplied explicitly by the caller.
24
24
 
25
25
  #### Parameters
26
26
 
27
- | Parameter | Type |
28
- | ---------- | --------------------- |
29
- | `model` | `Model`\<`Api`\> |
30
- | `context` | `TranscriptContext` |
31
- | `options?` | `SimpleStreamOptions` |
27
+ | Parameter | Type |
28
+ | ---------- | ------------------------------------------------------ |
29
+ | `model` | [`Model`](effect.md#model-1)\<[`Api`](effect.md#api)\> |
30
+ | `context` | [`Context`](effect.md#context) |
31
+ | `options?` | [`SimpleStreamOptions`](effect.md#simplestreamoptions) |
32
32
 
33
33
  #### Returns
34
34
 
35
- \| `AssistantMessageEventStream` \| `Promise`\<`AssistantMessageEventStream`\>
35
+ \| [`AssistantMessageEventStream`](effect.md#assistantmessageeventstream) \|
36
+ `Promise`\<[`AssistantMessageEventStream`](effect.md#assistantmessageeventstream)\>
36
37
 
37
38
  ---
38
39
 
@@ -128,15 +129,19 @@ Result produced by a tool before Mule forms Pi's correlated result message.
128
129
  ##### content
129
130
 
130
131
  ```ts
131
- readonly content: (TextContent | ImageContent)[];
132
+ readonly content: (
133
+ | TextContent
134
+ | ImageContent)[];
132
135
  ```
133
136
 
134
- ##### details?
137
+ ##### data?
135
138
 
136
139
  ```ts
137
- readonly optional details?: JsonValue;
140
+ readonly optional data?: JsonValue;
138
141
  ```
139
142
 
143
+ Application payload for listeners, never part of a model message.
144
+
140
145
  ##### usage?
141
146
 
142
147
  ```ts
@@ -276,6 +281,7 @@ type MuleEvent =
276
281
  turn: MuleIdentity;
277
282
  message: MuleIdentity;
278
283
  value: Message;
284
+ data?: JsonValue;
279
285
  }
280
286
  | {
281
287
  type: "tool_execution_start";
@@ -403,9 +409,19 @@ Lifecycle emitted around Pi values. Pi messages and events are not rewritten.
403
409
  turn: MuleIdentity;
404
410
  message: MuleIdentity;
405
411
  value: Message;
412
+ data?: JsonValue;
406
413
  }
407
414
  ```
408
415
 
416
+ | Name | Type | Description |
417
+ | --------- | ---------------------------------- | --------------------------------------------------------------- |
418
+ | `type` | `"message_end"` | - |
419
+ | `run` | [`MuleIdentity`](#muleidentity) | - |
420
+ | `turn` | [`MuleIdentity`](#muleidentity) | - |
421
+ | `message` | [`MuleIdentity`](#muleidentity) | - |
422
+ | `value` | [`Message`](effect.md#message) | - |
423
+ | `data?` | [`JsonValue`](effect.md#jsonvalue) | Application payload independent of the completed model message. |
424
+
409
425
  ---
410
426
 
411
427
  ##### Type Literal
@@ -546,12 +562,12 @@ Durable evidence for a call in an interrupted assistant turn.
546
562
  }
547
563
  ```
548
564
 
549
- | Name | Type | Description |
550
- | ---------- | ----------------------------------- | ------------------------------------------------------ |
551
- | `call` | `ToolCall` | - |
552
- | `state` | `"completed"` | - |
553
- | `result` | [`MuleToolResult`](#muletoolresult) | - |
554
- | `message?` | `ToolResultMessage` | Present when the transcript message was committed too. |
565
+ | Name | Type | Description |
566
+ | ---------- | -------------------------------------------------- | ------------------------------------------------------ |
567
+ | `call` | [`ToolCall`](effect.md#toolcall) | - |
568
+ | `state` | `"completed"` | - |
569
+ | `result` | [`MuleToolResult`](#muletoolresult) | - |
570
+ | `message?` | [`ToolResultMessage`](effect.md#toolresultmessage) | Present when the transcript message was committed too. |
555
571
 
556
572
  ---
557
573
 
@@ -628,10 +644,10 @@ Continue a durable, completed assistant turn before requesting another response.
628
644
  ##### streamOptions?
629
645
 
630
646
  ```ts
631
- readonly optional streamOptions?: Omit<SimpleStreamOptions, "signal">;
647
+ readonly optional streamOptions?: Omit<SimpleStreamOptions, "signal" | "maxRetries">;
632
648
  ```
633
649
 
634
- Pi stream options. Cancellation is the run's interruption, never a signal here.
650
+ Provider-native retries are disabled; the typed host policy owns retry.
635
651
 
636
652
  ##### modelStreamIdleTimeoutMs?
637
653
 
@@ -653,9 +669,30 @@ readonly optional toolExecution?: "parallel" | "sequential";
653
669
  readonly optional retry?: RetryPolicy;
654
670
  ```
655
671
 
656
- Pi's bounded retry policy around each assistant call (`retryAssistantCall`).
672
+ Bounded retry around each assistant call, using Pi's exponential delay.
657
673
  Undefined means no retry, matching pi-ai's own default. Hosts that want Pi
658
- coding-agent's numbers pass `piCodingAgentRetryDefaults`.
674
+ coding-agent's numbers pass `piCodingAgentRetryDefaults`. Enabled policy counts
675
+ and delays must be non-negative safe integers. Each assistant turn captures its
676
+ policy before requesting the model.
677
+
678
+ ##### retryable
679
+
680
+ ```ts
681
+ readonly retryable: (message) => boolean;
682
+ ```
683
+
684
+ Host-owned typed decision for this exact assistant message. Only true permits
685
+ retry; unknown messages return false, never a decision from prose.
686
+
687
+ ###### Parameters
688
+
689
+ | Parameter | Type |
690
+ | --------- | ------------------------------------------------ |
691
+ | `message` | [`AssistantMessage`](effect.md#assistantmessage) |
692
+
693
+ ###### Returns
694
+
695
+ `boolean`
659
696
 
660
697
  ##### retryAfterMs?
661
698
 
@@ -667,9 +704,9 @@ Provider's bounded Retry-After evidence for the last assistant error.
667
704
 
668
705
  ###### Parameters
669
706
 
670
- | Parameter | Type |
671
- | --------- | ------------------ |
672
- | `message` | `AssistantMessage` |
707
+ | Parameter | Type |
708
+ | --------- | ------------------------------------------------ |
709
+ | `message` | [`AssistantMessage`](effect.md#assistantmessage) |
673
710
 
674
711
  ###### Returns
675
712
 
@@ -815,10 +852,10 @@ Decode and authorize one exact Pi tool call before it can execute.
815
852
 
816
853
  ###### Parameters
817
854
 
818
- | Parameter | Type |
819
- | --------- | ------------- |
820
- | `call` | `ToolCall` |
821
- | `signal` | `AbortSignal` |
855
+ | Parameter | Type |
856
+ | --------- | -------------------------------- |
857
+ | `call` | [`ToolCall`](effect.md#toolcall) |
858
+ | `signal` | `AbortSignal` |
822
859
 
823
860
  ###### Returns
824
861
 
@@ -836,13 +873,13 @@ Inputs for one complete Pi model/tool loop through the Promise facade.
836
873
 
837
874
  #### Type Declaration
838
875
 
839
- | Name | Type | Description |
840
- | ------------------------ | -------------------------------------------------------------- | -------------------------------------------------------------------- |
841
- | `tools?` | readonly [`MuleTool`](#muletool)[] | - |
842
- | `resolveApiKey()?` | (`provider`, `signal`) => `Promise`\<`string` \| `undefined`\> | Resolve a fresh provider credential immediately before each Pi call. |
843
- | `getSteeringMessages()?` | (`signal`) => `Promise`\<readonly `Message`[]\> | Pull messages that should steer the active run at Pi's safe point. |
844
- | `getFollowUpMessages()?` | (`signal`) => `Promise`\<readonly `Message`[]\> | Pull messages queued until the run would otherwise finish. |
845
- | `shouldStopAfterTurn()?` | (`turn`, `signal`) => `Promise`\<`boolean`\> | Request a graceful stop after the current Pi turn has fully settled. |
876
+ | Name | Type | Description |
877
+ | ------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
878
+ | `tools?` | readonly [`MuleTool`](#muletool)[] | - |
879
+ | `resolveApiKey()?` | (`provider`, `signal`) => `Promise`\<`string` \| `undefined`\> | Resolve a fresh provider credential immediately before each Pi call. |
880
+ | `getSteeringMessages()?` | (`signal`) => `Promise`\<readonly [`Message`](effect.md#message)[]\> | Pull messages that should steer the active run at Pi's safe point. |
881
+ | `getFollowUpMessages()?` | (`signal`) => `Promise`\<readonly [`Message`](effect.md#message)[]\> | Pull messages queued until the run would otherwise finish. |
882
+ | `shouldStopAfterTurn()?` | (`turn`, `signal`) => `Promise`\<`boolean`\> | Request a graceful stop after the current Pi turn has fully settled. |
846
883
 
847
884
  ---
848
885
 
@@ -878,6 +915,43 @@ the run, or with the abort reason (an `AbortError` when the reason is not an
878
915
 
879
916
  `Promise`\<[`MuleRunOutcome`](#mulerunoutcome)\>
880
917
 
918
+ ---
919
+
920
+ ### ProviderRejection
921
+
922
+ ```ts
923
+ type ProviderRejection =
924
+ | Readonly<{
925
+ code: "usage-limit-reached";
926
+ }>
927
+ | Readonly<{
928
+ code: "provider_unavailable";
929
+ status?: number;
930
+ }>
931
+ | Readonly<{
932
+ code: "provider_rejected";
933
+ status: number;
934
+ }>;
935
+ ```
936
+
937
+ Bounded provider evidence, never response bodies, headers or error prose.
938
+
939
+ ---
940
+
941
+ ### ProviderStatusRecorder
942
+
943
+ ```ts
944
+ type ProviderStatusRecorder = Readonly<{
945
+ fetch: typeof globalThis.fetch;
946
+ onProviderStreamEvent: NonNullable<
947
+ SimpleStreamOptions["onProviderStreamEvent"]
948
+ >;
949
+ rejection: () => ProviderRejection | undefined;
950
+ }>;
951
+ ```
952
+
953
+ One provider call's transport and parsed-event observations.
954
+
881
955
  ## Variables
882
956
 
883
957
  ### mule
@@ -887,3 +961,80 @@ const mule: Mule;
887
961
  ```
888
962
 
889
963
  Default Promise-facing Mule interface.
964
+
965
+ ---
966
+
967
+ ### streamModel
968
+
969
+ ```ts
970
+ const streamModel: MuleStreamFunction;
971
+ ```
972
+
973
+ Pi's maintained stream behind Mule's structural provider port.
974
+
975
+ ## Functions
976
+
977
+ ### decodeProviderData()
978
+
979
+ ```ts
980
+ function decodeProviderData(data): ProviderData;
981
+ ```
982
+
983
+ Decode Pi's parsed request/event data before it enters an owned hook.
984
+
985
+ #### Parameters
986
+
987
+ | Parameter | Type |
988
+ | --------- | --------- |
989
+ | `data` | `unknown` |
990
+
991
+ #### Returns
992
+
993
+ [`ProviderData`](effect.md#providerdata)
994
+
995
+ ---
996
+
997
+ ### normalizeModel()
998
+
999
+ ```ts
1000
+ function normalizeModel<TApi>(model): Model<TApi>;
1001
+ ```
1002
+
1003
+ Validate a catalog model's opaque sampling fields before it enters Mule.
1004
+
1005
+ #### Type Parameters
1006
+
1007
+ | Type Parameter |
1008
+ | --------------------------------------- |
1009
+ | `TApi` _extends_ [`Api`](effect.md#api) |
1010
+
1011
+ #### Parameters
1012
+
1013
+ | Parameter | Type |
1014
+ | --------- | --------------------------------------------------------------------------------------------------------- |
1015
+ | `model` | `Omit`\<[`Model`](effect.md#model-1)\<`TApi`\>, `"samplingParams"` \| `"samplingParamsByThinkingLevel"`\> |
1016
+
1017
+ #### Returns
1018
+
1019
+ [`Model`](effect.md#model-1)\<`TApi`\>
1020
+
1021
+ ---
1022
+
1023
+ ### observeProviderStatus()
1024
+
1025
+ ```ts
1026
+ function observeProviderStatus(options?): ProviderStatusRecorder;
1027
+ ```
1028
+
1029
+ Observe one call's typed HTTP and parsed-event evidence. Pi owns stream
1030
+ decoding; this module retains no provider prose.
1031
+
1032
+ #### Parameters
1033
+
1034
+ | Parameter | Type |
1035
+ | ---------- | -------------------------------------------------------------------------------------------------------- |
1036
+ | `options?` | `Pick`\<[`SimpleStreamOptions`](effect.md#simplestreamoptions), `"onProviderStreamEvent"` \| `"fetch"`\> |
1037
+
1038
+ #### Returns
1039
+
1040
+ [`ProviderStatusRecorder`](#providerstatusrecorder)
@@ -10,14 +10,241 @@
10
10
 
11
11
  ## Type Aliases
12
12
 
13
+ ### FauxModelDefinition
14
+
15
+ ```ts
16
+ type FauxModelDefinition = object;
17
+ ```
18
+
19
+ Credential-free model definition for the scripted provider.
20
+
21
+ #### Properties
22
+
23
+ ##### id
24
+
25
+ ```ts
26
+ id: string;
27
+ ```
28
+
29
+ ##### name?
30
+
31
+ ```ts
32
+ optional name?: string;
33
+ ```
34
+
35
+ ##### reasoning?
36
+
37
+ ```ts
38
+ optional reasoning?: boolean;
39
+ ```
40
+
41
+ ##### input?
42
+
43
+ ```ts
44
+ optional input?: ("text" | "image")[];
45
+ ```
46
+
47
+ ##### inputLimits?
48
+
49
+ ```ts
50
+ optional inputLimits?: Model<Api>["inputLimits"];
51
+ ```
52
+
53
+ ##### cost?
54
+
55
+ ```ts
56
+ optional cost?: object;
57
+ ```
58
+
59
+ ###### input
60
+
61
+ ```ts
62
+ input: number;
63
+ ```
64
+
65
+ ###### output
66
+
67
+ ```ts
68
+ output: number;
69
+ ```
70
+
71
+ ###### cacheRead
72
+
73
+ ```ts
74
+ cacheRead: number;
75
+ ```
76
+
77
+ ###### cacheWrite
78
+
79
+ ```ts
80
+ cacheWrite: number;
81
+ ```
82
+
83
+ ##### contextWindow?
84
+
85
+ ```ts
86
+ optional contextWindow?: number;
87
+ ```
88
+
89
+ ##### maxTokens?
90
+
91
+ ```ts
92
+ optional maxTokens?: number;
93
+ ```
94
+
95
+ ---
96
+
97
+ ### RegisterFauxProviderOptions
98
+
99
+ ```ts
100
+ type RegisterFauxProviderOptions = object;
101
+ ```
102
+
103
+ Scripted provider configuration, independent of provider SDK declarations.
104
+
105
+ #### Properties
106
+
107
+ ##### api?
108
+
109
+ ```ts
110
+ optional api?: string;
111
+ ```
112
+
113
+ ##### provider?
114
+
115
+ ```ts
116
+ optional provider?: string;
117
+ ```
118
+
119
+ ##### models?
120
+
121
+ ```ts
122
+ optional models?: FauxModelDefinition[];
123
+ ```
124
+
125
+ ##### deferred?
126
+
127
+ ```ts
128
+ optional deferred?: object;
129
+ ```
130
+
131
+ ###### pendingFetches?
132
+
133
+ ```ts
134
+ optional pendingFetches?: number;
135
+ ```
136
+
137
+ ###### pollAfterMs?
138
+
139
+ ```ts
140
+ optional pollAfterMs?: number;
141
+ ```
142
+
143
+ ##### tokensPerSecond?
144
+
145
+ ```ts
146
+ optional tokensPerSecond?: number;
147
+ ```
148
+
149
+ ##### tokenSize?
150
+
151
+ ```ts
152
+ optional tokenSize?: object;
153
+ ```
154
+
155
+ ###### min?
156
+
157
+ ```ts
158
+ optional min?: number;
159
+ ```
160
+
161
+ ###### max?
162
+
163
+ ```ts
164
+ optional max?: number;
165
+ ```
166
+
167
+ ---
168
+
169
+ ### FauxProviderState
170
+
171
+ ```ts
172
+ type FauxProviderState = object;
173
+ ```
174
+
175
+ Counters retained by the scripted provider.
176
+
177
+ #### Properties
178
+
179
+ ##### callCount
180
+
181
+ ```ts
182
+ callCount: number;
183
+ ```
184
+
185
+ ##### deferredFetchCount
186
+
187
+ ```ts
188
+ deferredFetchCount: number;
189
+ ```
190
+
191
+ ##### cancelledDeferred
192
+
193
+ ```ts
194
+ cancelledDeferred: NonNullable < AssistantMessage["deferred"] > [];
195
+ ```
196
+
197
+ ---
198
+
199
+ ### FauxResponseFactory
200
+
201
+ ```ts
202
+ type FauxResponseFactory = (
203
+ context,
204
+ options,
205
+ state,
206
+ model,
207
+ ) => AssistantMessage | Promise<AssistantMessage>;
208
+ ```
209
+
210
+ Function that observes a model request and supplies a scripted reply.
211
+
212
+ #### Parameters
213
+
214
+ | Parameter | Type |
215
+ | --------- | -------------------------------------------------------------------------- |
216
+ | `context` | [`Context`](effect.md#context) |
217
+ | `options` | `Parameters`\<[`MuleStreamFunction`](index.md#mulestreamfunction)\>\[`2`\] |
218
+ | `state` | [`FauxProviderState`](#fauxproviderstate) |
219
+ | `model` | [`Model`](effect.md#model-1)\<[`Api`](effect.md#api)\> |
220
+
221
+ #### Returns
222
+
223
+ \| [`AssistantMessage`](effect.md#assistantmessage) \|
224
+ `Promise`\<[`AssistantMessage`](effect.md#assistantmessage)\>
225
+
226
+ ---
227
+
228
+ ### FauxResponseStep
229
+
230
+ ```ts
231
+ type FauxResponseStep = AssistantMessage | FauxResponseFactory;
232
+ ```
233
+
234
+ A scripted reply or a factory that observes the normalized request.
235
+
236
+ ---
237
+
13
238
  ### FauxModel
14
239
 
15
240
  ```ts
16
241
  type FauxModel = Readonly<{
17
242
  model: Model<Api>;
18
- stream: FauxProviderHandle["provider"]["streamSimple"];
243
+ stream: (...args) => AssistantMessageEventStream;
244
+ retryable: (message) => boolean;
19
245
  setResponses: (replies) => void;
20
- state: FauxProviderHandle["state"];
246
+ state: FauxProviderState;
247
+ getPendingResponseCount: () => number;
21
248
  }>;
22
249
  ```
23
250
 
@@ -35,10 +262,10 @@ Create a credential-free model for tests and runnable examples.
35
262
 
36
263
  #### Parameters
37
264
 
38
- | Parameter | Type |
39
- | --------- | ----------------------------- |
40
- | `replies` | readonly `FauxResponseStep`[] |
41
- | `options` | `RegisterFauxProviderOptions` |
265
+ | Parameter | Type |
266
+ | --------- | ------------------------------------------------------------- |
267
+ | `replies` | readonly [`FauxResponseStep`](#fauxresponsestep)[] |
268
+ | `options` | [`RegisterFauxProviderOptions`](#registerfauxprovideroptions) |
42
269
 
43
270
  #### Returns
44
271
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fungi.computer/mule",
3
- "version": "0.0.2",
3
+ "version": "0.1.1",
4
4
  "author": "Levi <levi@technomancy.dev>",
5
5
  "description": "Effect-native Pi model and tool loop",
6
6
  "type": "module",
@@ -28,8 +28,8 @@
28
28
  "THIRD_PARTY_NOTICES"
29
29
  ],
30
30
  "dependencies": {
31
- "@earendil-works/pi-ai": "0.99.2",
32
- "@fungi.computer/cairn": "0.0.1",
31
+ "@earendil-works/pi-ai": "1.3.0",
32
+ "@fungi.computer/cairn": "0.1.0",
33
33
  "effect": "4.0.2",
34
34
  "typebox": "1.3.27"
35
35
  },