@reactive-agents/interaction 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 +46 -0
- package/dist/index.d.ts +423 -0
- package/dist/index.js +782 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,782 @@
|
|
|
1
|
+
// src/types/mode.ts
|
|
2
|
+
import { Schema } from "effect";
|
|
3
|
+
var InteractionModeType = Schema.Literal(
|
|
4
|
+
"autonomous",
|
|
5
|
+
// Fire-and-forget: agent runs independently
|
|
6
|
+
"supervised",
|
|
7
|
+
// Checkpoints: agent pauses at milestones for approval
|
|
8
|
+
"collaborative",
|
|
9
|
+
// Real-time: agent and user work together
|
|
10
|
+
"consultative",
|
|
11
|
+
// Advisory: agent observes and suggests
|
|
12
|
+
"interrogative"
|
|
13
|
+
// Drill-down: user explores agent state/reasoning
|
|
14
|
+
);
|
|
15
|
+
var SessionId = Schema.String.pipe(Schema.brand("SessionId"));
|
|
16
|
+
var InteractionModeSchema = Schema.Struct({
|
|
17
|
+
mode: InteractionModeType,
|
|
18
|
+
agentId: Schema.String,
|
|
19
|
+
sessionId: SessionId,
|
|
20
|
+
startedAt: Schema.DateFromSelf,
|
|
21
|
+
metadata: Schema.optional(
|
|
22
|
+
Schema.Record({ key: Schema.String, value: Schema.Unknown })
|
|
23
|
+
)
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// src/types/checkpoint.ts
|
|
27
|
+
import { Schema as Schema2 } from "effect";
|
|
28
|
+
var CheckpointStatus = Schema2.Literal(
|
|
29
|
+
"pending",
|
|
30
|
+
"approved",
|
|
31
|
+
"rejected",
|
|
32
|
+
"auto-approved",
|
|
33
|
+
"expired"
|
|
34
|
+
);
|
|
35
|
+
var CheckpointSchema = Schema2.Struct({
|
|
36
|
+
id: Schema2.String,
|
|
37
|
+
agentId: Schema2.String,
|
|
38
|
+
taskId: Schema2.String,
|
|
39
|
+
milestoneName: Schema2.String,
|
|
40
|
+
description: Schema2.String,
|
|
41
|
+
status: CheckpointStatus,
|
|
42
|
+
createdAt: Schema2.DateFromSelf,
|
|
43
|
+
resolvedAt: Schema2.optional(Schema2.DateFromSelf),
|
|
44
|
+
userComment: Schema2.optional(Schema2.String)
|
|
45
|
+
});
|
|
46
|
+
var CheckpointFrequency = Schema2.Literal("milestone", "time-based");
|
|
47
|
+
var AutoApproveAction = Schema2.Literal("approve", "reject", "pause");
|
|
48
|
+
var CheckpointConfigSchema = Schema2.Struct({
|
|
49
|
+
frequency: CheckpointFrequency,
|
|
50
|
+
intervalMs: Schema2.optional(Schema2.Number),
|
|
51
|
+
milestones: Schema2.optional(Schema2.Array(Schema2.String)),
|
|
52
|
+
autoApprove: Schema2.Struct({
|
|
53
|
+
enabled: Schema2.Boolean,
|
|
54
|
+
timeoutMs: Schema2.Number,
|
|
55
|
+
defaultAction: AutoApproveAction
|
|
56
|
+
})
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// src/types/notification.ts
|
|
60
|
+
import { Schema as Schema3 } from "effect";
|
|
61
|
+
var NotificationChannel = Schema3.Literal(
|
|
62
|
+
"in-app",
|
|
63
|
+
// Dashboard notification
|
|
64
|
+
"callback",
|
|
65
|
+
// Programmatic callback
|
|
66
|
+
"event-bus"
|
|
67
|
+
// EventBus from Layer 1
|
|
68
|
+
);
|
|
69
|
+
var NotificationPriority = Schema3.Literal(
|
|
70
|
+
"low",
|
|
71
|
+
"normal",
|
|
72
|
+
"high",
|
|
73
|
+
"urgent"
|
|
74
|
+
);
|
|
75
|
+
var NotificationSchema = Schema3.Struct({
|
|
76
|
+
id: Schema3.String,
|
|
77
|
+
agentId: Schema3.String,
|
|
78
|
+
channel: NotificationChannel,
|
|
79
|
+
priority: NotificationPriority,
|
|
80
|
+
title: Schema3.String,
|
|
81
|
+
body: Schema3.String,
|
|
82
|
+
data: Schema3.optional(Schema3.Unknown),
|
|
83
|
+
createdAt: Schema3.DateFromSelf,
|
|
84
|
+
readAt: Schema3.optional(Schema3.DateFromSelf)
|
|
85
|
+
});
|
|
86
|
+
var ReportingFrequency = Schema3.Literal(
|
|
87
|
+
"realtime",
|
|
88
|
+
"milestone",
|
|
89
|
+
"hourly",
|
|
90
|
+
"daily"
|
|
91
|
+
);
|
|
92
|
+
var ReportingDetailLevel = Schema3.Literal(
|
|
93
|
+
"minimal",
|
|
94
|
+
"summary",
|
|
95
|
+
"detailed"
|
|
96
|
+
);
|
|
97
|
+
var ReportingConfigSchema = Schema3.Struct({
|
|
98
|
+
frequency: ReportingFrequency,
|
|
99
|
+
channel: NotificationChannel,
|
|
100
|
+
detail: ReportingDetailLevel,
|
|
101
|
+
streaming: Schema3.Boolean
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// src/types/interrupt.ts
|
|
105
|
+
import { Schema as Schema4 } from "effect";
|
|
106
|
+
var InterruptTrigger = Schema4.Literal(
|
|
107
|
+
"error",
|
|
108
|
+
"uncertainty",
|
|
109
|
+
"high-cost",
|
|
110
|
+
"critical-decision",
|
|
111
|
+
"user-requested",
|
|
112
|
+
"custom"
|
|
113
|
+
);
|
|
114
|
+
var InterruptSeverity = Schema4.Literal("low", "medium", "high", "critical");
|
|
115
|
+
var InterruptRuleSchema = Schema4.Struct({
|
|
116
|
+
trigger: InterruptTrigger,
|
|
117
|
+
severity: InterruptSeverity,
|
|
118
|
+
threshold: Schema4.optional(Schema4.Number),
|
|
119
|
+
enabled: Schema4.Boolean
|
|
120
|
+
});
|
|
121
|
+
var InterruptEventSchema = Schema4.Struct({
|
|
122
|
+
id: Schema4.String,
|
|
123
|
+
trigger: InterruptTrigger,
|
|
124
|
+
severity: InterruptSeverity,
|
|
125
|
+
agentId: Schema4.String,
|
|
126
|
+
taskId: Schema4.String,
|
|
127
|
+
message: Schema4.String,
|
|
128
|
+
context: Schema4.optional(Schema4.Unknown),
|
|
129
|
+
timestamp: Schema4.DateFromSelf,
|
|
130
|
+
acknowledged: Schema4.Boolean
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
// src/types/collaboration.ts
|
|
134
|
+
import { Schema as Schema5 } from "effect";
|
|
135
|
+
var CollaborationStatus = Schema5.Literal("active", "paused", "ended");
|
|
136
|
+
var QuestionStyle = Schema5.Literal("inline", "batch", "separate");
|
|
137
|
+
var CollaborationSessionSchema = Schema5.Struct({
|
|
138
|
+
id: SessionId,
|
|
139
|
+
agentId: Schema5.String,
|
|
140
|
+
taskId: Schema5.String,
|
|
141
|
+
status: CollaborationStatus,
|
|
142
|
+
thinkingVisible: Schema5.Boolean,
|
|
143
|
+
streamingEnabled: Schema5.Boolean,
|
|
144
|
+
questionStyle: QuestionStyle,
|
|
145
|
+
rollbackEnabled: Schema5.Boolean,
|
|
146
|
+
startedAt: Schema5.DateFromSelf,
|
|
147
|
+
endedAt: Schema5.optional(Schema5.DateFromSelf)
|
|
148
|
+
});
|
|
149
|
+
var CollaborationMessageType = Schema5.Literal(
|
|
150
|
+
"thought",
|
|
151
|
+
"question",
|
|
152
|
+
"answer",
|
|
153
|
+
"suggestion",
|
|
154
|
+
"update",
|
|
155
|
+
"action"
|
|
156
|
+
);
|
|
157
|
+
var CollaborationMessageSchema = Schema5.Struct({
|
|
158
|
+
id: Schema5.String,
|
|
159
|
+
sessionId: SessionId,
|
|
160
|
+
type: CollaborationMessageType,
|
|
161
|
+
sender: Schema5.Literal("agent", "user"),
|
|
162
|
+
content: Schema5.String,
|
|
163
|
+
timestamp: Schema5.DateFromSelf
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
// src/types/preference.ts
|
|
167
|
+
import { Schema as Schema6 } from "effect";
|
|
168
|
+
var ApprovalAction = Schema6.Literal("auto-approve", "auto-reject", "ask");
|
|
169
|
+
var ApprovalPatternSchema = Schema6.Struct({
|
|
170
|
+
id: Schema6.String,
|
|
171
|
+
taskType: Schema6.String,
|
|
172
|
+
costThreshold: Schema6.optional(Schema6.Number),
|
|
173
|
+
action: ApprovalAction,
|
|
174
|
+
confidence: Schema6.Number,
|
|
175
|
+
occurrences: Schema6.Number,
|
|
176
|
+
lastSeen: Schema6.DateFromSelf
|
|
177
|
+
});
|
|
178
|
+
var InterruptionTolerance = Schema6.Literal("low", "medium", "high");
|
|
179
|
+
var UserPreferenceSchema = Schema6.Struct({
|
|
180
|
+
userId: Schema6.String,
|
|
181
|
+
learningEnabled: Schema6.Boolean,
|
|
182
|
+
interruptionTolerance: InterruptionTolerance,
|
|
183
|
+
preferredMode: Schema6.optional(Schema6.String),
|
|
184
|
+
approvalPatterns: Schema6.Array(ApprovalPatternSchema),
|
|
185
|
+
lastUpdated: Schema6.DateFromSelf
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
// src/types/config.ts
|
|
189
|
+
import { Schema as Schema7 } from "effect";
|
|
190
|
+
var EscalationConditionType = Schema7.Literal(
|
|
191
|
+
"uncertainty",
|
|
192
|
+
"cost",
|
|
193
|
+
"duration",
|
|
194
|
+
"user-active",
|
|
195
|
+
"confidence",
|
|
196
|
+
"consecutive-approvals"
|
|
197
|
+
);
|
|
198
|
+
var EscalationConditionSchema = Schema7.Struct({
|
|
199
|
+
type: EscalationConditionType,
|
|
200
|
+
threshold: Schema7.Number
|
|
201
|
+
});
|
|
202
|
+
var ModeTransitionRuleSchema = Schema7.Struct({
|
|
203
|
+
from: InteractionModeType,
|
|
204
|
+
to: InteractionModeType,
|
|
205
|
+
conditions: Schema7.Array(EscalationConditionSchema)
|
|
206
|
+
});
|
|
207
|
+
var InteractionConfigSchema = Schema7.Struct({
|
|
208
|
+
defaultMode: InteractionModeType,
|
|
209
|
+
interruptRules: Schema7.Array(InterruptRuleSchema),
|
|
210
|
+
reporting: ReportingConfigSchema,
|
|
211
|
+
checkpoints: Schema7.optional(CheckpointConfigSchema),
|
|
212
|
+
escalationRules: Schema7.Array(ModeTransitionRuleSchema),
|
|
213
|
+
deescalationRules: Schema7.Array(ModeTransitionRuleSchema),
|
|
214
|
+
learningEnabled: Schema7.Boolean
|
|
215
|
+
});
|
|
216
|
+
var defaultInteractionConfig = {
|
|
217
|
+
defaultMode: "autonomous",
|
|
218
|
+
interruptRules: [
|
|
219
|
+
{ trigger: "error", severity: "high", enabled: true },
|
|
220
|
+
{ trigger: "uncertainty", severity: "medium", threshold: 0.3, enabled: true },
|
|
221
|
+
{ trigger: "high-cost", severity: "medium", threshold: 10, enabled: true },
|
|
222
|
+
{ trigger: "critical-decision", severity: "critical", enabled: true }
|
|
223
|
+
],
|
|
224
|
+
reporting: {
|
|
225
|
+
frequency: "milestone",
|
|
226
|
+
channel: "event-bus",
|
|
227
|
+
detail: "summary",
|
|
228
|
+
streaming: false
|
|
229
|
+
},
|
|
230
|
+
escalationRules: [
|
|
231
|
+
{
|
|
232
|
+
from: "autonomous",
|
|
233
|
+
to: "supervised",
|
|
234
|
+
conditions: [{ type: "uncertainty", threshold: 0.3 }]
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
from: "supervised",
|
|
238
|
+
to: "collaborative",
|
|
239
|
+
conditions: [
|
|
240
|
+
{ type: "uncertainty", threshold: 0.5 },
|
|
241
|
+
{ type: "user-active", threshold: 1 }
|
|
242
|
+
]
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
deescalationRules: [
|
|
246
|
+
{
|
|
247
|
+
from: "collaborative",
|
|
248
|
+
to: "autonomous",
|
|
249
|
+
conditions: [
|
|
250
|
+
{ type: "confidence", threshold: 0.9 },
|
|
251
|
+
{ type: "consecutive-approvals", threshold: 3 }
|
|
252
|
+
]
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
learningEnabled: true
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// src/errors/errors.ts
|
|
259
|
+
import { Data } from "effect";
|
|
260
|
+
var InteractionError = class extends Data.TaggedError("InteractionError") {
|
|
261
|
+
};
|
|
262
|
+
var ModeError = class extends Data.TaggedError("ModeError") {
|
|
263
|
+
};
|
|
264
|
+
var CheckpointError = class extends Data.TaggedError("CheckpointError") {
|
|
265
|
+
};
|
|
266
|
+
var SessionNotFoundError = class extends Data.TaggedError("SessionNotFoundError") {
|
|
267
|
+
};
|
|
268
|
+
var NotificationError = class extends Data.TaggedError("NotificationError") {
|
|
269
|
+
};
|
|
270
|
+
var InputTimeoutError = class extends Data.TaggedError("InputTimeoutError") {
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// src/services/interaction-manager.ts
|
|
274
|
+
import { Context as Context6, Effect as Effect6, Layer as Layer6 } from "effect";
|
|
275
|
+
|
|
276
|
+
// src/services/mode-switcher.ts
|
|
277
|
+
import { Context, Effect, Layer, Ref } from "effect";
|
|
278
|
+
import { EventBus } from "@reactive-agents/core";
|
|
279
|
+
var ModeSwitcher = class extends Context.Tag("ModeSwitcher")() {
|
|
280
|
+
};
|
|
281
|
+
var ModeSwitcherLive = (config = defaultInteractionConfig) => Layer.effect(
|
|
282
|
+
ModeSwitcher,
|
|
283
|
+
Effect.gen(function* () {
|
|
284
|
+
const eventBus = yield* EventBus;
|
|
285
|
+
const modesRef = yield* Ref.make(/* @__PURE__ */ new Map());
|
|
286
|
+
const checkConditions = (rule, context) => {
|
|
287
|
+
return rule.conditions.every((condition) => {
|
|
288
|
+
switch (condition.type) {
|
|
289
|
+
case "uncertainty":
|
|
290
|
+
return context.confidence !== void 0 && context.confidence < condition.threshold;
|
|
291
|
+
case "cost":
|
|
292
|
+
return context.cost !== void 0 && context.cost > condition.threshold;
|
|
293
|
+
case "duration":
|
|
294
|
+
return context.durationMs !== void 0 && context.durationMs > condition.threshold;
|
|
295
|
+
case "user-active":
|
|
296
|
+
return context.userActive === true;
|
|
297
|
+
case "confidence":
|
|
298
|
+
return context.confidence !== void 0 && context.confidence >= condition.threshold;
|
|
299
|
+
case "consecutive-approvals":
|
|
300
|
+
return context.consecutiveApprovals !== void 0 && context.consecutiveApprovals >= condition.threshold;
|
|
301
|
+
default:
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
};
|
|
306
|
+
return {
|
|
307
|
+
getMode: (agentId) => Ref.get(modesRef).pipe(
|
|
308
|
+
Effect.map((m) => m.get(agentId) ?? config.defaultMode)
|
|
309
|
+
),
|
|
310
|
+
setMode: (agentId, targetMode) => Effect.gen(function* () {
|
|
311
|
+
const currentMode = yield* Ref.get(modesRef).pipe(
|
|
312
|
+
Effect.map((m) => m.get(agentId) ?? config.defaultMode)
|
|
313
|
+
);
|
|
314
|
+
if (currentMode === targetMode) return;
|
|
315
|
+
yield* Ref.update(modesRef, (m) => {
|
|
316
|
+
const next = new Map(m);
|
|
317
|
+
next.set(agentId, targetMode);
|
|
318
|
+
return next;
|
|
319
|
+
});
|
|
320
|
+
yield* eventBus.publish({
|
|
321
|
+
_tag: "Custom",
|
|
322
|
+
type: "interaction.mode-changed",
|
|
323
|
+
payload: { agentId, from: currentMode, to: targetMode }
|
|
324
|
+
});
|
|
325
|
+
}),
|
|
326
|
+
evaluateTransition: (agentId, context) => Effect.gen(function* () {
|
|
327
|
+
const currentMode = yield* Ref.get(modesRef).pipe(
|
|
328
|
+
Effect.map((m) => m.get(agentId) ?? config.defaultMode)
|
|
329
|
+
);
|
|
330
|
+
for (const rule of config.escalationRules) {
|
|
331
|
+
if (rule.from === currentMode && checkConditions(rule, context)) {
|
|
332
|
+
return rule.to;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
for (const rule of config.deescalationRules) {
|
|
336
|
+
if (rule.from === currentMode && checkConditions(rule, context)) {
|
|
337
|
+
return rule.to;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
341
|
+
})
|
|
342
|
+
};
|
|
343
|
+
})
|
|
344
|
+
);
|
|
345
|
+
|
|
346
|
+
// src/services/notification-service.ts
|
|
347
|
+
import { Context as Context2, Effect as Effect2, Layer as Layer2, Ref as Ref2 } from "effect";
|
|
348
|
+
import { ulid } from "ulid";
|
|
349
|
+
import { EventBus as EventBus2 } from "@reactive-agents/core";
|
|
350
|
+
var NotificationService = class extends Context2.Tag("NotificationService")() {
|
|
351
|
+
};
|
|
352
|
+
var NotificationServiceLive = Layer2.effect(
|
|
353
|
+
NotificationService,
|
|
354
|
+
Effect2.gen(function* () {
|
|
355
|
+
const eventBus = yield* EventBus2;
|
|
356
|
+
const notificationsRef = yield* Ref2.make(
|
|
357
|
+
/* @__PURE__ */ new Map()
|
|
358
|
+
);
|
|
359
|
+
return {
|
|
360
|
+
send: (params) => Effect2.gen(function* () {
|
|
361
|
+
const notification = {
|
|
362
|
+
id: ulid(),
|
|
363
|
+
agentId: params.agentId,
|
|
364
|
+
channel: params.channel,
|
|
365
|
+
priority: params.priority,
|
|
366
|
+
title: params.title,
|
|
367
|
+
body: params.body,
|
|
368
|
+
data: params.data,
|
|
369
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
370
|
+
readAt: void 0
|
|
371
|
+
};
|
|
372
|
+
yield* Ref2.update(notificationsRef, (m) => {
|
|
373
|
+
const next = new Map(m);
|
|
374
|
+
next.set(notification.id, notification);
|
|
375
|
+
return next;
|
|
376
|
+
});
|
|
377
|
+
yield* eventBus.publish({
|
|
378
|
+
_tag: "Custom",
|
|
379
|
+
type: "interaction.notification",
|
|
380
|
+
payload: notification
|
|
381
|
+
});
|
|
382
|
+
return notification;
|
|
383
|
+
}),
|
|
384
|
+
listUnread: () => Ref2.get(notificationsRef).pipe(
|
|
385
|
+
Effect2.map(
|
|
386
|
+
(m) => Array.from(m.values()).filter((n) => n.readAt == null)
|
|
387
|
+
)
|
|
388
|
+
),
|
|
389
|
+
markRead: (notificationId) => Ref2.update(notificationsRef, (m) => {
|
|
390
|
+
const next = new Map(m);
|
|
391
|
+
const n = next.get(notificationId);
|
|
392
|
+
if (n) {
|
|
393
|
+
next.set(notificationId, { ...n, readAt: /* @__PURE__ */ new Date() });
|
|
394
|
+
}
|
|
395
|
+
return next;
|
|
396
|
+
})
|
|
397
|
+
};
|
|
398
|
+
})
|
|
399
|
+
);
|
|
400
|
+
|
|
401
|
+
// src/services/checkpoint-service.ts
|
|
402
|
+
import { Context as Context3, Effect as Effect3, Layer as Layer3, Ref as Ref3 } from "effect";
|
|
403
|
+
import { EventBus as EventBus3 } from "@reactive-agents/core";
|
|
404
|
+
var CheckpointService = class extends Context3.Tag("CheckpointService")() {
|
|
405
|
+
};
|
|
406
|
+
var CheckpointServiceLive = Layer3.effect(
|
|
407
|
+
CheckpointService,
|
|
408
|
+
Effect3.gen(function* () {
|
|
409
|
+
const eventBus = yield* EventBus3;
|
|
410
|
+
const checkpointsRef = yield* Ref3.make(/* @__PURE__ */ new Map());
|
|
411
|
+
return {
|
|
412
|
+
createCheckpoint: (params) => Effect3.gen(function* () {
|
|
413
|
+
const checkpoint = {
|
|
414
|
+
id: crypto.randomUUID(),
|
|
415
|
+
agentId: params.agentId,
|
|
416
|
+
taskId: params.taskId,
|
|
417
|
+
milestoneName: params.milestoneName,
|
|
418
|
+
description: params.description,
|
|
419
|
+
status: "pending",
|
|
420
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
421
|
+
};
|
|
422
|
+
yield* Ref3.update(checkpointsRef, (m) => {
|
|
423
|
+
const next = new Map(m);
|
|
424
|
+
next.set(checkpoint.id, checkpoint);
|
|
425
|
+
return next;
|
|
426
|
+
});
|
|
427
|
+
yield* eventBus.publish({
|
|
428
|
+
_tag: "Custom",
|
|
429
|
+
type: "interaction.checkpoint-created",
|
|
430
|
+
payload: checkpoint
|
|
431
|
+
});
|
|
432
|
+
return checkpoint;
|
|
433
|
+
}),
|
|
434
|
+
resolveCheckpoint: (checkpointId, status, comment) => Effect3.gen(function* () {
|
|
435
|
+
const checkpoints = yield* Ref3.get(checkpointsRef);
|
|
436
|
+
const existing = checkpoints.get(checkpointId);
|
|
437
|
+
if (!existing) {
|
|
438
|
+
return yield* Effect3.fail(
|
|
439
|
+
new CheckpointError({ checkpointId, message: "Checkpoint not found" })
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
const resolved = {
|
|
443
|
+
...existing,
|
|
444
|
+
status,
|
|
445
|
+
resolvedAt: /* @__PURE__ */ new Date(),
|
|
446
|
+
userComment: comment
|
|
447
|
+
};
|
|
448
|
+
yield* Ref3.update(checkpointsRef, (m) => {
|
|
449
|
+
const next = new Map(m);
|
|
450
|
+
next.set(checkpointId, resolved);
|
|
451
|
+
return next;
|
|
452
|
+
});
|
|
453
|
+
yield* eventBus.publish({
|
|
454
|
+
_tag: "Custom",
|
|
455
|
+
type: "interaction.checkpoint-resolved",
|
|
456
|
+
payload: resolved
|
|
457
|
+
});
|
|
458
|
+
return resolved;
|
|
459
|
+
}),
|
|
460
|
+
getCheckpoint: (checkpointId) => Effect3.gen(function* () {
|
|
461
|
+
const checkpoints = yield* Ref3.get(checkpointsRef);
|
|
462
|
+
const cp = checkpoints.get(checkpointId);
|
|
463
|
+
if (!cp) {
|
|
464
|
+
return yield* Effect3.fail(
|
|
465
|
+
new CheckpointError({ checkpointId, message: "Checkpoint not found" })
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
return cp;
|
|
469
|
+
}),
|
|
470
|
+
listPending: (agentId) => Ref3.get(checkpointsRef).pipe(
|
|
471
|
+
Effect3.map(
|
|
472
|
+
(m) => Array.from(m.values()).filter(
|
|
473
|
+
(cp) => cp.status === "pending" && (!agentId || cp.agentId === agentId)
|
|
474
|
+
)
|
|
475
|
+
)
|
|
476
|
+
)
|
|
477
|
+
};
|
|
478
|
+
})
|
|
479
|
+
);
|
|
480
|
+
|
|
481
|
+
// src/services/collaboration-service.ts
|
|
482
|
+
import { Context as Context4, Effect as Effect4, Layer as Layer4, Ref as Ref4 } from "effect";
|
|
483
|
+
import { EventBus as EventBus4 } from "@reactive-agents/core";
|
|
484
|
+
var CollaborationService = class extends Context4.Tag("CollaborationService")() {
|
|
485
|
+
};
|
|
486
|
+
var CollaborationServiceLive = Layer4.effect(
|
|
487
|
+
CollaborationService,
|
|
488
|
+
Effect4.gen(function* () {
|
|
489
|
+
const eventBus = yield* EventBus4;
|
|
490
|
+
const sessionsRef = yield* Ref4.make(/* @__PURE__ */ new Map());
|
|
491
|
+
const messagesRef = yield* Ref4.make(/* @__PURE__ */ new Map());
|
|
492
|
+
return {
|
|
493
|
+
startSession: (params) => Effect4.gen(function* () {
|
|
494
|
+
const sessionId = crypto.randomUUID();
|
|
495
|
+
const session = {
|
|
496
|
+
id: sessionId,
|
|
497
|
+
agentId: params.agentId,
|
|
498
|
+
taskId: params.taskId,
|
|
499
|
+
status: "active",
|
|
500
|
+
thinkingVisible: params.thinkingVisible ?? true,
|
|
501
|
+
streamingEnabled: params.streamingEnabled ?? false,
|
|
502
|
+
questionStyle: "inline",
|
|
503
|
+
rollbackEnabled: false,
|
|
504
|
+
startedAt: /* @__PURE__ */ new Date()
|
|
505
|
+
};
|
|
506
|
+
yield* Ref4.update(sessionsRef, (m) => {
|
|
507
|
+
const next = new Map(m);
|
|
508
|
+
next.set(sessionId, session);
|
|
509
|
+
return next;
|
|
510
|
+
});
|
|
511
|
+
yield* Ref4.update(messagesRef, (m) => {
|
|
512
|
+
const next = new Map(m);
|
|
513
|
+
next.set(sessionId, []);
|
|
514
|
+
return next;
|
|
515
|
+
});
|
|
516
|
+
yield* eventBus.publish({
|
|
517
|
+
_tag: "Custom",
|
|
518
|
+
type: "interaction.collaboration-started",
|
|
519
|
+
payload: session
|
|
520
|
+
});
|
|
521
|
+
return session;
|
|
522
|
+
}),
|
|
523
|
+
endSession: (sessionId) => Effect4.gen(function* () {
|
|
524
|
+
const sessions = yield* Ref4.get(sessionsRef);
|
|
525
|
+
const session = sessions.get(sessionId);
|
|
526
|
+
if (!session) {
|
|
527
|
+
return yield* Effect4.fail(new SessionNotFoundError({ sessionId }));
|
|
528
|
+
}
|
|
529
|
+
yield* Ref4.update(sessionsRef, (m) => {
|
|
530
|
+
const next = new Map(m);
|
|
531
|
+
next.set(sessionId, { ...session, status: "ended", endedAt: /* @__PURE__ */ new Date() });
|
|
532
|
+
return next;
|
|
533
|
+
});
|
|
534
|
+
}),
|
|
535
|
+
sendMessage: (params) => Effect4.gen(function* () {
|
|
536
|
+
const sessions = yield* Ref4.get(sessionsRef);
|
|
537
|
+
if (!sessions.has(params.sessionId)) {
|
|
538
|
+
return yield* Effect4.fail(new SessionNotFoundError({ sessionId: params.sessionId }));
|
|
539
|
+
}
|
|
540
|
+
const message = {
|
|
541
|
+
id: crypto.randomUUID(),
|
|
542
|
+
sessionId: params.sessionId,
|
|
543
|
+
type: params.type,
|
|
544
|
+
sender: params.sender,
|
|
545
|
+
content: params.content,
|
|
546
|
+
timestamp: /* @__PURE__ */ new Date()
|
|
547
|
+
};
|
|
548
|
+
yield* Ref4.update(messagesRef, (m) => {
|
|
549
|
+
const next = new Map(m);
|
|
550
|
+
const existing = next.get(params.sessionId) ?? [];
|
|
551
|
+
next.set(params.sessionId, [...existing, message]);
|
|
552
|
+
return next;
|
|
553
|
+
});
|
|
554
|
+
return message;
|
|
555
|
+
}),
|
|
556
|
+
getMessages: (sessionId) => Effect4.gen(function* () {
|
|
557
|
+
const sessions = yield* Ref4.get(sessionsRef);
|
|
558
|
+
if (!sessions.has(sessionId)) {
|
|
559
|
+
return yield* Effect4.fail(new SessionNotFoundError({ sessionId }));
|
|
560
|
+
}
|
|
561
|
+
const msgs = yield* Ref4.get(messagesRef);
|
|
562
|
+
return msgs.get(sessionId) ?? [];
|
|
563
|
+
}),
|
|
564
|
+
getSession: (sessionId) => Effect4.gen(function* () {
|
|
565
|
+
const sessions = yield* Ref4.get(sessionsRef);
|
|
566
|
+
const session = sessions.get(sessionId);
|
|
567
|
+
if (!session) {
|
|
568
|
+
return yield* Effect4.fail(new SessionNotFoundError({ sessionId }));
|
|
569
|
+
}
|
|
570
|
+
return session;
|
|
571
|
+
})
|
|
572
|
+
};
|
|
573
|
+
})
|
|
574
|
+
);
|
|
575
|
+
|
|
576
|
+
// src/services/preference-learner.ts
|
|
577
|
+
import { Context as Context5, Effect as Effect5, Layer as Layer5, Ref as Ref5 } from "effect";
|
|
578
|
+
var PreferenceLearner = class extends Context5.Tag("PreferenceLearner")() {
|
|
579
|
+
};
|
|
580
|
+
var PreferenceLearnerLive = Layer5.effect(
|
|
581
|
+
PreferenceLearner,
|
|
582
|
+
Effect5.gen(function* () {
|
|
583
|
+
const prefsRef = yield* Ref5.make(/* @__PURE__ */ new Map());
|
|
584
|
+
const getOrCreatePref = (userId) => Ref5.get(prefsRef).pipe(
|
|
585
|
+
Effect5.map(
|
|
586
|
+
(m) => m.get(userId) ?? {
|
|
587
|
+
userId,
|
|
588
|
+
learningEnabled: true,
|
|
589
|
+
interruptionTolerance: "medium",
|
|
590
|
+
approvalPatterns: [],
|
|
591
|
+
lastUpdated: /* @__PURE__ */ new Date()
|
|
592
|
+
}
|
|
593
|
+
)
|
|
594
|
+
);
|
|
595
|
+
return {
|
|
596
|
+
getPreference: (userId) => getOrCreatePref(userId),
|
|
597
|
+
recordApproval: (params) => Effect5.gen(function* () {
|
|
598
|
+
const pref = yield* getOrCreatePref(params.userId);
|
|
599
|
+
const existing = pref.approvalPatterns.find(
|
|
600
|
+
(p) => p.taskType === params.taskType
|
|
601
|
+
);
|
|
602
|
+
let updatedPatterns;
|
|
603
|
+
if (existing) {
|
|
604
|
+
updatedPatterns = pref.approvalPatterns.map(
|
|
605
|
+
(p) => p.taskType === params.taskType ? {
|
|
606
|
+
...p,
|
|
607
|
+
occurrences: p.occurrences + 1,
|
|
608
|
+
confidence: Math.min(1, p.confidence + 0.1),
|
|
609
|
+
action: params.approved ? "auto-approve" : p.action,
|
|
610
|
+
lastSeen: /* @__PURE__ */ new Date()
|
|
611
|
+
} : p
|
|
612
|
+
);
|
|
613
|
+
} else {
|
|
614
|
+
updatedPatterns = [
|
|
615
|
+
...pref.approvalPatterns,
|
|
616
|
+
{
|
|
617
|
+
id: crypto.randomUUID(),
|
|
618
|
+
taskType: params.taskType,
|
|
619
|
+
costThreshold: params.cost,
|
|
620
|
+
action: params.approved ? "auto-approve" : "ask",
|
|
621
|
+
confidence: 0.3,
|
|
622
|
+
occurrences: 1,
|
|
623
|
+
lastSeen: /* @__PURE__ */ new Date()
|
|
624
|
+
}
|
|
625
|
+
];
|
|
626
|
+
}
|
|
627
|
+
yield* Ref5.update(prefsRef, (m) => {
|
|
628
|
+
const next = new Map(m);
|
|
629
|
+
next.set(params.userId, {
|
|
630
|
+
...pref,
|
|
631
|
+
approvalPatterns: updatedPatterns,
|
|
632
|
+
lastUpdated: /* @__PURE__ */ new Date()
|
|
633
|
+
});
|
|
634
|
+
return next;
|
|
635
|
+
});
|
|
636
|
+
}),
|
|
637
|
+
shouldAutoApprove: (params) => Effect5.gen(function* () {
|
|
638
|
+
const pref = yield* getOrCreatePref(params.userId);
|
|
639
|
+
if (!pref.learningEnabled) return false;
|
|
640
|
+
const pattern = pref.approvalPatterns.find(
|
|
641
|
+
(p) => p.taskType === params.taskType
|
|
642
|
+
);
|
|
643
|
+
if (!pattern) return false;
|
|
644
|
+
if (pattern.confidence < 0.7 || pattern.occurrences < 3) return false;
|
|
645
|
+
if (pattern.action !== "auto-approve") return false;
|
|
646
|
+
if (params.cost && pattern.costThreshold && params.cost > pattern.costThreshold) {
|
|
647
|
+
return false;
|
|
648
|
+
}
|
|
649
|
+
return true;
|
|
650
|
+
}),
|
|
651
|
+
updateTolerance: (userId, tolerance) => Effect5.gen(function* () {
|
|
652
|
+
const pref = yield* getOrCreatePref(userId);
|
|
653
|
+
yield* Ref5.update(prefsRef, (m) => {
|
|
654
|
+
const next = new Map(m);
|
|
655
|
+
next.set(userId, {
|
|
656
|
+
...pref,
|
|
657
|
+
interruptionTolerance: tolerance,
|
|
658
|
+
lastUpdated: /* @__PURE__ */ new Date()
|
|
659
|
+
});
|
|
660
|
+
return next;
|
|
661
|
+
});
|
|
662
|
+
})
|
|
663
|
+
};
|
|
664
|
+
})
|
|
665
|
+
);
|
|
666
|
+
|
|
667
|
+
// src/services/interaction-manager.ts
|
|
668
|
+
import { EventBus as EventBus5 } from "@reactive-agents/core";
|
|
669
|
+
var InteractionManager = class extends Context6.Tag("InteractionManager")() {
|
|
670
|
+
};
|
|
671
|
+
var InteractionManagerLive = Layer6.effect(
|
|
672
|
+
InteractionManager,
|
|
673
|
+
Effect6.gen(function* () {
|
|
674
|
+
const modeSwitcher = yield* ModeSwitcher;
|
|
675
|
+
const notifications = yield* NotificationService;
|
|
676
|
+
const checkpoints = yield* CheckpointService;
|
|
677
|
+
const collaboration = yield* CollaborationService;
|
|
678
|
+
const preferences = yield* PreferenceLearner;
|
|
679
|
+
const eventBus = yield* EventBus5;
|
|
680
|
+
return {
|
|
681
|
+
// Mode
|
|
682
|
+
getMode: (agentId) => modeSwitcher.getMode(agentId),
|
|
683
|
+
switchMode: (agentId, mode) => Effect6.gen(function* () {
|
|
684
|
+
yield* modeSwitcher.setMode(agentId, mode);
|
|
685
|
+
yield* eventBus.publish({
|
|
686
|
+
_tag: "Custom",
|
|
687
|
+
type: "interaction.mode-changed",
|
|
688
|
+
payload: { agentId, mode }
|
|
689
|
+
});
|
|
690
|
+
}),
|
|
691
|
+
evaluateTransition: (agentId, context) => modeSwitcher.evaluateTransition(agentId, context),
|
|
692
|
+
// Notifications
|
|
693
|
+
notify: (params) => notifications.send({ ...params, data: void 0 }),
|
|
694
|
+
listUnread: () => notifications.listUnread(),
|
|
695
|
+
markRead: (notificationId) => notifications.markRead(notificationId),
|
|
696
|
+
// Checkpoints
|
|
697
|
+
createCheckpoint: (params) => checkpoints.createCheckpoint(params),
|
|
698
|
+
resolveCheckpoint: (id, status, comment) => checkpoints.resolveCheckpoint(id, status, comment),
|
|
699
|
+
listPendingCheckpoints: (agentId) => checkpoints.listPending(agentId),
|
|
700
|
+
// Collaboration
|
|
701
|
+
startCollaboration: (params) => collaboration.startSession(params),
|
|
702
|
+
endCollaboration: (sessionId) => collaboration.endSession(sessionId),
|
|
703
|
+
sendCollaborationMessage: (params) => collaboration.sendMessage(params),
|
|
704
|
+
// Preferences
|
|
705
|
+
getPreference: (userId) => preferences.getPreference(userId),
|
|
706
|
+
shouldAutoApprove: (params) => preferences.shouldAutoApprove(params)
|
|
707
|
+
};
|
|
708
|
+
})
|
|
709
|
+
);
|
|
710
|
+
|
|
711
|
+
// src/runtime.ts
|
|
712
|
+
import { Layer as Layer7 } from "effect";
|
|
713
|
+
var createInteractionLayer = (config = defaultInteractionConfig) => {
|
|
714
|
+
const NotificationLayer = NotificationServiceLive;
|
|
715
|
+
const SwitcherLayer = ModeSwitcherLive(config);
|
|
716
|
+
const CheckpointLayer = CheckpointServiceLive;
|
|
717
|
+
const CollaborationLayer = CollaborationServiceLive;
|
|
718
|
+
const PreferenceLayer = PreferenceLearnerLive;
|
|
719
|
+
const LeafLayers = Layer7.mergeAll(
|
|
720
|
+
NotificationLayer,
|
|
721
|
+
SwitcherLayer,
|
|
722
|
+
CheckpointLayer,
|
|
723
|
+
CollaborationLayer,
|
|
724
|
+
PreferenceLayer
|
|
725
|
+
);
|
|
726
|
+
const ManagerLayer = InteractionManagerLive.pipe(Layer7.provide(LeafLayers));
|
|
727
|
+
return Layer7.mergeAll(ManagerLayer, LeafLayers);
|
|
728
|
+
};
|
|
729
|
+
export {
|
|
730
|
+
ApprovalAction,
|
|
731
|
+
ApprovalPatternSchema,
|
|
732
|
+
AutoApproveAction,
|
|
733
|
+
CheckpointConfigSchema,
|
|
734
|
+
CheckpointError,
|
|
735
|
+
CheckpointFrequency,
|
|
736
|
+
CheckpointSchema,
|
|
737
|
+
CheckpointService,
|
|
738
|
+
CheckpointServiceLive,
|
|
739
|
+
CheckpointStatus,
|
|
740
|
+
CollaborationMessageSchema,
|
|
741
|
+
CollaborationMessageType,
|
|
742
|
+
CollaborationService,
|
|
743
|
+
CollaborationServiceLive,
|
|
744
|
+
CollaborationSessionSchema,
|
|
745
|
+
CollaborationStatus,
|
|
746
|
+
EscalationConditionSchema,
|
|
747
|
+
EscalationConditionType,
|
|
748
|
+
InputTimeoutError,
|
|
749
|
+
InteractionConfigSchema,
|
|
750
|
+
InteractionError,
|
|
751
|
+
InteractionManager,
|
|
752
|
+
InteractionManagerLive,
|
|
753
|
+
InteractionModeSchema,
|
|
754
|
+
InteractionModeType,
|
|
755
|
+
InterruptEventSchema,
|
|
756
|
+
InterruptRuleSchema,
|
|
757
|
+
InterruptSeverity,
|
|
758
|
+
InterruptTrigger,
|
|
759
|
+
InterruptionTolerance,
|
|
760
|
+
ModeError,
|
|
761
|
+
ModeSwitcher,
|
|
762
|
+
ModeSwitcherLive,
|
|
763
|
+
ModeTransitionRuleSchema,
|
|
764
|
+
NotificationChannel,
|
|
765
|
+
NotificationError,
|
|
766
|
+
NotificationPriority,
|
|
767
|
+
NotificationSchema,
|
|
768
|
+
NotificationService,
|
|
769
|
+
NotificationServiceLive,
|
|
770
|
+
PreferenceLearner,
|
|
771
|
+
PreferenceLearnerLive,
|
|
772
|
+
QuestionStyle,
|
|
773
|
+
ReportingConfigSchema,
|
|
774
|
+
ReportingDetailLevel,
|
|
775
|
+
ReportingFrequency,
|
|
776
|
+
SessionId,
|
|
777
|
+
SessionNotFoundError,
|
|
778
|
+
UserPreferenceSchema,
|
|
779
|
+
createInteractionLayer,
|
|
780
|
+
defaultInteractionConfig
|
|
781
|
+
};
|
|
782
|
+
//# sourceMappingURL=index.js.map
|