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