effect-assistant 0.0.0-stage → 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.
Files changed (172) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +22 -2
  3. package/dist/AppEvent.d.ts +111 -0
  4. package/dist/AppEvent.d.ts.map +1 -0
  5. package/dist/AppEvent.js +71 -0
  6. package/dist/AppEvent.js.map +1 -0
  7. package/dist/Assistant.d.ts +403 -0
  8. package/dist/Assistant.d.ts.map +1 -0
  9. package/dist/Assistant.js +126 -0
  10. package/dist/Assistant.js.map +1 -0
  11. package/dist/AssistantActivity.d.ts +85 -0
  12. package/dist/AssistantActivity.d.ts.map +1 -0
  13. package/dist/AssistantActivity.js +105 -0
  14. package/dist/AssistantActivity.js.map +1 -0
  15. package/dist/AssistantEngine.d.ts +116 -0
  16. package/dist/AssistantEngine.d.ts.map +1 -0
  17. package/dist/AssistantEngine.js +255 -0
  18. package/dist/AssistantEngine.js.map +1 -0
  19. package/dist/AssistantEvent.d.ts +551 -0
  20. package/dist/AssistantEvent.d.ts.map +1 -0
  21. package/dist/AssistantEvent.js +473 -0
  22. package/dist/AssistantEvent.js.map +1 -0
  23. package/dist/AssistantLoop.d.ts +173 -0
  24. package/dist/AssistantLoop.d.ts.map +1 -0
  25. package/dist/AssistantLoop.js +111 -0
  26. package/dist/AssistantLoop.js.map +1 -0
  27. package/dist/AssistantToolCall.d.ts +32 -0
  28. package/dist/AssistantToolCall.d.ts.map +1 -0
  29. package/dist/AssistantToolCall.js +37 -0
  30. package/dist/AssistantToolCall.js.map +1 -0
  31. package/dist/Block.d.ts +69 -0
  32. package/dist/Block.d.ts.map +1 -0
  33. package/dist/Block.js +39 -0
  34. package/dist/Block.js.map +1 -0
  35. package/dist/BlockKit.d.ts +180 -0
  36. package/dist/BlockKit.d.ts.map +1 -0
  37. package/dist/BlockKit.js +148 -0
  38. package/dist/BlockKit.js.map +1 -0
  39. package/dist/ChatId.d.ts +31 -0
  40. package/dist/ChatId.d.ts.map +1 -0
  41. package/dist/ChatId.js +36 -0
  42. package/dist/ChatId.js.map +1 -0
  43. package/dist/ChatLog.d.ts +109 -0
  44. package/dist/ChatLog.d.ts.map +1 -0
  45. package/dist/ChatLog.js +177 -0
  46. package/dist/ChatLog.js.map +1 -0
  47. package/dist/ChatView.d.ts +408 -0
  48. package/dist/ChatView.d.ts.map +1 -0
  49. package/dist/ChatView.js +443 -0
  50. package/dist/ChatView.js.map +1 -0
  51. package/dist/Chats.d.ts +110 -0
  52. package/dist/Chats.d.ts.map +1 -0
  53. package/dist/Chats.js +98 -0
  54. package/dist/Chats.js.map +1 -0
  55. package/dist/Compaction.d.ts +105 -0
  56. package/dist/Compaction.d.ts.map +1 -0
  57. package/dist/Compaction.js +126 -0
  58. package/dist/Compaction.js.map +1 -0
  59. package/dist/CurrentChat.d.ts +40 -0
  60. package/dist/CurrentChat.d.ts.map +1 -0
  61. package/dist/CurrentChat.js +33 -0
  62. package/dist/CurrentChat.js.map +1 -0
  63. package/dist/InputId.d.ts +38 -0
  64. package/dist/InputId.d.ts.map +1 -0
  65. package/dist/InputId.js +43 -0
  66. package/dist/InputId.js.map +1 -0
  67. package/dist/Instructions.d.ts +56 -0
  68. package/dist/Instructions.d.ts.map +1 -0
  69. package/dist/Instructions.js +50 -0
  70. package/dist/Instructions.js.map +1 -0
  71. package/dist/Memory.d.ts +190 -0
  72. package/dist/Memory.d.ts.map +1 -0
  73. package/dist/Memory.js +216 -0
  74. package/dist/Memory.js.map +1 -0
  75. package/dist/RunId.d.ts +41 -0
  76. package/dist/RunId.d.ts.map +1 -0
  77. package/dist/RunId.js +46 -0
  78. package/dist/RunId.js.map +1 -0
  79. package/dist/Skill.d.ts +72 -0
  80. package/dist/Skill.d.ts.map +1 -0
  81. package/dist/Skill.js +58 -0
  82. package/dist/Skill.js.map +1 -0
  83. package/dist/Specialist.d.ts +267 -0
  84. package/dist/Specialist.d.ts.map +1 -0
  85. package/dist/Specialist.js +119 -0
  86. package/dist/Specialist.js.map +1 -0
  87. package/dist/ToolDiscovery.d.ts +107 -0
  88. package/dist/ToolDiscovery.d.ts.map +1 -0
  89. package/dist/ToolDiscovery.js +140 -0
  90. package/dist/ToolDiscovery.js.map +1 -0
  91. package/dist/ToolFailure.d.ts +66 -0
  92. package/dist/ToolFailure.d.ts.map +1 -0
  93. package/dist/ToolFailure.js +79 -0
  94. package/dist/ToolFailure.js.map +1 -0
  95. package/dist/_virtual/_rolldown/runtime.js +13 -0
  96. package/dist/index.d.ts +24 -0
  97. package/dist/index.js +24 -0
  98. package/dist/internal/chat.js +177 -0
  99. package/dist/internal/chat.js.map +1 -0
  100. package/dist/internal/events.d.ts +46 -0
  101. package/dist/internal/events.d.ts.map +1 -0
  102. package/dist/internal/events.js +65 -0
  103. package/dist/internal/events.js.map +1 -0
  104. package/dist/internal/history.js +147 -0
  105. package/dist/internal/history.js.map +1 -0
  106. package/dist/internal/instructions.js +11 -0
  107. package/dist/internal/instructions.js.map +1 -0
  108. package/dist/internal/loop.d.ts +73 -0
  109. package/dist/internal/loop.d.ts.map +1 -0
  110. package/dist/internal/loop.js +131 -0
  111. package/dist/internal/loop.js.map +1 -0
  112. package/dist/internal/schema.js +14 -0
  113. package/dist/internal/schema.js.map +1 -0
  114. package/dist/internal/skills.js +28 -0
  115. package/dist/internal/skills.js.map +1 -0
  116. package/dist/internal/specialists.js +272 -0
  117. package/dist/internal/specialists.js.map +1 -0
  118. package/dist/internal/telemetry.js +85 -0
  119. package/dist/internal/telemetry.js.map +1 -0
  120. package/dist/internal/toolkit.d.ts +62 -0
  121. package/dist/internal/toolkit.d.ts.map +1 -0
  122. package/dist/internal/toolkit.js +108 -0
  123. package/dist/internal/toolkit.js.map +1 -0
  124. package/dist/internal/tools.js +113 -0
  125. package/dist/internal/tools.js.map +1 -0
  126. package/dist/internal/turns.d.ts +64 -0
  127. package/dist/internal/turns.d.ts.map +1 -0
  128. package/dist/internal/turns.js +214 -0
  129. package/dist/internal/turns.js.map +1 -0
  130. package/dist/internal/uuid.js +45 -0
  131. package/dist/internal/uuid.js.map +1 -0
  132. package/dist/internal/writer.d.ts +12 -0
  133. package/dist/internal/writer.d.ts.map +1 -0
  134. package/package.json +52 -3
  135. package/src/AppEvent.ts +134 -0
  136. package/src/Assistant.ts +589 -0
  137. package/src/AssistantActivity.ts +150 -0
  138. package/src/AssistantEngine.ts +343 -0
  139. package/src/AssistantEvent.ts +569 -0
  140. package/src/AssistantLoop.ts +209 -0
  141. package/src/AssistantToolCall.ts +40 -0
  142. package/src/Block.ts +84 -0
  143. package/src/BlockKit.ts +298 -0
  144. package/src/ChatId.ts +36 -0
  145. package/src/ChatLog.ts +247 -0
  146. package/src/ChatView.ts +587 -0
  147. package/src/Chats.ts +122 -0
  148. package/src/Compaction.ts +207 -0
  149. package/src/CurrentChat.ts +47 -0
  150. package/src/InputId.ts +43 -0
  151. package/src/Instructions.ts +72 -0
  152. package/src/Memory.ts +276 -0
  153. package/src/RunId.ts +46 -0
  154. package/src/Skill.ts +91 -0
  155. package/src/Specialist.ts +355 -0
  156. package/src/ToolDiscovery.ts +179 -0
  157. package/src/ToolFailure.ts +74 -0
  158. package/src/index.ts +120 -0
  159. package/src/internal/chat.ts +323 -0
  160. package/src/internal/events.ts +100 -0
  161. package/src/internal/history.ts +294 -0
  162. package/src/internal/instructions.ts +9 -0
  163. package/src/internal/loop.ts +274 -0
  164. package/src/internal/schema.ts +25 -0
  165. package/src/internal/skills.ts +37 -0
  166. package/src/internal/specialists.ts +410 -0
  167. package/src/internal/telemetry.ts +125 -0
  168. package/src/internal/toolkit.ts +188 -0
  169. package/src/internal/tools.ts +159 -0
  170. package/src/internal/turns.ts +410 -0
  171. package/src/internal/uuid.ts +50 -0
  172. package/src/internal/writer.ts +12 -0
