@fungi.computer/bird-dog 0.1.0 → 0.2.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/dist/effect.d.ts +158 -35
- package/dist/effect.js +77 -9
- package/dist/index.d.ts +38 -12
- package/package.json +2 -2
package/dist/effect.d.ts
CHANGED
|
@@ -2,12 +2,20 @@ import type { WatchdogQueuedJob, WatchdogStoredJob } from "@fungi.computer/watch
|
|
|
2
2
|
import * as Effect from "effect/Effect";
|
|
3
3
|
import * as Schema from "effect/Schema";
|
|
4
4
|
import type { BirdDogAgentJobInput, BirdDogAgentJobPayload, BirdDogMail, BirdDogSettlement } from "./index.js";
|
|
5
|
+
/** The maximum UTF-8 size of one mail body. */
|
|
6
|
+
export declare const BIRD_DOG_MAIL_CONTENT_MAX_BYTES: number;
|
|
5
7
|
/** Parser for an ordinary agent Session address. */
|
|
6
8
|
export declare const BirdDogAgentReferenceSchema: Schema.Struct<{
|
|
7
9
|
readonly kind: Schema.Literal<"agent">;
|
|
8
10
|
readonly agentId: Schema.String;
|
|
9
11
|
readonly sessionId: Schema.String;
|
|
10
12
|
}>;
|
|
13
|
+
/** An addressed Agent may create its first Session when accepting this mail. */
|
|
14
|
+
export declare const BirdDogAgentRecipientReferenceSchema: Schema.Struct<{
|
|
15
|
+
readonly kind: Schema.Literal<"agent">;
|
|
16
|
+
readonly agentId: Schema.String;
|
|
17
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
18
|
+
}>;
|
|
11
19
|
/** The most characters a reply's failure diagnostic may carry. */
|
|
12
20
|
export declare const BIRD_DOG_DIAGNOSTIC_MAX_LENGTH = 200;
|
|
13
21
|
/**
|
|
@@ -15,11 +23,33 @@ export declare const BIRD_DOG_DIAGNOSTIC_MAX_LENGTH = 200;
|
|
|
15
23
|
* replying Session's command, its exact Watchdog outcome and, for work that did
|
|
16
24
|
* not complete, the Session's bounded terminal diagnostic.
|
|
17
25
|
*/
|
|
18
|
-
export declare const
|
|
26
|
+
export declare const SettledBirdDogReplySchema: Schema.Struct<{
|
|
19
27
|
readonly commandId: Schema.String;
|
|
20
28
|
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
21
29
|
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
22
30
|
}>;
|
|
31
|
+
/** A terminal delivery failure, correlated by the original mail key only. */
|
|
32
|
+
export declare const BirdDogUndeliverableReasonSchema: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
33
|
+
export declare const UndeliverableBirdDogReplySchema: Schema.Struct<{
|
|
34
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
35
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
36
|
+
}>;
|
|
37
|
+
/** Recipient acceptance, before the command has settled. */
|
|
38
|
+
export declare const AcceptedBirdDogReplySchema: Schema.Struct<{
|
|
39
|
+
readonly outcome: Schema.Literal<"accepted">;
|
|
40
|
+
readonly commandId: Schema.String;
|
|
41
|
+
}>;
|
|
42
|
+
export declare const BirdDogReplySchema: Schema.Union<readonly [Schema.Struct<{
|
|
43
|
+
readonly commandId: Schema.String;
|
|
44
|
+
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
45
|
+
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
46
|
+
}>, Schema.Struct<{
|
|
47
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
48
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
49
|
+
}>, Schema.Struct<{
|
|
50
|
+
readonly outcome: Schema.Literal<"accepted">;
|
|
51
|
+
readonly commandId: Schema.String;
|
|
52
|
+
}>]>;
|
|
23
53
|
/**
|
|
24
54
|
* One secret-safe line of at most `BIRD_DOG_DIAGNOSTIC_MAX_LENGTH` characters
|
|
25
55
|
* from a Session's terminal diagnostic, or nothing when it is blank. Control
|
|
@@ -28,18 +58,54 @@ export declare const BirdDogReplySchema: Schema.Struct<{
|
|
|
28
58
|
* line is cut, so a cut never exposes part of one.
|
|
29
59
|
*/
|
|
30
60
|
export declare function boundedDiagnostic(text: string): string | undefined;
|
|
31
|
-
|
|
32
|
-
|
|
61
|
+
export declare const BirdDogMailSchema: Schema.Union<readonly [Schema.Struct<{
|
|
62
|
+
readonly from: Schema.Struct<{
|
|
63
|
+
readonly kind: Schema.Literal<"agent">;
|
|
64
|
+
readonly agentId: Schema.String;
|
|
65
|
+
readonly sessionId: Schema.String;
|
|
66
|
+
}>;
|
|
67
|
+
/** Settlement or acceptance facts, present only on a reply. */
|
|
68
|
+
readonly reply: Schema.optionalKey<Schema.Union<readonly [Schema.Struct<{
|
|
69
|
+
readonly commandId: Schema.String;
|
|
70
|
+
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
71
|
+
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
72
|
+
}>, Schema.Struct<{
|
|
73
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
74
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
75
|
+
}>, Schema.Struct<{
|
|
76
|
+
readonly outcome: Schema.Literal<"accepted">;
|
|
77
|
+
readonly commandId: Schema.String;
|
|
78
|
+
}>]>>;
|
|
33
79
|
readonly key: Schema.String;
|
|
34
80
|
readonly to: Schema.Struct<{
|
|
35
81
|
readonly kind: Schema.Literal<"agent">;
|
|
36
82
|
readonly agentId: Schema.String;
|
|
37
|
-
readonly sessionId: Schema.String
|
|
83
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
38
84
|
}>;
|
|
39
|
-
readonly
|
|
85
|
+
readonly replyTo: Schema.$Array<Schema.Struct<{
|
|
40
86
|
readonly kind: Schema.Literal<"agent">;
|
|
41
87
|
readonly agentId: Schema.String;
|
|
42
88
|
readonly sessionId: Schema.String;
|
|
89
|
+
}>>;
|
|
90
|
+
readonly content: Schema.String;
|
|
91
|
+
readonly createdAt: Schema.Number;
|
|
92
|
+
readonly meta: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
93
|
+
}>, Schema.Struct<{
|
|
94
|
+
readonly from: Schema.Struct<{
|
|
95
|
+
readonly kind: Schema.Literal<"agent">;
|
|
96
|
+
readonly agentId: Schema.String;
|
|
97
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
98
|
+
}>;
|
|
99
|
+
/** An unstarted recipient can only author an undeliverable reply. */
|
|
100
|
+
readonly reply: Schema.Struct<{
|
|
101
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
102
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
103
|
+
}>;
|
|
104
|
+
readonly key: Schema.String;
|
|
105
|
+
readonly to: Schema.Struct<{
|
|
106
|
+
readonly kind: Schema.Literal<"agent">;
|
|
107
|
+
readonly agentId: Schema.String;
|
|
108
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
43
109
|
}>;
|
|
44
110
|
readonly replyTo: Schema.$Array<Schema.Struct<{
|
|
45
111
|
readonly kind: Schema.Literal<"agent">;
|
|
@@ -48,15 +114,8 @@ export declare const BirdDogMailSchema: Schema.Struct<{
|
|
|
48
114
|
}>>;
|
|
49
115
|
readonly content: Schema.String;
|
|
50
116
|
readonly createdAt: Schema.Number;
|
|
51
|
-
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
52
117
|
readonly meta: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
53
|
-
|
|
54
|
-
readonly reply: Schema.optionalKey<Schema.Struct<{
|
|
55
|
-
readonly commandId: Schema.String;
|
|
56
|
-
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
57
|
-
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
58
|
-
}>>;
|
|
59
|
-
}>;
|
|
118
|
+
}>]>;
|
|
60
119
|
/** Parser for accepted Session work. */
|
|
61
120
|
export declare const BirdDogAgentWorkSchema: Schema.Struct<{
|
|
62
121
|
readonly jobId: Schema.String;
|
|
@@ -72,17 +131,54 @@ export declare const BirdDogAgentJobPayloadSchema: Schema.Struct<{
|
|
|
72
131
|
readonly sessionId: Schema.String;
|
|
73
132
|
readonly commandFactId: Schema.String;
|
|
74
133
|
}>;
|
|
75
|
-
readonly mail: Schema.optional<Schema.Struct<{
|
|
134
|
+
readonly mail: Schema.optional<Schema.Union<readonly [Schema.Struct<{
|
|
135
|
+
readonly from: Schema.Struct<{
|
|
136
|
+
readonly kind: Schema.Literal<"agent">;
|
|
137
|
+
readonly agentId: Schema.String;
|
|
138
|
+
readonly sessionId: Schema.String;
|
|
139
|
+
}>;
|
|
140
|
+
/** Settlement or acceptance facts, present only on a reply. */
|
|
141
|
+
readonly reply: Schema.optionalKey<Schema.Union<readonly [Schema.Struct<{
|
|
142
|
+
readonly commandId: Schema.String;
|
|
143
|
+
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
144
|
+
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
145
|
+
}>, Schema.Struct<{
|
|
146
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
147
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
148
|
+
}>, Schema.Struct<{
|
|
149
|
+
readonly outcome: Schema.Literal<"accepted">;
|
|
150
|
+
readonly commandId: Schema.String;
|
|
151
|
+
}>]>>;
|
|
76
152
|
readonly key: Schema.String;
|
|
77
153
|
readonly to: Schema.Struct<{
|
|
78
154
|
readonly kind: Schema.Literal<"agent">;
|
|
79
155
|
readonly agentId: Schema.String;
|
|
80
|
-
readonly sessionId: Schema.String
|
|
156
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
81
157
|
}>;
|
|
82
|
-
readonly
|
|
158
|
+
readonly replyTo: Schema.$Array<Schema.Struct<{
|
|
83
159
|
readonly kind: Schema.Literal<"agent">;
|
|
84
160
|
readonly agentId: Schema.String;
|
|
85
161
|
readonly sessionId: Schema.String;
|
|
162
|
+
}>>;
|
|
163
|
+
readonly content: Schema.String;
|
|
164
|
+
readonly createdAt: Schema.Number;
|
|
165
|
+
readonly meta: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
166
|
+
}>, Schema.Struct<{
|
|
167
|
+
readonly from: Schema.Struct<{
|
|
168
|
+
readonly kind: Schema.Literal<"agent">;
|
|
169
|
+
readonly agentId: Schema.String;
|
|
170
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
171
|
+
}>;
|
|
172
|
+
/** An unstarted recipient can only author an undeliverable reply. */
|
|
173
|
+
readonly reply: Schema.Struct<{
|
|
174
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
175
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
176
|
+
}>;
|
|
177
|
+
readonly key: Schema.String;
|
|
178
|
+
readonly to: Schema.Struct<{
|
|
179
|
+
readonly kind: Schema.Literal<"agent">;
|
|
180
|
+
readonly agentId: Schema.String;
|
|
181
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
86
182
|
}>;
|
|
87
183
|
readonly replyTo: Schema.$Array<Schema.Struct<{
|
|
88
184
|
readonly kind: Schema.Literal<"agent">;
|
|
@@ -91,15 +187,8 @@ export declare const BirdDogAgentJobPayloadSchema: Schema.Struct<{
|
|
|
91
187
|
}>>;
|
|
92
188
|
readonly content: Schema.String;
|
|
93
189
|
readonly createdAt: Schema.Number;
|
|
94
|
-
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
95
190
|
readonly meta: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
96
|
-
|
|
97
|
-
readonly reply: Schema.optionalKey<Schema.Struct<{
|
|
98
|
-
readonly commandId: Schema.String;
|
|
99
|
-
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
100
|
-
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
101
|
-
}>>;
|
|
102
|
-
}>>;
|
|
191
|
+
}>]>>;
|
|
103
192
|
}>;
|
|
104
193
|
/** Parser for accepted work entering BirdDog's transactional projection. */
|
|
105
194
|
export declare const BirdDogAgentJobInputSchema: Schema.Struct<{
|
|
@@ -111,17 +200,54 @@ export declare const BirdDogAgentJobInputSchema: Schema.Struct<{
|
|
|
111
200
|
readonly maxRecoveries: Schema.Int;
|
|
112
201
|
}>>;
|
|
113
202
|
}>;
|
|
114
|
-
readonly mail: Schema.optional<Schema.Struct<{
|
|
203
|
+
readonly mail: Schema.optional<Schema.Union<readonly [Schema.Struct<{
|
|
204
|
+
readonly from: Schema.Struct<{
|
|
205
|
+
readonly kind: Schema.Literal<"agent">;
|
|
206
|
+
readonly agentId: Schema.String;
|
|
207
|
+
readonly sessionId: Schema.String;
|
|
208
|
+
}>;
|
|
209
|
+
/** Settlement or acceptance facts, present only on a reply. */
|
|
210
|
+
readonly reply: Schema.optionalKey<Schema.Union<readonly [Schema.Struct<{
|
|
211
|
+
readonly commandId: Schema.String;
|
|
212
|
+
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
213
|
+
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
214
|
+
}>, Schema.Struct<{
|
|
215
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
216
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
217
|
+
}>, Schema.Struct<{
|
|
218
|
+
readonly outcome: Schema.Literal<"accepted">;
|
|
219
|
+
readonly commandId: Schema.String;
|
|
220
|
+
}>]>>;
|
|
115
221
|
readonly key: Schema.String;
|
|
116
222
|
readonly to: Schema.Struct<{
|
|
117
223
|
readonly kind: Schema.Literal<"agent">;
|
|
118
224
|
readonly agentId: Schema.String;
|
|
119
|
-
readonly sessionId: Schema.String
|
|
225
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
120
226
|
}>;
|
|
121
|
-
readonly
|
|
227
|
+
readonly replyTo: Schema.$Array<Schema.Struct<{
|
|
122
228
|
readonly kind: Schema.Literal<"agent">;
|
|
123
229
|
readonly agentId: Schema.String;
|
|
124
230
|
readonly sessionId: Schema.String;
|
|
231
|
+
}>>;
|
|
232
|
+
readonly content: Schema.String;
|
|
233
|
+
readonly createdAt: Schema.Number;
|
|
234
|
+
readonly meta: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
235
|
+
}>, Schema.Struct<{
|
|
236
|
+
readonly from: Schema.Struct<{
|
|
237
|
+
readonly kind: Schema.Literal<"agent">;
|
|
238
|
+
readonly agentId: Schema.String;
|
|
239
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
240
|
+
}>;
|
|
241
|
+
/** An unstarted recipient can only author an undeliverable reply. */
|
|
242
|
+
readonly reply: Schema.Struct<{
|
|
243
|
+
readonly outcome: Schema.Literal<"undeliverable">;
|
|
244
|
+
readonly reason: Schema.Literals<readonly ["recipient_offline", "recipient_left"]>;
|
|
245
|
+
}>;
|
|
246
|
+
readonly key: Schema.String;
|
|
247
|
+
readonly to: Schema.Struct<{
|
|
248
|
+
readonly kind: Schema.Literal<"agent">;
|
|
249
|
+
readonly agentId: Schema.String;
|
|
250
|
+
readonly sessionId: Schema.optionalKey<Schema.String>;
|
|
125
251
|
}>;
|
|
126
252
|
readonly replyTo: Schema.$Array<Schema.Struct<{
|
|
127
253
|
readonly kind: Schema.Literal<"agent">;
|
|
@@ -130,15 +256,8 @@ export declare const BirdDogAgentJobInputSchema: Schema.Struct<{
|
|
|
130
256
|
}>>;
|
|
131
257
|
readonly content: Schema.String;
|
|
132
258
|
readonly createdAt: Schema.Number;
|
|
133
|
-
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
134
259
|
readonly meta: Schema.optionalKey<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
135
|
-
|
|
136
|
-
readonly reply: Schema.optionalKey<Schema.Struct<{
|
|
137
|
-
readonly commandId: Schema.String;
|
|
138
|
-
readonly outcome: Schema.Literals<readonly ["completed", "failed", "interrupted", "cancelled", "outcome_unknown"]>;
|
|
139
|
-
readonly diagnostic: Schema.optionalKey<Schema.String>;
|
|
140
|
-
}>>;
|
|
141
|
-
}>>;
|
|
260
|
+
}>]>>;
|
|
142
261
|
}>;
|
|
143
262
|
/** BirdDog could not complete one owned store or transport operation. */
|
|
144
263
|
export declare class BirdDogError extends Error {
|
|
@@ -172,6 +291,8 @@ export type EffectBirdDogOptions = Readonly<{
|
|
|
172
291
|
export type BirdDogEffect = Readonly<{
|
|
173
292
|
/** Queue replies owed by a settled agent job. */
|
|
174
293
|
fanOut: (settlement: BirdDogSettlement) => Effect.Effect<void, BirdDogError>;
|
|
294
|
+
/** Durably queue one authored mail item in this Agent's existing outbox. */
|
|
295
|
+
postMail?: ((mail: BirdDogMail) => Effect.Effect<void, BirdDogError>) | undefined;
|
|
175
296
|
/** Deliver due replies and schedule any required retry wake. */
|
|
176
297
|
drainOutbox: () => Effect.Effect<void, BirdDogError>;
|
|
177
298
|
/** Earliest owed reply delivery, including retries; absent after delivery. */
|
|
@@ -189,6 +310,8 @@ export declare const decodeAgentJob: (job: WatchdogStoredJob) => BirdDogAgentJob
|
|
|
189
310
|
* are presented. A reply never carries the settled work's host metadata.
|
|
190
311
|
*/
|
|
191
312
|
export declare function settlementReplies(settlement: BirdDogSettlement, createdAt: number): readonly BirdDogMail[];
|
|
313
|
+
/** Build the recipient's one stable acceptance notice for one original mail. */
|
|
314
|
+
export declare function acceptedNotice(mail: BirdDogMail, sessionId: string, commandId: string, createdAt: number): BirdDogMail;
|
|
192
315
|
/**
|
|
193
316
|
* Whether this mail room's outbox still owes any reply a delivery attempt.
|
|
194
317
|
* Delivered receipts and exhausted dead letters stay but owe nothing.
|
package/dist/effect.js
CHANGED
|
@@ -2,12 +2,24 @@ import * as Effect from "effect/Effect";
|
|
|
2
2
|
import * as Schema from "effect/Schema";
|
|
3
3
|
import { makePostOutbox, postOutboxPending, } from "@fungi.computer/carrier/post";
|
|
4
4
|
const Identifier = Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(256));
|
|
5
|
+
/** The maximum UTF-8 size of one mail body. */
|
|
6
|
+
export const BIRD_DOG_MAIL_CONTENT_MAX_BYTES = 256 * 1024;
|
|
7
|
+
const MailContent = Schema.String.check(Schema.makeFilter((content) => new TextEncoder().encode(content).byteLength <=
|
|
8
|
+
BIRD_DOG_MAIL_CONTENT_MAX_BYTES, {
|
|
9
|
+
message: `Mail content must be at most ${String(BIRD_DOG_MAIL_CONTENT_MAX_BYTES)} UTF-8 bytes`,
|
|
10
|
+
}));
|
|
5
11
|
/** Parser for an ordinary agent Session address. */
|
|
6
12
|
export const BirdDogAgentReferenceSchema = Schema.Struct({
|
|
7
13
|
kind: Schema.Literal("agent"),
|
|
8
14
|
agentId: Identifier,
|
|
9
15
|
sessionId: Identifier,
|
|
10
16
|
});
|
|
17
|
+
/** An addressed Agent may create its first Session when accepting this mail. */
|
|
18
|
+
export const BirdDogAgentRecipientReferenceSchema = Schema.Struct({
|
|
19
|
+
kind: Schema.Literal("agent"),
|
|
20
|
+
agentId: Identifier,
|
|
21
|
+
sessionId: Schema.optionalKey(Identifier),
|
|
22
|
+
});
|
|
11
23
|
/** The most characters a reply's failure diagnostic may carry. */
|
|
12
24
|
export const BIRD_DOG_DIAGNOSTIC_MAX_LENGTH = 200;
|
|
13
25
|
/**
|
|
@@ -15,7 +27,7 @@ export const BIRD_DOG_DIAGNOSTIC_MAX_LENGTH = 200;
|
|
|
15
27
|
* replying Session's command, its exact Watchdog outcome and, for work that did
|
|
16
28
|
* not complete, the Session's bounded terminal diagnostic.
|
|
17
29
|
*/
|
|
18
|
-
export const
|
|
30
|
+
export const SettledBirdDogReplySchema = Schema.Struct({
|
|
19
31
|
commandId: Identifier,
|
|
20
32
|
outcome: Schema.Literals([
|
|
21
33
|
"completed",
|
|
@@ -26,6 +38,25 @@ export const BirdDogReplySchema = Schema.Struct({
|
|
|
26
38
|
]),
|
|
27
39
|
diagnostic: Schema.optionalKey(Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(BIRD_DOG_DIAGNOSTIC_MAX_LENGTH))),
|
|
28
40
|
});
|
|
41
|
+
/** A terminal delivery failure, correlated by the original mail key only. */
|
|
42
|
+
export const BirdDogUndeliverableReasonSchema = Schema.Literals([
|
|
43
|
+
"recipient_offline",
|
|
44
|
+
"recipient_left",
|
|
45
|
+
]);
|
|
46
|
+
export const UndeliverableBirdDogReplySchema = Schema.Struct({
|
|
47
|
+
outcome: Schema.Literal("undeliverable"),
|
|
48
|
+
reason: BirdDogUndeliverableReasonSchema,
|
|
49
|
+
});
|
|
50
|
+
/** Recipient acceptance, before the command has settled. */
|
|
51
|
+
export const AcceptedBirdDogReplySchema = Schema.Struct({
|
|
52
|
+
outcome: Schema.Literal("accepted"),
|
|
53
|
+
commandId: Identifier,
|
|
54
|
+
});
|
|
55
|
+
export const BirdDogReplySchema = Schema.Union([
|
|
56
|
+
SettledBirdDogReplySchema,
|
|
57
|
+
UndeliverableBirdDogReplySchema,
|
|
58
|
+
AcceptedBirdDogReplySchema,
|
|
59
|
+
]);
|
|
29
60
|
const REDACTED = "[redacted]";
|
|
30
61
|
// An authorization scheme's credential, e.g. `Bearer <token>`.
|
|
31
62
|
const schemeCredential = /\b(bearer|basic)\s+[^\s"',;]+/giu;
|
|
@@ -53,18 +84,29 @@ export function boundedDiagnostic(text) {
|
|
|
53
84
|
return line.length === 0 ? undefined : line;
|
|
54
85
|
}
|
|
55
86
|
/** Parser for addressed agent correspondence. */
|
|
56
|
-
|
|
87
|
+
const BirdDogMailFields = {
|
|
57
88
|
key: Identifier,
|
|
58
|
-
to:
|
|
59
|
-
from: BirdDogAgentReferenceSchema,
|
|
89
|
+
to: BirdDogAgentRecipientReferenceSchema,
|
|
60
90
|
replyTo: Schema.Array(BirdDogAgentReferenceSchema),
|
|
61
|
-
content:
|
|
91
|
+
content: MailContent,
|
|
62
92
|
createdAt: Schema.Number.check(Schema.isGreaterThanOrEqualTo(0)),
|
|
63
93
|
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
64
94
|
meta: Schema.optionalKey(Schema.Json),
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
95
|
+
};
|
|
96
|
+
export const BirdDogMailSchema = Schema.Union([
|
|
97
|
+
Schema.Struct({
|
|
98
|
+
...BirdDogMailFields,
|
|
99
|
+
from: BirdDogAgentReferenceSchema,
|
|
100
|
+
/** Settlement or acceptance facts, present only on a reply. */
|
|
101
|
+
reply: Schema.optionalKey(BirdDogReplySchema),
|
|
102
|
+
}),
|
|
103
|
+
Schema.Struct({
|
|
104
|
+
...BirdDogMailFields,
|
|
105
|
+
from: BirdDogAgentRecipientReferenceSchema,
|
|
106
|
+
/** An unstarted recipient can only author an undeliverable reply. */
|
|
107
|
+
reply: UndeliverableBirdDogReplySchema,
|
|
108
|
+
}),
|
|
109
|
+
]);
|
|
68
110
|
/** Parser for accepted Session work. */
|
|
69
111
|
export const BirdDogAgentWorkSchema = Schema.Struct({
|
|
70
112
|
jobId: Identifier,
|
|
@@ -141,7 +183,7 @@ export function settlementReplies(settlement, createdAt) {
|
|
|
141
183
|
return mail.replyTo.map((destination, index) => ({
|
|
142
184
|
key: `${mail.key}:reply:${String(index)}`,
|
|
143
185
|
to: destination,
|
|
144
|
-
from: mail.to,
|
|
186
|
+
from: { ...mail.to, sessionId: work.sessionId },
|
|
145
187
|
replyTo: [],
|
|
146
188
|
content: settlement.content.length > 0
|
|
147
189
|
? settlement.content
|
|
@@ -150,6 +192,24 @@ export function settlementReplies(settlement, createdAt) {
|
|
|
150
192
|
reply,
|
|
151
193
|
}));
|
|
152
194
|
}
|
|
195
|
+
/** Build the recipient's one stable acceptance notice for one original mail. */
|
|
196
|
+
export function acceptedNotice(mail, sessionId, commandId, createdAt) {
|
|
197
|
+
const recipientSession = Schema.decodeUnknownSync(Identifier)(sessionId);
|
|
198
|
+
const sender = Schema.decodeUnknownSync(BirdDogAgentReferenceSchema)(mail.from);
|
|
199
|
+
const reply = Schema.decodeUnknownSync(AcceptedBirdDogReplySchema)({
|
|
200
|
+
outcome: "accepted",
|
|
201
|
+
commandId,
|
|
202
|
+
});
|
|
203
|
+
return {
|
|
204
|
+
key: `${mail.key}:accepted`,
|
|
205
|
+
to: sender,
|
|
206
|
+
from: { ...mail.to, sessionId: recipientSession },
|
|
207
|
+
replyTo: [],
|
|
208
|
+
content: "Work accepted.",
|
|
209
|
+
createdAt,
|
|
210
|
+
reply,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
153
213
|
/**
|
|
154
214
|
* Whether this mail room's outbox still owes any reply a delivery attempt.
|
|
155
215
|
* Delivered receipts and exhausted dead letters stay but owe nothing.
|
|
@@ -182,8 +242,16 @@ export const make = (options) => {
|
|
|
182
242
|
if (wake !== undefined)
|
|
183
243
|
yield* options.scheduleWake(wake);
|
|
184
244
|
});
|
|
245
|
+
const postMail = (mail) => Effect.gen(function* () {
|
|
246
|
+
const createdAt = options.now();
|
|
247
|
+
const hint = yield* post.enqueue(mail, createdAt);
|
|
248
|
+
if (hint !== undefined)
|
|
249
|
+
yield* options.scheduleWake(hint);
|
|
250
|
+
return;
|
|
251
|
+
});
|
|
185
252
|
return Effect.succeed({
|
|
186
253
|
fanOut,
|
|
254
|
+
postMail,
|
|
187
255
|
drainOutbox: post.drain,
|
|
188
256
|
nextWakeAt: post.nextWakeAt,
|
|
189
257
|
});
|
package/dist/index.d.ts
CHANGED
|
@@ -6,18 +6,11 @@ export type BirdDogAgentReference = Readonly<{
|
|
|
6
6
|
agentId: string;
|
|
7
7
|
sessionId: string;
|
|
8
8
|
}>;
|
|
9
|
-
/**
|
|
10
|
-
export type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
replyTo: readonly BirdDogAgentReference[];
|
|
15
|
-
content: string;
|
|
16
|
-
createdAt: number;
|
|
17
|
-
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
18
|
-
meta?: BirdDogMeta;
|
|
19
|
-
/** Settlement facts, present only on a reply BirdDog built. */
|
|
20
|
-
reply?: BirdDogReply;
|
|
9
|
+
/** An addressed Agent whose first Session may be created on acceptance. */
|
|
10
|
+
export type BirdDogAgentRecipientReference = Readonly<{
|
|
11
|
+
kind: "agent";
|
|
12
|
+
agentId: string;
|
|
13
|
+
sessionId?: string;
|
|
21
14
|
}>;
|
|
22
15
|
/**
|
|
23
16
|
* What a reply reports about the settled work beside its content. The
|
|
@@ -25,12 +18,45 @@ export type BirdDogMail = Readonly<{
|
|
|
25
18
|
* against the mail it sent.
|
|
26
19
|
*/
|
|
27
20
|
export type BirdDogReply = Readonly<{
|
|
21
|
+
/** The recipient accepted the work into the named Session. */
|
|
22
|
+
commandId: string;
|
|
23
|
+
outcome: "accepted";
|
|
24
|
+
}> | Readonly<{
|
|
28
25
|
/** The replying Session's accepted command: the sender's receipt `commandId`. */
|
|
29
26
|
commandId: string;
|
|
30
27
|
/** The exact Watchdog outcome; failures are never collapsed. */
|
|
31
28
|
outcome: "completed" | "failed" | "interrupted" | "cancelled" | "outcome_unknown";
|
|
32
29
|
/** Bounded terminal diagnostic for work that did not complete or cancel. */
|
|
33
30
|
diagnostic?: string;
|
|
31
|
+
}> | Readonly<{
|
|
32
|
+
outcome: "undeliverable";
|
|
33
|
+
reason: "recipient_offline" | "recipient_left";
|
|
34
|
+
}>;
|
|
35
|
+
/** Addressed mail; an unstarted Agent may author only an undeliverable reply. */
|
|
36
|
+
export type BirdDogMail = Readonly<{
|
|
37
|
+
key: string;
|
|
38
|
+
to: BirdDogAgentRecipientReference;
|
|
39
|
+
replyTo: readonly BirdDogAgentReference[];
|
|
40
|
+
content: string;
|
|
41
|
+
createdAt: number;
|
|
42
|
+
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
43
|
+
meta?: BirdDogMeta;
|
|
44
|
+
from: BirdDogAgentReference;
|
|
45
|
+
/** Settlement or acceptance facts, present only on a reply. */
|
|
46
|
+
reply?: BirdDogReply;
|
|
47
|
+
}> | Readonly<{
|
|
48
|
+
key: string;
|
|
49
|
+
to: BirdDogAgentRecipientReference;
|
|
50
|
+
replyTo: readonly BirdDogAgentReference[];
|
|
51
|
+
content: string;
|
|
52
|
+
createdAt: number;
|
|
53
|
+
/** The sender's opaque host metadata; BirdDog never reads it. */
|
|
54
|
+
meta?: BirdDogMeta;
|
|
55
|
+
/** No Session exists when a never-started recipient is undeliverable. */
|
|
56
|
+
from: BirdDogAgentRecipientReference;
|
|
57
|
+
reply: Extract<BirdDogReply, {
|
|
58
|
+
outcome: "undeliverable";
|
|
59
|
+
}>;
|
|
34
60
|
}>;
|
|
35
61
|
/** Opaque JSON a host attached to the work; BirdDog only carries it. */
|
|
36
62
|
export type BirdDogMeta = typeof Schema.Json.Type;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fungi.computer/bird-dog",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"author": "Levi <levi@technomancy.dev>",
|
|
5
5
|
"description": "Durable addressed agent mail over generic Watchdog work",
|
|
6
6
|
"type": "module",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"LICENSE"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@fungi.computer/carrier": "0.
|
|
26
|
+
"@fungi.computer/carrier": "0.2.0",
|
|
27
27
|
"@fungi.computer/watchdog": "0.1.0",
|
|
28
28
|
"effect": "4.0.2"
|
|
29
29
|
},
|