@@ -0,0 +1,473 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { ChatId } from "./ChatId.js";
3
+ import { InputId, make } from "./InputId.js";
4
+ import { RunId } from "./RunId.js";
5
+ import * as Predicate from "effect/Predicate";
6
+ import * as Schema from "effect/Schema";
7
+ import * as Response from "effect/ai/Response";
8
+ //#region src/AssistantEvent.ts
9
+ /**
10
+ * Defines the events that can happen in a chat.
11
+ *
12
+ * A chat is an append-only log of these events, and the log is the source of truth. A chat client
13
+ * receives the part of the log its user sees (`ChatView`), and the model's history is rebuilt
14
+ * from the log before every model call. Besides the library's events ({@link AssistantEvent}), a
15
+ * log holds the application's own events ({@link StoredAppEvent}).
16
+ *
17
+ * @since 0.1.0
18
+ */
19
+ var AssistantEvent_exports = /* @__PURE__ */ __exportAll({
20
+ AppTag: () => AppTag,
21
+ AssistantEvent: () => AssistantEvent,
22
+ AssistantMessage: () => AssistantMessage,
23
+ Attachment: () => Attachment,
24
+ BlockAnswer: () => BlockAnswer,
25
+ BlocksClosed: () => BlocksClosed,
26
+ ChatDeleted: () => ChatDeleted,
27
+ Entry: () => Entry,
28
+ Input: () => Input,
29
+ MessageBlock: () => MessageBlock,
30
+ ModelOutput: () => ModelOutput,
31
+ ModelPart: () => ModelPart,
32
+ SpecialistFinished: () => SpecialistFinished,
33
+ SpecialistStarted: () => SpecialistStarted,
34
+ StoredAppEvent: () => StoredAppEvent,
35
+ ToolCallPart: () => ToolCallPart,
36
+ ToolOutcome: () => ToolOutcome,
37
+ ToolResult: () => ToolResult,
38
+ ToolStarted: () => ToolStarted,
39
+ TurnCompleted: () => TurnCompleted,
40
+ TurnFailed: () => TurnFailed,
41
+ TurnStarted: () => TurnStarted,
42
+ UserInput: () => UserInput,
43
+ UserMessage: () => UserMessage,
44
+ assistantTexts: () => assistantTexts,
45
+ attachmentLine: () => attachmentLine,
46
+ formatSize: () => formatSize,
47
+ isInput: () => isInput,
48
+ isLibraryEvent: () => isLibraryEvent,
49
+ isTurnEnd: () => isTurnEnd,
50
+ isUserInput: () => isUserInput,
51
+ isWaking: () => isWaking,
52
+ maxAttachments: () => 10,
53
+ textWithAttachments: () => textWithAttachments
54
+ });
55
+ /**
56
+ * Schema for a file the user attached to a message, kept by reference.
57
+ *
58
+ * The file itself is stored elsewhere, so the log never holds its bytes.
59
+ *
60
+ * @category schemas
61
+ * @since 0.1.0
62
+ */
63
+ const Attachment = Schema.Struct({
64
+ fileId: Schema.String.check(Schema.isMaxLength(64)),
65
+ name: Schema.String.check(Schema.isMaxLength(255)),
66
+ mediaType: Schema.String.check(Schema.isMaxLength(127)),
67
+ /** In bytes. */
68
+ size: Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0))
69
+ });
70
+ /**
71
+ * The maximum number of files one message can carry.
72
+ *
73
+ * Each attached file is a line in every prompt after the message.
74
+ *
75
+ * @category utils
76
+ * @since 0.1.0
77
+ */
78
+ const maxAttachments = 10;
79
+ /**
80
+ * Formats a byte count for people and the model, such as `2.1 MB`.
81
+ *
82
+ * @category utils
83
+ * @since 0.1.0
84
+ */
85
+ const formatSize = (bytes) => bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : bytes < 1073741824 ? `${(bytes / 1048576).toFixed(1)} MB` : `${(bytes / 1073741824).toFixed(1)} GB`;
86
+ /**
87
+ * Returns the line the model reads for an attachment.
88
+ *
89
+ * The line names the file and never holds its content.
90
+ *
91
+ * @category utils
92
+ * @since 0.1.0
93
+ */
94
+ const attachmentLine = (attachment) => `[attached: ${attachment.name}, ${attachment.mediaType}, ${formatSize(attachment.size)}, id ${attachment.fileId}]`;
95
+ /**
96
+ * Returns a message's text followed by a line for each attached file.
97
+ *
98
+ * @category utils
99
+ * @since 0.1.0
100
+ */
101
+ const textWithAttachments = (text, attachments) => attachments === void 0 || attachments.length === 0 ? text : [text, ...attachments.map(attachmentLine)].filter((part) => part.length > 0).join("\n");
102
+ /**
103
+ * Represents text the user typed, and the files they attached.
104
+ *
105
+ * `id` defaults to a new one. Pass the client's own id so that a retried send stores the message
106
+ * once.
107
+ *
108
+ * @category schemas
109
+ * @since 0.1.0
110
+ */
111
+ var UserMessage = class extends Schema.TaggedClass()("UserMessage", {
112
+ id: InputId.pipe(Schema.withConstructorDefault(make())),
113
+ text: Schema.String,
114
+ attachments: Schema.optional(Schema.Array(Attachment).check(Schema.isMaxLength(10)))
115
+ }) {};
116
+ /**
117
+ * Represents the user's answer to a block.
118
+ *
119
+ * It holds the id of the message the block was on, and the value in the block's answer schema
120
+ * (in its JSON form). A chat UI shows it inside the block rather than as a message.
121
+ *
122
+ * @category schemas
123
+ * @since 0.1.0
124
+ */
125
+ var BlockAnswer = class extends Schema.TaggedClass()("BlockAnswer", {
126
+ id: InputId,
127
+ messageId: Schema.String,
128
+ kind: Schema.String,
129
+ value: Schema.Unknown
130
+ }) {};
131
+ /**
132
+ * Represents a specialist run that finished working on a brief.
133
+ *
134
+ * Unless the assistant stopped the run, it is an input, and a turn reads its report and decides
135
+ * what to tell the user. Its id is fixed per run and brief, so it is stored once.
136
+ *
137
+ * @category schemas
138
+ * @since 0.1.0
139
+ */
140
+ var SpecialistFinished = class extends Schema.TaggedClass()("SpecialistFinished", {
141
+ id: InputId,
142
+ runId: RunId,
143
+ specialist: Schema.String,
144
+ /** Which brief this answers: 1 for the first, then one more per follow-up. */
145
+ brief: Schema.Int,
146
+ goal: Schema.String,
147
+ status: Schema.Literals([
148
+ "answered",
149
+ "failed",
150
+ "stopped",
151
+ "cut_off"
152
+ ]),
153
+ report: Schema.optional(Schema.String),
154
+ error: Schema.optional(Schema.String)
155
+ }) {};
156
+ /**
157
+ * Schema for every input `Assistant.submit` accepts.
158
+ *
159
+ * @category schemas
160
+ * @since 0.1.0
161
+ */
162
+ const Input = Schema.Union([
163
+ UserMessage,
164
+ BlockAnswer,
165
+ SpecialistFinished
166
+ ]);
167
+ /**
168
+ * Schema for the inputs from the chat's user, which are messages and block answers.
169
+ *
170
+ * A turn owes each one a reply. It is also what a chat client usually may submit, since the app's
171
+ * events come from the server.
172
+ *
173
+ * @category schemas
174
+ * @since 0.1.0
175
+ */
176
+ const UserInput = Schema.Union([UserMessage, BlockAnswer]);
177
+ /**
178
+ * Represents the UI shown with a message, as a block kind from the assistant's `BlockKit` and its
179
+ * props.
180
+ *
181
+ * @category schemas
182
+ * @since 0.1.0
183
+ */
184
+ var MessageBlock = class extends Schema.Class("effect-assistant/MessageBlock")({
185
+ kind: Schema.String,
186
+ props: Schema.Unknown
187
+ }) {};
188
+ /**
189
+ * Represents a message the assistant sent the user with `send_user_message`, optionally with a
190
+ * block.
191
+ *
192
+ * @category schemas
193
+ * @since 0.1.0
194
+ */
195
+ var AssistantMessage = class extends Schema.TaggedClass()("AssistantMessage", {
196
+ id: Schema.String,
197
+ text: Schema.String,
198
+ block: Schema.optional(MessageBlock),
199
+ /** Earlier messages whose block the user answered by typing instead. Their blocks close. */
200
+ closes: Schema.optional(Schema.Array(Schema.String))
201
+ }) {};
202
+ /**
203
+ * Schema for a tool call the model made.
204
+ *
205
+ * It is `effect/ai`'s tool call part (`Response.ToolCallPart`) for any tool, with its params in
206
+ * JSON, as the model wrote them.
207
+ *
208
+ * @category schemas
209
+ * @since 0.1.0
210
+ */
211
+ const ToolCallPart = Schema.Struct({
212
+ ...Response.ToolCallPart("", Schema.Json).fields,
213
+ name: Schema.String
214
+ }).annotate({ identifier: "ToolCallPart" });
215
+ /**
216
+ * Schema for what the log keeps of a model call.
217
+ *
218
+ * It uses `effect/ai`'s response parts for text, reasoning (with the provider's metadata, such as
219
+ * a thinking block's signature), and tool calls.
220
+ *
221
+ * @category schemas
222
+ * @since 0.1.0
223
+ */
224
+ const ModelPart = Schema.Union([
225
+ Response.TextPart,
226
+ Response.ReasoningPart,
227
+ ToolCallPart
228
+ ]);
229
+ /**
230
+ * Represents what one model call wrote, as response parts for text, reasoning, and tool calls.
231
+ *
232
+ * `Prompt.fromResponseParts` turns the parts into history.
233
+ *
234
+ * @category schemas
235
+ * @since 0.1.0
236
+ */
237
+ var ModelOutput = class extends Schema.TaggedClass()("ModelOutput", {
238
+ parts: Schema.Array(ModelPart),
239
+ /**
240
+ * The last entry the model had read when it wrote this. Inputs after it
241
+ * arrived while the model was working. A turn has handled what its
242
+ * outputs had read.
243
+ */
244
+ seenThroughSeq: Schema.optional(Schema.Int),
245
+ /** The model that wrote it, as the provider's id for it or the name the context gave it. */
246
+ model: Schema.optional(Schema.String),
247
+ /** The provider's id for the response, when it gives one. */
248
+ responseId: Schema.optional(Schema.String),
249
+ /** The call's token usage, with input (including the cache's reads and writes) and output. */
250
+ usage: Schema.optional(Response.Usage),
251
+ /** How long the call took, in milliseconds. */
252
+ durationMillis: Schema.optional(Schema.Finite)
253
+ }) {};
254
+ /**
255
+ * Represents a tool call that is about to run.
256
+ *
257
+ * It is stored before the tool runs, so after a crash the log says which calls may have done
258
+ * something. Those calls run again with the same call id (see `AssistantToolCall`).
259
+ *
260
+ * @category schemas
261
+ * @since 0.1.0
262
+ */
263
+ var ToolStarted = class extends Schema.TaggedClass()("ToolStarted", {
264
+ callId: Schema.String,
265
+ tool: Schema.String
266
+ }) {};
267
+ /**
268
+ * Schema for how a tool call went, either `"success"` or `"failure"`, which the model reads as an
269
+ * error.
270
+ *
271
+ * @category schemas
272
+ * @since 0.1.0
273
+ */
274
+ const ToolOutcome = Schema.Literals(["success", "failure"]);
275
+ /**
276
+ * Represents the result of one tool call, as the model reads it.
277
+ *
278
+ * It holds the tool's success or failure in its encoded (JSON) form, and which of the two it is. A
279
+ * failure includes its reason when it has one, which is a `ToolFailure`'s `reason` or the
280
+ * failure's tag.
281
+ *
282
+ * @category schemas
283
+ * @since 0.1.0
284
+ */
285
+ var ToolResult = class extends Schema.TaggedClass()("ToolResult", {
286
+ callId: Schema.String,
287
+ tool: Schema.String,
288
+ outcome: ToolOutcome,
289
+ result: Schema.Json,
290
+ reason: Schema.optional(Schema.String)
291
+ }) {};
292
+ /**
293
+ * Represents the start of a turn.
294
+ *
295
+ * @category schemas
296
+ * @since 0.1.0
297
+ */
298
+ var TurnStarted = class extends Schema.TaggedClass()("TurnStarted", {
299
+ /** The assistant that runs it. */
300
+ assistant: Schema.String,
301
+ /**
302
+ * The id of the turn's trace, when a tracer records it (not Effect's own, which exports nothing).
303
+ */
304
+ traceId: Schema.optional(Schema.String)
305
+ }) {};
306
+ /**
307
+ * Represents a turn that finished.
308
+ *
309
+ * `throughSeq` is the last entry the turn read. Inputs after it still need a turn.
310
+ *
311
+ * @category schemas
312
+ * @since 0.1.0
313
+ */
314
+ var TurnCompleted = class extends Schema.TaggedClass()("TurnCompleted", { throughSeq: Schema.Int }) {};
315
+ /**
316
+ * Represents a turn that failed.
317
+ *
318
+ * `throughSeq` covers everything stored when the turn failed, so a failing input isn't retried
319
+ * forever.
320
+ *
321
+ * @category schemas
322
+ * @since 0.1.0
323
+ */
324
+ var TurnFailed = class extends Schema.TaggedClass()("TurnFailed", {
325
+ throughSeq: Schema.Int,
326
+ message: Schema.String
327
+ }) {};
328
+ /**
329
+ * Represents a specialist run that started working, either spawned or continued by a follow-up
330
+ * message.
331
+ *
332
+ * The model doesn't see it, since the call that started the run says so, and the run's report
333
+ * arrives as a {@link SpecialistFinished}.
334
+ *
335
+ * @category schemas
336
+ * @since 0.1.0
337
+ */
338
+ var SpecialistStarted = class extends Schema.TaggedClass()("SpecialistStarted", {
339
+ runId: RunId,
340
+ specialist: Schema.String,
341
+ /** The goal it's working on. */
342
+ goal: Schema.String
343
+ }) {};
344
+ /**
345
+ * Represents the deletion of a chat.
346
+ *
347
+ * The chat stores nothing after it, the work running in the chat stopped, and its subscribers'
348
+ * streams end here. Its log stays.
349
+ *
350
+ * @category schemas
351
+ * @since 0.1.0
352
+ */
353
+ var ChatDeleted = class extends Schema.TaggedClass()("ChatDeleted", {}) {};
354
+ /**
355
+ * Represents blocks that closed without an answer, like the ones `BlockKit.closeStale` closes
356
+ * from a turn once the user moved on.
357
+ *
358
+ * The model doesn't see it.
359
+ *
360
+ * @category schemas
361
+ * @since 0.1.0
362
+ */
363
+ var BlocksClosed = class extends Schema.TaggedClass()("BlocksClosed", { messageIds: Schema.Array(Schema.String) }) {};
364
+ /**
365
+ * Schema for every event the library defines.
366
+ *
367
+ * @category schemas
368
+ * @since 0.1.0
369
+ */
370
+ const AssistantEvent = Schema.Union([
371
+ UserMessage,
372
+ BlockAnswer,
373
+ AssistantMessage,
374
+ ModelOutput,
375
+ ToolStarted,
376
+ ToolResult,
377
+ TurnStarted,
378
+ TurnCompleted,
379
+ TurnFailed,
380
+ SpecialistStarted,
381
+ SpecialistFinished,
382
+ BlocksClosed,
383
+ ChatDeleted
384
+ ]);
385
+ const libraryTags = new Set(AssistantEvent.members.map((member) => member.fields._tag.schema.literal));
386
+ /**
387
+ * Schema for the tag of one of the application's own events.
388
+ *
389
+ * It accepts any tag but the library's, and it is branded, so narrowing an entry's event to one
390
+ * of the library's events (`Predicate.isTagged(event, "UserMessage")`) never leaves an app event
391
+ * in.
392
+ *
393
+ * @category schemas
394
+ * @since 0.1.0
395
+ */
396
+ const AppTag = Schema.String.pipe(Schema.brand("~effect-assistant/AppTag"));
397
+ /**
398
+ * Schema for one of the application's own events as it is stored, with its `_tag` and its fields
399
+ * in JSON.
400
+ *
401
+ * An assistant made with `events: [AppEvent.make(Summary)]` decodes it to a `Summary` in
402
+ * `CurrentChat`'s `entries` and in its `subscribe`.
403
+ *
404
+ * @category schemas
405
+ * @since 0.1.0
406
+ */
407
+ const StoredAppEvent = Schema.StructWithRest(Schema.Struct({ _tag: AppTag }), [Schema.Record(Schema.String, Schema.Json)]).check(Schema.makeFilter((event) => !libraryTags.has(event._tag) || `${event._tag} is one of the library's events`));
408
+ /**
409
+ * Returns whether an event is one of the library's, not one of the app's own.
410
+ *
411
+ * @category guards
412
+ * @since 0.1.0
413
+ */
414
+ const isLibraryEvent = (event) => libraryTags.has(event._tag);
415
+ /**
416
+ * Schema for a stored event with its position in the chat.
417
+ *
418
+ * `seq` starts at 1 and has no gaps. `at` is the time the event was stored, in epoch
419
+ * milliseconds.
420
+ *
421
+ * @category schemas
422
+ * @since 0.1.0
423
+ */
424
+ const Entry = Schema.Struct({
425
+ chatId: ChatId,
426
+ seq: Schema.Int,
427
+ at: Schema.Finite,
428
+ event: Schema.Union([AssistantEvent, StoredAppEvent])
429
+ });
430
+ /**
431
+ * Returns whether an event is one of the library's inputs, which are a user message, a block
432
+ * answer, or a finished specialist run.
433
+ *
434
+ * The application's events that wake a turn are inputs too, but only their assistant knows which
435
+ * (see `AppEvent`).
436
+ *
437
+ * @category guards
438
+ * @since 0.1.0
439
+ */
440
+ const isInput = (event) => Predicate.isTagged(event, "UserMessage") || Predicate.isTagged(event, "BlockAnswer") || Predicate.isTagged(event, "SpecialistFinished");
441
+ /**
442
+ * Returns whether an input starts a turn, which every input does except a run the assistant
443
+ * stopped itself.
444
+ *
445
+ * @category guards
446
+ * @since 0.1.0
447
+ */
448
+ const isWaking = (input) => !(Predicate.isTagged(input, "SpecialistFinished") && input.status === "stopped");
449
+ /**
450
+ * Returns whether an input came from the chat's user, and so is owed a reply.
451
+ *
452
+ * @category guards
453
+ * @since 0.1.0
454
+ */
455
+ const isUserInput = (input) => Predicate.isTagged(input, "UserMessage") || Predicate.isTagged(input, "BlockAnswer");
456
+ /**
457
+ * Returns whether an event ends a turn, and so says how far the assistant has read.
458
+ *
459
+ * @category guards
460
+ * @since 0.1.0
461
+ */
462
+ const isTurnEnd = (event) => Predicate.isTagged(event, "TurnCompleted") || Predicate.isTagged(event, "TurnFailed");
463
+ /**
464
+ * Returns the text of every message the user was shown, in order.
465
+ *
466
+ * @category utils
467
+ * @since 0.1.0
468
+ */
469
+ const assistantTexts = (entries) => entries.flatMap(({ event }) => isLibraryEvent(event) && Predicate.isTagged(event, "AssistantMessage") ? [event.text] : []);
470
+ //#endregion
471
+ export { AppTag, AssistantEvent, AssistantEvent_exports, AssistantMessage, Attachment, BlockAnswer, BlocksClosed, ChatDeleted, Entry, Input, MessageBlock, ModelOutput, ModelPart, SpecialistFinished, SpecialistStarted, StoredAppEvent, ToolCallPart, ToolOutcome, ToolResult, ToolStarted, TurnCompleted, TurnFailed, TurnStarted, UserInput, UserMessage, assistantTexts, attachmentLine, formatSize, isInput, isLibraryEvent, isTurnEnd, isUserInput, isWaking, maxAttachments, textWithAttachments };
472
+
473
+ //# sourceMappingURL=AssistantEvent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AssistantEvent.js","names":["makeInputId"],"sources":["../src/AssistantEvent.ts"],"sourcesContent":["/**\n * Defines the events that can happen in a chat.\n *\n * A chat is an append-only log of these events, and the log is the source of truth. A chat client\n * receives the part of the log its user sees (`ChatView`), and the model's history is rebuilt\n * from the log before every model call. Besides the library's events ({@link AssistantEvent}), a\n * log holds the application's own events ({@link StoredAppEvent}).\n *\n * @since 0.1.0\n */\nimport * as Response from \"effect/ai/Response\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport { ChatId } from \"./ChatId.ts\"\nimport { InputId, make as makeInputId } from \"./InputId.ts\"\nimport { RunId } from \"./RunId.ts\"\n\n/**\n * Schema for a file the user attached to a message, kept by reference.\n *\n * The file itself is stored elsewhere, so the log never holds its bytes.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const Attachment = Schema.Struct({\n fileId: Schema.String.check(Schema.isMaxLength(64)),\n name: Schema.String.check(Schema.isMaxLength(255)),\n mediaType: Schema.String.check(Schema.isMaxLength(127)),\n /** In bytes. */\n size: Schema.Finite.check(Schema.isGreaterThanOrEqualTo(0))\n})\n\n/**\n * The maximum number of files one message can carry.\n *\n * Each attached file is a line in every prompt after the message.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const maxAttachments = 10\n\n/**\n * Represents a file the user attached to a message.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Attachment = typeof Attachment.Type\n\n/**\n * Formats a byte count for people and the model, such as `2.1 MB`.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const formatSize = (bytes: number): string =>\n bytes < 1024\n ? `${bytes} B`\n : bytes < 1024 * 1024\n ? `${(bytes / 1024).toFixed(1)} KB`\n : bytes < 1024 * 1024 * 1024\n ? `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n : `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`\n\n/**\n * Returns the line the model reads for an attachment.\n *\n * The line names the file and never holds its content.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const attachmentLine = (attachment: Attachment): string =>\n `[attached: ${attachment.name}, ${attachment.mediaType}, ${formatSize(attachment.size)}, id ${attachment.fileId}]`\n\n/**\n * Returns a message's text followed by a line for each attached file.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const textWithAttachments = (text: string, attachments: ReadonlyArray<Attachment> | undefined): string =>\n attachments === undefined || attachments.length === 0\n ? text\n : [text, ...attachments.map(attachmentLine)].filter((part) => part.length > 0).join(\"\\n\")\n\n/**\n * Represents text the user typed, and the files they attached.\n *\n * `id` defaults to a new one. Pass the client's own id so that a retried send stores the message\n * once.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class UserMessage extends Schema.TaggedClass<UserMessage>()(\"UserMessage\", {\n id: InputId.pipe(Schema.withConstructorDefault(makeInputId())),\n text: Schema.String,\n attachments: Schema.optional(Schema.Array(Attachment).check(Schema.isMaxLength(maxAttachments)))\n}) {}\n\n/**\n * Represents the user's answer to a block.\n *\n * It holds the id of the message the block was on, and the value in the block's answer schema\n * (in its JSON form). A chat UI shows it inside the block rather than as a message.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class BlockAnswer extends Schema.TaggedClass<BlockAnswer>()(\"BlockAnswer\", {\n id: InputId,\n messageId: Schema.String,\n kind: Schema.String,\n value: Schema.Unknown\n}) {}\n\n/**\n * Represents a specialist run that finished working on a brief.\n *\n * Unless the assistant stopped the run, it is an input, and a turn reads its report and decides\n * what to tell the user. Its id is fixed per run and brief, so it is stored once.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class SpecialistFinished extends Schema.TaggedClass<SpecialistFinished>()(\"SpecialistFinished\", {\n id: InputId,\n runId: RunId,\n specialist: Schema.String,\n /** Which brief this answers: 1 for the first, then one more per follow-up. */\n brief: Schema.Int,\n goal: Schema.String,\n status: Schema.Literals([\"answered\", \"failed\", \"stopped\", \"cut_off\"]),\n report: Schema.optional(Schema.String),\n error: Schema.optional(Schema.String)\n}) {}\n\n/**\n * Schema for every input `Assistant.submit` accepts.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const Input = Schema.Union([UserMessage, BlockAnswer, SpecialistFinished])\n\n/**\n * Represents an input to an assistant.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Input = typeof Input.Type\n\n/**\n * Schema for the inputs from the chat's user, which are messages and block answers.\n *\n * A turn owes each one a reply. It is also what a chat client usually may submit, since the app's\n * events come from the server.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const UserInput = Schema.Union([UserMessage, BlockAnswer])\n\n/**\n * Represents an input from the chat's user.\n *\n * @category models\n * @since 0.1.0\n */\nexport type UserInput = typeof UserInput.Type\n\n/**\n * Represents the UI shown with a message, as a block kind from the assistant's `BlockKit` and its\n * props.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class MessageBlock extends Schema.Class<MessageBlock>(\"effect-assistant/MessageBlock\")({\n kind: Schema.String,\n props: Schema.Unknown\n}) {}\n\n/**\n * Represents a message the assistant sent the user with `send_user_message`, optionally with a\n * block.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class AssistantMessage extends Schema.TaggedClass<AssistantMessage>()(\"AssistantMessage\", {\n id: Schema.String,\n text: Schema.String,\n block: Schema.optional(MessageBlock),\n /** Earlier messages whose block the user answered by typing instead. Their blocks close. */\n closes: Schema.optional(Schema.Array(Schema.String))\n}) {}\n\n/**\n * Schema for a tool call the model made.\n *\n * It is `effect/ai`'s tool call part (`Response.ToolCallPart`) for any tool, with its params in\n * JSON, as the model wrote them.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const ToolCallPart = Schema.Struct({\n ...Response.ToolCallPart(\"\", Schema.Json).fields,\n name: Schema.String\n}).annotate({ identifier: \"ToolCallPart\" })\n\n/**\n * Represents a tool call the model made.\n *\n * @category models\n * @since 0.1.0\n */\nexport type ToolCallPart = typeof ToolCallPart.Type\n\n/**\n * Schema for what the log keeps of a model call.\n *\n * It uses `effect/ai`'s response parts for text, reasoning (with the provider's metadata, such as\n * a thinking block's signature), and tool calls.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const ModelPart = Schema.Union([Response.TextPart, Response.ReasoningPart, ToolCallPart])\n\n/**\n * Represents a part of a model call's output.\n *\n * @category models\n * @since 0.1.0\n */\nexport type ModelPart = typeof ModelPart.Type\n\n/**\n * Represents what one model call wrote, as response parts for text, reasoning, and tool calls.\n *\n * `Prompt.fromResponseParts` turns the parts into history.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class ModelOutput extends Schema.TaggedClass<ModelOutput>()(\"ModelOutput\", {\n parts: Schema.Array(ModelPart),\n /**\n * The last entry the model had read when it wrote this. Inputs after it\n * arrived while the model was working. A turn has handled what its\n * outputs had read.\n */\n seenThroughSeq: Schema.optional(Schema.Int),\n /** The model that wrote it, as the provider's id for it or the name the context gave it. */\n model: Schema.optional(Schema.String),\n /** The provider's id for the response, when it gives one. */\n responseId: Schema.optional(Schema.String),\n /** The call's token usage, with input (including the cache's reads and writes) and output. */\n usage: Schema.optional(Response.Usage),\n /** How long the call took, in milliseconds. */\n durationMillis: Schema.optional(Schema.Finite)\n}) {}\n\n/**\n * Represents a tool call that is about to run.\n *\n * It is stored before the tool runs, so after a crash the log says which calls may have done\n * something. Those calls run again with the same call id (see `AssistantToolCall`).\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class ToolStarted extends Schema.TaggedClass<ToolStarted>()(\"ToolStarted\", {\n callId: Schema.String,\n tool: Schema.String\n}) {}\n\n/**\n * Schema for how a tool call went, either `\"success\"` or `\"failure\"`, which the model reads as an\n * error.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const ToolOutcome = Schema.Literals([\"success\", \"failure\"])\n\n/**\n * Represents how a tool call went.\n *\n * @category models\n * @since 0.1.0\n */\nexport type ToolOutcome = typeof ToolOutcome.Type\n\n/**\n * Represents the result of one tool call, as the model reads it.\n *\n * It holds the tool's success or failure in its encoded (JSON) form, and which of the two it is. A\n * failure includes its reason when it has one, which is a `ToolFailure`'s `reason` or the\n * failure's tag.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class ToolResult extends Schema.TaggedClass<ToolResult>()(\"ToolResult\", {\n callId: Schema.String,\n tool: Schema.String,\n outcome: ToolOutcome,\n result: Schema.Json,\n reason: Schema.optional(Schema.String)\n}) {}\n\n/**\n * Represents the start of a turn.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class TurnStarted extends Schema.TaggedClass<TurnStarted>()(\"TurnStarted\", {\n /** The assistant that runs it. */\n assistant: Schema.String,\n /**\n * The id of the turn's trace, when a tracer records it (not Effect's own, which exports nothing).\n */\n traceId: Schema.optional(Schema.String)\n}) {}\n\n/**\n * Represents a turn that finished.\n *\n * `throughSeq` is the last entry the turn read. Inputs after it still need a turn.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class TurnCompleted extends Schema.TaggedClass<TurnCompleted>()(\"TurnCompleted\", {\n throughSeq: Schema.Int\n}) {}\n\n/**\n * Represents a turn that failed.\n *\n * `throughSeq` covers everything stored when the turn failed, so a failing input isn't retried\n * forever.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class TurnFailed extends Schema.TaggedClass<TurnFailed>()(\"TurnFailed\", {\n throughSeq: Schema.Int,\n message: Schema.String\n}) {}\n\n/**\n * Represents a specialist run that started working, either spawned or continued by a follow-up\n * message.\n *\n * The model doesn't see it, since the call that started the run says so, and the run's report\n * arrives as a {@link SpecialistFinished}.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class SpecialistStarted extends Schema.TaggedClass<SpecialistStarted>()(\"SpecialistStarted\", {\n runId: RunId,\n specialist: Schema.String,\n /** The goal it's working on. */\n goal: Schema.String\n}) {}\n\n/**\n * Represents the deletion of a chat.\n *\n * The chat stores nothing after it, the work running in the chat stopped, and its subscribers'\n * streams end here. Its log stays.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class ChatDeleted extends Schema.TaggedClass<ChatDeleted>()(\"ChatDeleted\", {}) {}\n\n/**\n * Represents blocks that closed without an answer, like the ones `BlockKit.closeStale` closes\n * from a turn once the user moved on.\n *\n * The model doesn't see it.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class BlocksClosed extends Schema.TaggedClass<BlocksClosed>()(\"BlocksClosed\", {\n messageIds: Schema.Array(Schema.String)\n}) {}\n\n/**\n * Schema for every event the library defines.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const AssistantEvent = Schema.Union([\n UserMessage,\n BlockAnswer,\n AssistantMessage,\n ModelOutput,\n ToolStarted,\n ToolResult,\n TurnStarted,\n TurnCompleted,\n TurnFailed,\n SpecialistStarted,\n SpecialistFinished,\n BlocksClosed,\n ChatDeleted\n])\n\n/**\n * Represents an event the library defines.\n *\n * @category models\n * @since 0.1.0\n */\nexport type AssistantEvent = typeof AssistantEvent.Type\n\nconst libraryTags: ReadonlySet<string> = new Set(\n AssistantEvent.members.map((member) => member.fields._tag.schema.literal)\n)\n\n/**\n * Schema for the tag of one of the application's own events.\n *\n * It accepts any tag but the library's, and it is branded, so narrowing an entry's event to one\n * of the library's events (`Predicate.isTagged(event, \"UserMessage\")`) never leaves an app event\n * in.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const AppTag = Schema.String.pipe(Schema.brand(\"~effect-assistant/AppTag\"))\n\n/**\n * Schema for one of the application's own events as it is stored, with its `_tag` and its fields\n * in JSON.\n *\n * An assistant made with `events: [AppEvent.make(Summary)]` decodes it to a `Summary` in\n * `CurrentChat`'s `entries` and in its `subscribe`.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const StoredAppEvent = Schema.StructWithRest(Schema.Struct({ _tag: AppTag }), [\n Schema.Record(Schema.String, Schema.Json)\n]).check(Schema.makeFilter((event) => !libraryTags.has(event._tag) || `${event._tag} is one of the library's events`))\n\n/**\n * Represents one of the application's own events, as it is stored.\n *\n * @category models\n * @since 0.1.0\n */\nexport type StoredAppEvent = typeof StoredAppEvent.Type\n\n/**\n * Returns whether an event is one of the library's, not one of the app's own.\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isLibraryEvent = (event: { readonly _tag: string }): event is AssistantEvent => libraryTags.has(event._tag)\n\n/**\n * Represents a chat's entry with any event in it, either the library's or the application's own\n * (decoded or not).\n *\n * The folds over a chat take this type, so a client's typed entries fit too.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface AnyEntry {\n readonly chatId: ChatId\n readonly seq: number\n readonly at: number\n readonly event: { readonly _tag: string }\n}\n\n/**\n * Schema for a stored event with its position in the chat.\n *\n * `seq` starts at 1 and has no gaps. `at` is the time the event was stored, in epoch\n * milliseconds.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const Entry = Schema.Struct({\n chatId: ChatId,\n seq: Schema.Int,\n at: Schema.Finite,\n event: Schema.Union([AssistantEvent, StoredAppEvent])\n})\n\n/**\n * Represents a stored event with its position in the chat.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Entry = typeof Entry.Type\n\n/**\n * Returns whether an event is one of the library's inputs, which are a user message, a block\n * answer, or a finished specialist run.\n *\n * The application's events that wake a turn are inputs too, but only their assistant knows which\n * (see `AppEvent`).\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isInput = (event: { readonly _tag: string }): event is Input =>\n Predicate.isTagged(event, \"UserMessage\") ||\n Predicate.isTagged(event, \"BlockAnswer\") ||\n Predicate.isTagged(event, \"SpecialistFinished\")\n\n/**\n * Returns whether an input starts a turn, which every input does except a run the assistant\n * stopped itself.\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isWaking = (input: Input): boolean =>\n !(Predicate.isTagged(input, \"SpecialistFinished\") && input.status === \"stopped\")\n\n/**\n * Returns whether an input came from the chat's user, and so is owed a reply.\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isUserInput = (input: Input): input is UserInput =>\n Predicate.isTagged(input, \"UserMessage\") || Predicate.isTagged(input, \"BlockAnswer\")\n\n/**\n * Returns whether an event ends a turn, and so says how far the assistant has read.\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isTurnEnd = (event: { readonly _tag: string }): event is TurnCompleted | TurnFailed =>\n Predicate.isTagged(event, \"TurnCompleted\") || Predicate.isTagged(event, \"TurnFailed\")\n\n/**\n * Returns the text of every message the user was shown, in order.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const assistantTexts = (entries: ReadonlyArray<AnyEntry>): ReadonlyArray<string> =>\n entries.flatMap(({ event }) =>\n isLibraryEvent(event) && Predicate.isTagged(event, \"AssistantMessage\") ? [event.text] : []\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,aAAa,OAAO,OAAO;CACtC,QAAQ,OAAO,OAAO,MAAM,OAAO,YAAY,EAAE,CAAC;CAClD,MAAM,OAAO,OAAO,MAAM,OAAO,YAAY,GAAG,CAAC;CACjD,WAAW,OAAO,OAAO,MAAM,OAAO,YAAY,GAAG,CAAC;;CAEtD,MAAM,OAAO,OAAO,MAAM,OAAO,uBAAuB,CAAC,CAAC;AAC5D,CAAC;;;;;;;;;AAUD,MAAa,iBAAiB;;;;;;;AAgB9B,MAAa,cAAc,UACzB,QAAQ,OACJ,GAAG,MAAM,MACT,QAAQ,UACN,IAAI,QAAQ,KAAA,CAAM,QAAQ,CAAC,EAAE,OAC7B,QAAQ,aACN,IAAI,QAAS,QAAA,CAAc,QAAQ,CAAC,EAAE,OACtC,IAAI,QAAS,WAAA,CAAqB,QAAQ,CAAC,EAAE;;;;;;;;;AAUvD,MAAa,kBAAkB,eAC7B,cAAc,WAAW,KAAK,IAAI,WAAW,UAAU,IAAI,WAAW,WAAW,IAAI,EAAE,OAAO,WAAW,OAAO;;;;;;;AAQlH,MAAa,uBAAuB,MAAc,gBAChD,gBAAgB,KAAA,KAAa,YAAY,WAAW,IAChD,OACA,CAAC,MAAM,GAAG,YAAY,IAAI,cAAc,CAAC,CAAC,CAAC,QAAQ,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI;;;;;;;;;;AAW5F,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,IAAI,QAAQ,KAAK,OAAO,uBAAuBA,KAAY,CAAC,CAAC;CAC7D,MAAM,OAAO;CACb,aAAa,OAAO,SAAS,OAAO,MAAM,UAAU,CAAC,CAAC,MAAM,OAAO,YAAA,EAA0B,CAAC,CAAC;AACjG,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,IAAI;CACJ,WAAW,OAAO;CAClB,MAAM,OAAO;CACb,OAAO,OAAO;AAChB,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,IAAa,qBAAb,cAAwC,OAAO,YAAgC,CAAC,CAAC,sBAAsB;CACrG,IAAI;CACJ,OAAO;CACP,YAAY,OAAO;;CAEnB,OAAO,OAAO;CACd,MAAM,OAAO;CACb,QAAQ,OAAO,SAAS;EAAC;EAAY;EAAU;EAAW;CAAS,CAAC;CACpE,QAAQ,OAAO,SAAS,OAAO,MAAM;CACrC,OAAO,OAAO,SAAS,OAAO,MAAM;AACtC,CAAC,CAAC,CAAC,CAAC;;;;;;;AAQJ,MAAa,QAAQ,OAAO,MAAM;CAAC;CAAa;CAAa;AAAkB,CAAC;;;;;;;;;;AAmBhF,MAAa,YAAY,OAAO,MAAM,CAAC,aAAa,WAAW,CAAC;;;;;;;;AAiBhE,IAAa,eAAb,cAAkC,OAAO,MAAoB,+BAA+B,CAAC,CAAC;CAC5F,MAAM,OAAO;CACb,OAAO,OAAO;AAChB,CAAC,CAAC,CAAC,CAAC;;;;;;;;AASJ,IAAa,mBAAb,cAAsC,OAAO,YAA8B,CAAC,CAAC,oBAAoB;CAC/F,IAAI,OAAO;CACX,MAAM,OAAO;CACb,OAAO,OAAO,SAAS,YAAY;;CAEnC,QAAQ,OAAO,SAAS,OAAO,MAAM,OAAO,MAAM,CAAC;AACrD,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,MAAa,eAAe,OAAO,OAAO;CACxC,GAAG,SAAS,aAAa,IAAI,OAAO,IAAI,CAAC,CAAC;CAC1C,MAAM,OAAO;AACf,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,eAAe,CAAC;;;;;;;;;;AAmB1C,MAAa,YAAY,OAAO,MAAM;CAAC,SAAS;CAAU,SAAS;CAAe;AAAY,CAAC;;;;;;;;;AAkB/F,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,OAAO,OAAO,MAAM,SAAS;;;;;;CAM7B,gBAAgB,OAAO,SAAS,OAAO,GAAG;;CAE1C,OAAO,OAAO,SAAS,OAAO,MAAM;;CAEpC,YAAY,OAAO,SAAS,OAAO,MAAM;;CAEzC,OAAO,OAAO,SAAS,SAAS,KAAK;;CAErC,gBAAgB,OAAO,SAAS,OAAO,MAAM;AAC/C,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;CAChF,QAAQ,OAAO;CACf,MAAM,OAAO;AACf,CAAC,CAAC,CAAC,CAAC;;;;;;;;AASJ,MAAa,cAAc,OAAO,SAAS,CAAC,WAAW,SAAS,CAAC;;;;;;;;;;;AAoBjE,IAAa,aAAb,cAAgC,OAAO,YAAwB,CAAC,CAAC,cAAc;CAC7E,QAAQ,OAAO;CACf,MAAM,OAAO;CACb,SAAS;CACT,QAAQ,OAAO;CACf,QAAQ,OAAO,SAAS,OAAO,MAAM;AACvC,CAAC,CAAC,CAAC,CAAC;;;;;;;AAQJ,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe;;CAEhF,WAAW,OAAO;;;;CAIlB,SAAS,OAAO,SAAS,OAAO,MAAM;AACxC,CAAC,CAAC,CAAC,CAAC;;;;;;;;;AAUJ,IAAa,gBAAb,cAAmC,OAAO,YAA2B,CAAC,CAAC,iBAAiB,EACtF,YAAY,OAAO,IACrB,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,IAAa,aAAb,cAAgC,OAAO,YAAwB,CAAC,CAAC,cAAc;CAC7E,YAAY,OAAO;CACnB,SAAS,OAAO;AAClB,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;;AAYJ,IAAa,oBAAb,cAAuC,OAAO,YAA+B,CAAC,CAAC,qBAAqB;CAClG,OAAO;CACP,YAAY,OAAO;;CAEnB,MAAM,OAAO;AACf,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWJ,IAAa,cAAb,cAAiC,OAAO,YAAyB,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;AAWvF,IAAa,eAAb,cAAkC,OAAO,YAA0B,CAAC,CAAC,gBAAgB,EACnF,YAAY,OAAO,MAAM,OAAO,MAAM,EACxC,CAAC,CAAC,CAAC,CAAC;;;;;;;AAQJ,MAAa,iBAAiB,OAAO,MAAM;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF,CAAC;AAUD,MAAM,cAAmC,IAAI,IAC3C,eAAe,QAAQ,KAAK,WAAW,OAAO,OAAO,KAAK,OAAO,OAAO,CAC1E;;;;;;;;;;;AAYA,MAAa,SAAS,OAAO,OAAO,KAAK,OAAO,MAAM,0BAA0B,CAAC;;;;;;;;;;;AAYjF,MAAa,iBAAiB,OAAO,eAAe,OAAO,OAAO,EAAE,MAAM,OAAO,CAAC,GAAG,CACnF,OAAO,OAAO,OAAO,QAAQ,OAAO,IAAI,CAC1C,CAAC,CAAC,CAAC,MAAM,OAAO,YAAY,UAAU,CAAC,YAAY,IAAI,MAAM,IAAI,KAAK,GAAG,MAAM,KAAK,gCAAgC,CAAC;;;;;;;AAgBrH,MAAa,kBAAkB,UAA8D,YAAY,IAAI,MAAM,IAAI;;;;;;;;;;AA2BvH,MAAa,QAAQ,OAAO,OAAO;CACjC,QAAQ;CACR,KAAK,OAAO;CACZ,IAAI,OAAO;CACX,OAAO,OAAO,MAAM,CAAC,gBAAgB,cAAc,CAAC;AACtD,CAAC;;;;;;;;;;;AAoBD,MAAa,WAAW,UACtB,UAAU,SAAS,OAAO,aAAa,KACvC,UAAU,SAAS,OAAO,aAAa,KACvC,UAAU,SAAS,OAAO,oBAAoB;;;;;;;;AAShD,MAAa,YAAY,UACvB,EAAE,UAAU,SAAS,OAAO,oBAAoB,KAAK,MAAM,WAAW;;;;;;;AAQxE,MAAa,eAAe,UAC1B,UAAU,SAAS,OAAO,aAAa,KAAK,UAAU,SAAS,OAAO,aAAa;;;;;;;AAQrF,MAAa,aAAa,UACxB,UAAU,SAAS,OAAO,eAAe,KAAK,UAAU,SAAS,OAAO,YAAY;;;;;;;AAQtF,MAAa,kBAAkB,YAC7B,QAAQ,SAAS,EAAE,YACjB,eAAe,KAAK,KAAK,UAAU,SAAS,OAAO,kBAAkB,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,CAC3F"}
@@ -0,0 +1,173 @@
1
+ import { Instructions_d_exports, Resolved } from "./Instructions.js";
2
+ import { ToolServices, toolkit_d_exports } from "./internal/toolkit.js";
3
+ import { ChatHistory as ChatHistory$1, Event as Event$1, Step as Step$1, StepResult as StepResult$1, loop as loop$1, loop_d_exports, next as next$1, stop as stop$1, value as value$1 } from "./internal/loop.js";
4
+ import * as Effect from "effect/Effect";
5
+ import * as Stream from "effect/Stream";
6
+ import * as Prompt from "effect/ai/Prompt";
7
+ import * as Tool from "effect/ai/Tool";
8
+ import * as Toolkit from "effect/ai/Toolkit";
9
+ import * as LanguageModel from "effect/ai/LanguageModel";
10
+ import * as AiError from "effect/ai/AiError";
11
+ declare namespace AssistantLoop_d_exports {
12
+ export { ChatHistory, Event, Options, Step, StepOptions, StepResult, ToolkitServices, loop, next, run, step, stop, value };
13
+ }
14
+ /**
15
+ * Represents what the loop emits.
16
+ *
17
+ * For each model call, the loop emits the call's output. Then, for each of its tool calls, it
18
+ * emits a `ToolStarted` before the call runs and the call's result.
19
+ *
20
+ * @category models
21
+ * @since 0.1.0
22
+ */
23
+ export type Event = Event$1;
24
+ /**
25
+ * Represents a chat's history as the model reads it.
26
+ *
27
+ * It holds the messages, and the last `seq` of the chat they cover.
28
+ *
29
+ * @category models
30
+ * @since 0.1.0
31
+ */
32
+ export type ChatHistory = ChatHistory$1;
33
+ /**
34
+ * Represents how a step went, for deciding what comes next.
35
+ *
36
+ * @category models
37
+ * @since 0.1.0
38
+ */
39
+ export type StepResult = StepResult$1;
40
+ /**
41
+ * Represents what a loop body emits, which is either a value or what to do next.
42
+ *
43
+ * @category models
44
+ * @since 0.1.0
45
+ */
46
+ export type Step<A, S> = Step$1<A, S>;
47
+ /**
48
+ * Emits a value from a loop body.
49
+ *
50
+ * @category constructors
51
+ * @since 0.1.0
52
+ */
53
+ export declare const value: typeof value$1;
54
+ /**
55
+ * Ends a loop body's step and continues the loop with the given state.
56
+ *
57
+ * @category constructors
58
+ * @since 0.1.0
59
+ */
60
+ export declare const next: typeof next$1;
61
+ /**
62
+ * Ends the loop.
63
+ *
64
+ * @category constructors
65
+ * @since 0.1.0
66
+ */
67
+ export declare const stop: typeof stop$1;
68
+ /**
69
+ * Runs a loop body from an initial state.
70
+ *
71
+ * It emits the body's values, and runs the body again with the state it passes to `next`, until
72
+ * the body calls `stop`.
73
+ *
74
+ * @category constructors
75
+ * @since 0.1.0
76
+ */
77
+ export declare const loop: typeof loop$1;
78
+ type NoTools = Record<never, never>;
79
+ /**
80
+ * Extracts the services a toolkit's tools need when they run, which are their handlers and the
81
+ * services those handlers use.
82
+ *
83
+ * @category utility types
84
+ * @since 0.1.0
85
+ */
86
+ export type ToolkitServices<T extends Record<string, Tool.Any>> = Tool.HandlersFor<T> | ToolServices<T>;
87
+ /**
88
+ * Represents the options for {@link step}.
89
+ *
90
+ * @category models
91
+ * @since 0.1.0
92
+ */
93
+ export interface StepOptions<T extends Record<string, Tool.Any> = NoTools> {
94
+ /** The full system prompt, like `turn.instructions(text)`, optionally with span attributes. */
95
+ readonly instructions: string | Resolved;
96
+ /**
97
+ * The tools the model can call, in addition to the assistant's own tools in a turn. Their
98
+ * handlers come from the layer.
99
+ */
100
+ readonly toolkit?: Toolkit.Toolkit<T> | undefined;
101
+ /**
102
+ * The current history, read at the start of the step. It is either messages, or a chat's
103
+ * history (`turn.history()`), whose `throughSeq` the step's `ModelOutput` records as how far
104
+ * the model had read.
105
+ */
106
+ readonly history: Effect.Effect<ReadonlyArray<Prompt.Message> | ChatHistory>;
107
+ /**
108
+ * Defaults to `"auto"`, where a step without a tool call ends the loop. Forcing a call
109
+ * (`"required"`, or a tool by name) is refused by newer models, and with extended thinking.
110
+ */
111
+ readonly toolChoice?: LanguageModel.ToolChoice<string> | undefined;
112
+ }
113
+ /**
114
+ * Represents the options for {@link run}.
115
+ *
116
+ * @category models
117
+ * @since 0.1.0
118
+ */
119
+ export interface Options<T extends Record<string, Tool.Any> = NoTools> extends StepOptions<T> {
120
+ /** The model calls allowed. Defaults to 16. */
121
+ readonly maxSteps?: number | undefined;
122
+ }
123
+ /**
124
+ * Runs one step of the agent loop, as a body for {@link loop}.
125
+ *
126
+ * **Details**
127
+ *
128
+ * The step calls the model with the current history and emits its `ModelOutput`. It then runs
129
+ * the output's tool calls and emits a `ToolStarted` and a `ToolResult` for each. `then` receives
130
+ * the step's result and decides what comes next, with `AssistantLoop.next(state)` or
131
+ * `AssistantLoop.stop()`.
132
+ *
133
+ * A tool with Effect's `needsApproval` set fails the loop before the model is called: the
134
+ * library doesn't run calls that wait for approval (see the guide on involving the user).
135
+ *
136
+ * @category constructors
137
+ * @since 0.1.0
138
+ */
139
+ export declare const step: <T extends Record<string, Tool.Any> = NoTools, S = never, E2 = never, R2 = never>(options: StepOptions<T>, then: (result: StepResult) => Stream.Stream<Step<never, S>, E2, R2>) => Stream.Stream<Step<Event, S>, AiError.AiError | E2, LanguageModel.LanguageModel | ToolkitServices<T> | R2>;
140
+ /**
141
+ * Runs the agent loop as a stream.
142
+ *
143
+ * **Details**
144
+ *
145
+ * It runs {@link step} after step until the model is done and nothing new arrived while it
146
+ * worked, or until it has made `maxSteps` model calls.
147
+ *
148
+ * **Example** (A turn's loop with a step limit)
149
+ *
150
+ * ```ts
151
+ * import { AssistantLoop } from "effect-assistant"
152
+ * import * as Layer from "effect/Layer"
153
+ * import * as Stream from "effect/Stream"
154
+ *
155
+ * const instructions = "You help a small marketing team."
156
+ *
157
+ * const MyAssistantLive = MyAssistant.toLayer((turn) =>
158
+ * AssistantLoop.run({
159
+ * instructions: turn.instructions(instructions),
160
+ * toolkit: MyTools, // the assistant's own tools are added to them
161
+ * history: turn.history(),
162
+ * maxSteps: 12
163
+ * }).pipe(Stream.concat(turn.replyIfOwed({ instructions })))
164
+ * ).pipe(Layer.provide(MyToolsLive))
165
+ * ```
166
+ *
167
+ * @category constructors
168
+ * @since 0.1.0
169
+ */
170
+ export declare const run: <T extends Record<string, Tool.Any> = NoTools>(options: Options<T>) => Stream.Stream<Event, AiError.AiError, LanguageModel.LanguageModel | ToolkitServices<T>>;
171
+ //#endregion
172
+ export { AssistantLoop_d_exports };
173
+ //# sourceMappingURL=AssistantLoop.d.ts.map