effect-assistant 0.1.0 → 0.3.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 (131) hide show
  1. package/README.md +1 -1
  2. package/dist/Assistant.d.ts +74 -28
  3. package/dist/Assistant.d.ts.map +1 -1
  4. package/dist/Assistant.js +11 -4
  5. package/dist/Assistant.js.map +1 -1
  6. package/dist/AssistantActivity.d.ts +10 -16
  7. package/dist/AssistantActivity.d.ts.map +1 -1
  8. package/dist/AssistantActivity.js +11 -4
  9. package/dist/AssistantActivity.js.map +1 -1
  10. package/dist/AssistantEngine.d.ts +39 -1
  11. package/dist/AssistantEngine.d.ts.map +1 -1
  12. package/dist/AssistantEngine.js +81 -28
  13. package/dist/AssistantEngine.js.map +1 -1
  14. package/dist/AssistantEvent.d.ts +52 -70
  15. package/dist/AssistantEvent.d.ts.map +1 -1
  16. package/dist/AssistantEvent.js +28 -57
  17. package/dist/AssistantEvent.js.map +1 -1
  18. package/dist/AssistantLoop.d.ts +7 -5
  19. package/dist/AssistantLoop.d.ts.map +1 -1
  20. package/dist/AssistantLoop.js +6 -3
  21. package/dist/AssistantLoop.js.map +1 -1
  22. package/dist/Block.js.map +1 -1
  23. package/dist/BlockKit.d.ts +14 -18
  24. package/dist/BlockKit.d.ts.map +1 -1
  25. package/dist/BlockKit.js +4 -7
  26. package/dist/BlockKit.js.map +1 -1
  27. package/dist/ChatLog.js +1 -1
  28. package/dist/Compaction.d.ts +8 -4
  29. package/dist/Compaction.d.ts.map +1 -1
  30. package/dist/Compaction.js +12 -15
  31. package/dist/Compaction.js.map +1 -1
  32. package/dist/CurrentChat.d.ts +2 -1
  33. package/dist/CurrentChat.d.ts.map +1 -1
  34. package/dist/CurrentChat.js.map +1 -1
  35. package/dist/Instructions.js +1 -1
  36. package/dist/Skill.d.ts +33 -0
  37. package/dist/Skill.d.ts.map +1 -1
  38. package/dist/Skill.js +27 -1
  39. package/dist/Skill.js.map +1 -1
  40. package/dist/Specialist.d.ts +4 -1
  41. package/dist/Specialist.d.ts.map +1 -1
  42. package/dist/Specialist.js.map +1 -1
  43. package/dist/Timeline.d.ts +482 -0
  44. package/dist/Timeline.d.ts.map +1 -0
  45. package/dist/Timeline.js +572 -0
  46. package/dist/Timeline.js.map +1 -0
  47. package/dist/ToolDiscovery.d.ts +4 -5
  48. package/dist/ToolDiscovery.d.ts.map +1 -1
  49. package/dist/ToolDiscovery.js +5 -4
  50. package/dist/ToolDiscovery.js.map +1 -1
  51. package/dist/ToolFailure.d.ts +1 -1
  52. package/dist/ToolFailure.js +1 -1
  53. package/dist/ToolFailure.js.map +1 -1
  54. package/dist/index.d.ts +2 -5
  55. package/dist/index.js +4 -7
  56. package/dist/internal/chat.js +11 -37
  57. package/dist/internal/chat.js.map +1 -1
  58. package/dist/internal/events.d.ts +15 -16
  59. package/dist/internal/events.d.ts.map +1 -1
  60. package/dist/internal/events.js +29 -28
  61. package/dist/internal/events.js.map +1 -1
  62. package/dist/internal/history.js +26 -58
  63. package/dist/internal/history.js.map +1 -1
  64. package/dist/internal/input.js +7 -0
  65. package/dist/internal/input.js.map +1 -0
  66. package/dist/internal/loop.d.ts +2 -2
  67. package/dist/internal/loop.d.ts.map +1 -1
  68. package/dist/internal/loop.js +21 -56
  69. package/dist/internal/loop.js.map +1 -1
  70. package/dist/internal/skills.js +6 -1
  71. package/dist/internal/skills.js.map +1 -1
  72. package/dist/internal/specialists.js +7 -7
  73. package/dist/internal/specialists.js.map +1 -1
  74. package/dist/internal/toolkit.d.ts +6 -20
  75. package/dist/internal/toolkit.d.ts.map +1 -1
  76. package/dist/internal/toolkit.js +10 -31
  77. package/dist/internal/toolkit.js.map +1 -1
  78. package/dist/internal/tools.js +2 -21
  79. package/dist/internal/tools.js.map +1 -1
  80. package/dist/internal/turns.d.ts.map +1 -1
  81. package/dist/internal/turns.js +24 -43
  82. package/dist/internal/turns.js.map +1 -1
  83. package/package.json +3 -2
  84. package/src/Assistant.ts +75 -29
  85. package/src/AssistantActivity.ts +11 -18
  86. package/src/AssistantEngine.ts +110 -43
  87. package/src/AssistantEvent.ts +46 -74
  88. package/src/AssistantLoop.ts +7 -5
  89. package/src/Block.ts +1 -1
  90. package/src/BlockKit.ts +18 -31
  91. package/src/Compaction.ts +8 -21
  92. package/src/CurrentChat.ts +2 -1
  93. package/src/Skill.ts +34 -1
  94. package/src/Specialist.ts +4 -1
  95. package/src/Timeline.ts +861 -0
  96. package/src/ToolDiscovery.ts +5 -13
  97. package/src/ToolFailure.ts +1 -1
  98. package/src/index.ts +5 -20
  99. package/src/internal/chat.ts +8 -57
  100. package/src/internal/events.ts +43 -43
  101. package/src/internal/history.ts +36 -101
  102. package/src/internal/input.ts +3 -0
  103. package/src/internal/loop.ts +31 -101
  104. package/src/internal/skills.ts +11 -0
  105. package/src/internal/specialists.ts +6 -9
  106. package/src/internal/toolkit.ts +17 -60
  107. package/src/internal/tools.ts +2 -53
  108. package/src/internal/turns.ts +37 -79
  109. package/dist/AppEvent.d.ts +0 -111
  110. package/dist/AppEvent.d.ts.map +0 -1
  111. package/dist/AppEvent.js +0 -71
  112. package/dist/AppEvent.js.map +0 -1
  113. package/dist/ChatView.d.ts +0 -459
  114. package/dist/ChatView.d.ts.map +0 -1
  115. package/dist/ChatView.js +0 -496
  116. package/dist/ChatView.js.map +0 -1
  117. package/dist/Decision.d.ts +0 -145
  118. package/dist/Decision.d.ts.map +0 -1
  119. package/dist/Decision.js +0 -178
  120. package/dist/Decision.js.map +0 -1
  121. package/dist/DecisionId.d.ts +0 -37
  122. package/dist/DecisionId.d.ts.map +0 -1
  123. package/dist/DecisionId.js +0 -44
  124. package/dist/DecisionId.js.map +0 -1
  125. package/dist/internal/decisions.js +0 -66
  126. package/dist/internal/decisions.js.map +0 -1
  127. package/src/AppEvent.ts +0 -134
  128. package/src/ChatView.ts +0 -658
  129. package/src/Decision.ts +0 -241
  130. package/src/DecisionId.ts +0 -46
  131. package/src/internal/decisions.ts +0 -131
@@ -1,145 +0,0 @@
1
- import { AnyEntry, AssistantEvent_d_exports, DecisionOutcome, DecisionRequested, ToolResult } from "./AssistantEvent.js";
2
- import { Block, Block_d_exports } from "./Block.js";
3
- import { InputId } from "./InputId.js";
4
- import * as Schema from "effect/Schema";
5
- declare namespace Decision_d_exports {
6
- export { Answer, Props, State, answerAll, apply, block, fromEntries, kind };
7
- }
8
- /**
9
- * The kind of the decision block.
10
- *
11
- * @category utils
12
- * @since 0.1.0
13
- */
14
- export declare const kind = "decision";
15
- /**
16
- * Schema for the decision block's props, which list the decisions it asks for and, optionally,
17
- * its buttons' labels.
18
- *
19
- * @category schemas
20
- * @since 0.1.0
21
- */
22
- export declare const Props: Schema.Struct<{
23
- readonly decisionIds: Schema.$Array<Schema.String>;
24
- readonly approveLabel: Schema.optional<Schema.String>;
25
- readonly declineLabel: Schema.optional<Schema.String>;
26
- }>;
27
- /**
28
- * Represents the decision block's props.
29
- *
30
- * @category models
31
- * @since 0.1.0
32
- */
33
- export type Props = typeof Props.Type;
34
- /**
35
- * Schema for the decision block's answer, which holds an outcome for every decision the block
36
- * asks for, by id.
37
- *
38
- * @category schemas
39
- * @since 0.1.0
40
- */
41
- export declare const Answer: Schema.Struct<{
42
- readonly decisions: Schema.$Record<Schema.String, Schema.Literals<readonly ["approved", "declined"]>>;
43
- }>;
44
- /**
45
- * Represents the decision block's answer.
46
- *
47
- * @category models
48
- * @since 0.1.0
49
- */
50
- export type Answer = typeof Answer.Type;
51
- /**
52
- * Block with approve and decline buttons for the decisions waiting for the user.
53
- *
54
- * **Details**
55
- *
56
- * Put it in the assistant's `BlockKit`. An assistant with a tool that needs a decision must have
57
- * it. The client renders it like any other block, with the calls from {@link fromEntries} (their
58
- * tool and params).
59
- *
60
- * **Example** (Asking the user before placing an order)
61
- *
62
- * ```ts
63
- * import { Assistant, BlockKit, Decision } from "effect-assistant"
64
- * import * as Tool from "effect/ai/Tool"
65
- * import * as Toolkit from "effect/ai/Toolkit"
66
- * import * as Effect from "effect/Effect"
67
- * import * as Layer from "effect/Layer"
68
- * import * as Schema from "effect/Schema"
69
- *
70
- * export const Shop = Assistant.make("shop", { blocks: BlockKit.make([Decision.block]) })
71
- *
72
- * const OrderTools = Toolkit.make(
73
- * Tool.make("place_order", {
74
- * description: "Places an order.",
75
- * parameters: Schema.Struct({ sku: Schema.String, quantity: Schema.Int }),
76
- * success: Schema.Struct({ reference: Schema.String }),
77
- * needsApproval: true
78
- * })
79
- * )
80
- *
81
- * const OrderToolsLive = OrderTools.toLayer({
82
- * place_order: () => Effect.succeed({ reference: "R-1042" })
83
- * })
84
- *
85
- * // The call waits until the user answers the decision block.
86
- * const ShopLive = Shop.toLayer((turn) =>
87
- * turn.loop({ instructions: "You place orders for the team.", toolkit: OrderTools })
88
- * ).pipe(Layer.provide(OrderToolsLive))
89
- * ```
90
- *
91
- * @category constructors
92
- * @since 0.1.0
93
- */
94
- export declare const block: Block<"decision", Schema.Struct<{
95
- readonly decisionIds: Schema.$Array<Schema.String>;
96
- readonly approveLabel: Schema.optional<Schema.String>;
97
- readonly declineLabel: Schema.optional<Schema.String>;
98
- }>, Schema.Struct<{
99
- readonly decisions: Schema.$Record<Schema.String, Schema.Literals<readonly ["approved", "declined"]>>;
100
- }>>;
101
- /**
102
- * Creates an answer that gives every decision the block asks for the same outcome.
103
- *
104
- * This is what an "Approve" or "Decline" button sends.
105
- *
106
- * @category constructors
107
- * @since 0.1.0
108
- */
109
- export declare const answerAll: (props: Props, outcome: DecisionOutcome) => Answer;
110
- /**
111
- * Represents the state of a decision.
112
- *
113
- * @category models
114
- * @since 0.1.0
115
- */
116
- export interface State {
117
- readonly request: DecisionRequested;
118
- /** How the user decided, or `undefined` while the decision waits. */
119
- readonly outcome: DecisionOutcome | undefined;
120
- /** The id of the answer that decided it. */
121
- readonly answer: InputId | undefined;
122
- /** Whether its `DecisionResolved` is stored. A workflow's decision has been passed on by then. */
123
- readonly resolved: boolean;
124
- /** The approved call's result, once the call has run. */
125
- readonly result: ToolResult | undefined;
126
- }
127
- /**
128
- * Returns the decision states after one more event.
129
- *
130
- * @category utils
131
- * @since 0.1.0
132
- */
133
- export declare const apply: (states: ReadonlyMap<string, State>, event: {
134
- readonly _tag: string;
135
- }) => ReadonlyMap<string, State>;
136
- /**
137
- * Returns every decision in the log and where it stands, by id.
138
- *
139
- * @category utils
140
- * @since 0.1.0
141
- */
142
- export declare const fromEntries: (entries: ReadonlyArray<AnyEntry>) => ReadonlyMap<string, State>;
143
- //#endregion
144
- export { Decision_d_exports };
145
- //# sourceMappingURL=Decision.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Decision.d.ts","names":[],"sources":["../src/Decision.ts"],"mappings":";;;;;;;;;;;;;qBAyBa;;;;;;;;qBASA,OAAK,OAAA;;;;;;;;;;;YAqBN,eAAe,MAAM;;;;;;;;qBASpB,QAAM,OAAA;;;;;;;;;YAUP,gBAAgB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA6CtB,OAAK,kBAAA,OAAA;;;;;;;;;;;;;;;qBAeL,YAAS,OAAW,OAAK,SAAW,oBAAiC;;;;;;;iBAUjE;WACN,SAAS;;WAET,SAAS;;WAET,QAAQ;;WAER;;WAEA,QAAQ;;;;;;;;qBAWN,QAAK,QACR,oBAAoB,QAAM;WAChB;MACjB,oBAAoB;;;;;;;qBAmEV,cAAW,SAAa,cAAc,cAA2B,oBAAoB"}
package/dist/Decision.js DELETED
@@ -1,178 +0,0 @@
1
- import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
- import { fromCallId } from "./DecisionId.js";
3
- import { DecisionOutcome, isLibraryEvent } from "./AssistantEvent.js";
4
- import { make } from "./Block.js";
5
- import * as Predicate from "effect/Predicate";
6
- import * as Schema from "effect/Schema";
7
- import * as Option from "effect/Option";
8
- //#region src/Decision.ts
9
- /**
10
- * Lets the user approve or decline a tool call the assistant can't make on its own, such as
11
- * placing an order or publishing a post.
12
- *
13
- * When the model calls a tool marked with Effect's `needsApproval`, the call is parked instead of
14
- * run. The model asks the user with the decision {@link block}, and the user's answer to that
15
- * block runs the call or declines it. {@link fromEntries} computes where every decision in a
16
- * chat's log stands.
17
- *
18
- * @since 0.1.0
19
- */
20
- var Decision_exports = /* @__PURE__ */ __exportAll({
21
- Answer: () => Answer,
22
- Props: () => Props,
23
- answerAll: () => answerAll,
24
- apply: () => apply,
25
- block: () => block,
26
- fromEntries: () => fromEntries,
27
- kind: () => kind
28
- });
29
- /**
30
- * The kind of the decision block.
31
- *
32
- * @category utils
33
- * @since 0.1.0
34
- */
35
- const kind = "decision";
36
- /**
37
- * Schema for the decision block's props, which list the decisions it asks for and, optionally,
38
- * its buttons' labels.
39
- *
40
- * @category schemas
41
- * @since 0.1.0
42
- */
43
- const Props = Schema.Struct({
44
- decisionIds: Schema.Array(Schema.String).check(Schema.isMinLength(1)).annotate({ description: "The decisions to ask for: each waiting call's decisionId. Several go in one block when the user decides them together." }),
45
- approveLabel: Schema.optional(Schema.String).annotate({ description: "The approve button, like \"Place order\"." }),
46
- declineLabel: Schema.optional(Schema.String).annotate({ description: "The decline button, like \"Cancel\"." })
47
- });
48
- /**
49
- * Schema for the decision block's answer, which holds an outcome for every decision the block
50
- * asks for, by id.
51
- *
52
- * @category schemas
53
- * @since 0.1.0
54
- */
55
- const Answer = Schema.Struct({ decisions: Schema.Record(Schema.String, DecisionOutcome) });
56
- /**
57
- * Block with approve and decline buttons for the decisions waiting for the user.
58
- *
59
- * **Details**
60
- *
61
- * Put it in the assistant's `BlockKit`. An assistant with a tool that needs a decision must have
62
- * it. The client renders it like any other block, with the calls from {@link fromEntries} (their
63
- * tool and params).
64
- *
65
- * **Example** (Asking the user before placing an order)
66
- *
67
- * ```ts
68
- * import { Assistant, BlockKit, Decision } from "effect-assistant"
69
- * import * as Tool from "effect/ai/Tool"
70
- * import * as Toolkit from "effect/ai/Toolkit"
71
- * import * as Effect from "effect/Effect"
72
- * import * as Layer from "effect/Layer"
73
- * import * as Schema from "effect/Schema"
74
- *
75
- * export const Shop = Assistant.make("shop", { blocks: BlockKit.make([Decision.block]) })
76
- *
77
- * const OrderTools = Toolkit.make(
78
- * Tool.make("place_order", {
79
- * description: "Places an order.",
80
- * parameters: Schema.Struct({ sku: Schema.String, quantity: Schema.Int }),
81
- * success: Schema.Struct({ reference: Schema.String }),
82
- * needsApproval: true
83
- * })
84
- * )
85
- *
86
- * const OrderToolsLive = OrderTools.toLayer({
87
- * place_order: () => Effect.succeed({ reference: "R-1042" })
88
- * })
89
- *
90
- * // The call waits until the user answers the decision block.
91
- * const ShopLive = Shop.toLayer((turn) =>
92
- * turn.loop({ instructions: "You place orders for the team.", toolkit: OrderTools })
93
- * ).pipe(Layer.provide(OrderToolsLive))
94
- * ```
95
- *
96
- * @category constructors
97
- * @since 0.1.0
98
- */
99
- const block = make(kind, {
100
- description: "Approve / decline buttons for decisions waiting for the user: a call of yours that waits for their decision. The only way such a decision is made: write what they decide on (the call's key facts), and put the decision ids in decisionIds.",
101
- props: Props,
102
- answer: Answer
103
- });
104
- /**
105
- * Creates an answer that gives every decision the block asks for the same outcome.
106
- *
107
- * This is what an "Approve" or "Decline" button sends.
108
- *
109
- * @category constructors
110
- * @since 0.1.0
111
- */
112
- const answerAll = (props, outcome) => ({ decisions: Object.fromEntries(props.decisionIds.map((id) => [id, outcome])) });
113
- const decodeAnswer = Schema.decodeUnknownOption(Answer);
114
- /**
115
- * Returns the decision states after one more event.
116
- *
117
- * @category utils
118
- * @since 0.1.0
119
- */
120
- const apply = (states, event) => {
121
- if (!isLibraryEvent(event)) return states;
122
- const update = (id, f) => {
123
- const state = states.get(id);
124
- return state === void 0 ? states : new Map(states).set(id, f(state));
125
- };
126
- if (Predicate.isTagged(event, "DecisionRequested")) return states.has(event.id) ? states : new Map(states).set(event.id, {
127
- request: event,
128
- outcome: void 0,
129
- answer: void 0,
130
- resolved: false,
131
- result: void 0
132
- });
133
- if (Predicate.isTagged(event, "DecisionResolved")) return update(event.id, (state) => ({
134
- ...state,
135
- outcome: event.outcome,
136
- answer: event.answer,
137
- resolved: true
138
- }));
139
- if (Predicate.isTagged(event, "BlockAnswer") && event.kind === "decision") return Option.match(decodeAnswer(event.value), {
140
- onNone: () => states,
141
- onSome: ({ decisions }) => {
142
- const next = new Map(states);
143
- for (const [id, outcome] of Object.entries(decisions)) {
144
- const state = states.get(id);
145
- if (state !== void 0 && state.outcome === void 0) next.set(id, {
146
- ...state,
147
- outcome,
148
- answer: event.id
149
- });
150
- }
151
- return next;
152
- }
153
- });
154
- if (Predicate.isTagged(event, "ToolResult")) {
155
- const id = fromCallId(event.callId);
156
- const state = states.get(id);
157
- return state !== void 0 && Predicate.isTagged(state.request.origin, "Call") && state.outcome === "approved" ? update(id, (current) => ({
158
- ...current,
159
- result: event
160
- })) : states;
161
- }
162
- return states;
163
- };
164
- /**
165
- * Returns every decision in the log and where it stands, by id.
166
- *
167
- * @category utils
168
- * @since 0.1.0
169
- */
170
- const fromEntries = (entries) => {
171
- let all = /* @__PURE__ */ new Map();
172
- for (const entry of entries) all = apply(all, entry.event);
173
- return all;
174
- };
175
- //#endregion
176
- export { Answer, Decision_exports, Props, answerAll, apply, block, fromEntries, kind };
177
-
178
- //# sourceMappingURL=Decision.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Decision.js","names":["AssistantEvent.DecisionOutcome","Block.make","AssistantEvent.isLibraryEvent","DecisionId.fromCallId"],"sources":["../src/Decision.ts"],"sourcesContent":["/**\n * Lets the user approve or decline a tool call the assistant can't make on its own, such as\n * placing an order or publishing a post.\n *\n * When the model calls a tool marked with Effect's `needsApproval`, the call is parked instead of\n * run. The model asks the user with the decision {@link block}, and the user's answer to that\n * block runs the call or declines it. {@link fromEntries} computes where every decision in a\n * chat's log stands.\n *\n * @since 0.1.0\n */\nimport * as Option from \"effect/Option\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport * as AssistantEvent from \"./AssistantEvent.ts\"\nimport * as Block from \"./Block.ts\"\nimport * as DecisionId from \"./DecisionId.ts\"\nimport type { InputId } from \"./InputId.ts\"\n\n/**\n * The kind of the decision block.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const kind = \"decision\"\n\n/**\n * Schema for the decision block's props, which list the decisions it asks for and, optionally,\n * its buttons' labels.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const Props = Schema.Struct({\n // Plain strings: a strict tool schema with the id's pattern is too much for some providers; the\n // ids are checked against the decisions waiting when the message is sent.\n decisionIds: Schema.Array(Schema.String).check(Schema.isMinLength(1)).annotate({\n description:\n \"The decisions to ask for: each waiting call's decisionId. Several go in one block when the user decides them together.\"\n }),\n approveLabel: Schema.optional(Schema.String).annotate({\n description: 'The approve button, like \"Place order\".'\n }),\n declineLabel: Schema.optional(Schema.String).annotate({\n description: 'The decline button, like \"Cancel\".'\n })\n})\n\n/**\n * Represents the decision block's props.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Props = typeof Props.Type\n\n/**\n * Schema for the decision block's answer, which holds an outcome for every decision the block\n * asks for, by id.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const Answer = Schema.Struct({\n decisions: Schema.Record(Schema.String, AssistantEvent.DecisionOutcome)\n})\n\n/**\n * Represents the decision block's answer.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Answer = typeof Answer.Type\n\n/**\n * Block with approve and decline buttons for the decisions waiting for the user.\n *\n * **Details**\n *\n * Put it in the assistant's `BlockKit`. An assistant with a tool that needs a decision must have\n * it. The client renders it like any other block, with the calls from {@link fromEntries} (their\n * tool and params).\n *\n * **Example** (Asking the user before placing an order)\n *\n * ```ts\n * import { Assistant, BlockKit, Decision } from \"effect-assistant\"\n * import * as Tool from \"effect/ai/Tool\"\n * import * as Toolkit from \"effect/ai/Toolkit\"\n * import * as Effect from \"effect/Effect\"\n * import * as Layer from \"effect/Layer\"\n * import * as Schema from \"effect/Schema\"\n *\n * export const Shop = Assistant.make(\"shop\", { blocks: BlockKit.make([Decision.block]) })\n *\n * const OrderTools = Toolkit.make(\n * Tool.make(\"place_order\", {\n * description: \"Places an order.\",\n * parameters: Schema.Struct({ sku: Schema.String, quantity: Schema.Int }),\n * success: Schema.Struct({ reference: Schema.String }),\n * needsApproval: true\n * })\n * )\n *\n * const OrderToolsLive = OrderTools.toLayer({\n * place_order: () => Effect.succeed({ reference: \"R-1042\" })\n * })\n *\n * // The call waits until the user answers the decision block.\n * const ShopLive = Shop.toLayer((turn) =>\n * turn.loop({ instructions: \"You place orders for the team.\", toolkit: OrderTools })\n * ).pipe(Layer.provide(OrderToolsLive))\n * ```\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const block = Block.make(kind, {\n description:\n \"Approve / decline buttons for decisions waiting for the user: a call of yours that waits for their decision. The only way such a decision is made: write what they decide on (the call's key facts), and put the decision ids in decisionIds.\",\n props: Props,\n answer: Answer\n})\n\n/**\n * Creates an answer that gives every decision the block asks for the same outcome.\n *\n * This is what an \"Approve\" or \"Decline\" button sends.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const answerAll = (props: Props, outcome: AssistantEvent.DecisionOutcome): Answer => ({\n decisions: Object.fromEntries(props.decisionIds.map((id) => [id, outcome]))\n})\n\n/**\n * Represents the state of a decision.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface State {\n readonly request: AssistantEvent.DecisionRequested\n /** How the user decided, or `undefined` while the decision waits. */\n readonly outcome: AssistantEvent.DecisionOutcome | undefined\n /** The id of the answer that decided it. */\n readonly answer: InputId | undefined\n /** Whether its `DecisionResolved` is stored. A workflow's decision has been passed on by then. */\n readonly resolved: boolean\n /** The approved call's result, once the call has run. */\n readonly result: AssistantEvent.ToolResult | undefined\n}\n\nconst decodeAnswer = Schema.decodeUnknownOption(Answer)\n\n/**\n * Returns the decision states after one more event.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const apply = (\n states: ReadonlyMap<string, State>,\n event: { readonly _tag: string }\n): ReadonlyMap<string, State> => {\n if (!AssistantEvent.isLibraryEvent(event)) return states\n\n const update = (id: string, f: (state: State) => State) => {\n const state = states.get(id)\n\n return state === undefined ? states : new Map(states).set(id, f(state))\n }\n\n if (Predicate.isTagged(event, \"DecisionRequested\")) {\n return states.has(event.id)\n ? states\n : new Map(states).set(event.id, {\n request: event,\n outcome: undefined,\n answer: undefined,\n resolved: false,\n result: undefined\n })\n }\n\n if (Predicate.isTagged(event, \"DecisionResolved\")) {\n return update(event.id, (state) => ({\n ...state,\n outcome: event.outcome,\n answer: event.answer,\n resolved: true\n }))\n }\n\n // A stored decision answer was checked against its block when it was submitted: the first one\n // for a decision decides it.\n if (Predicate.isTagged(event, \"BlockAnswer\") && event.kind === kind) {\n return Option.match(decodeAnswer(event.value), {\n onNone: () => states,\n onSome: ({ decisions }) => {\n const next = new Map(states)\n\n for (const [id, outcome] of Object.entries(decisions)) {\n const state = states.get(id)\n\n if (state !== undefined && state.outcome === undefined) next.set(id, { ...state, outcome, answer: event.id })\n }\n\n return next\n }\n })\n }\n\n if (Predicate.isTagged(event, \"ToolResult\")) {\n const id = DecisionId.fromCallId(event.callId)\n const state = states.get(id)\n\n return state !== undefined && Predicate.isTagged(state.request.origin, \"Call\") && state.outcome === \"approved\"\n ? update(id, (current) => ({ ...current, result: event }))\n : states\n }\n\n return states\n}\n\n/**\n * Returns every decision in the log and where it stands, by id.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const fromEntries = (entries: ReadonlyArray<AssistantEvent.AnyEntry>): ReadonlyMap<string, State> => {\n let all: ReadonlyMap<string, State> = new Map()\n\n for (const entry of entries) all = apply(all, entry.event)\n\n return all\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyBA,MAAa,OAAO;;;;;;;;AASpB,MAAa,QAAQ,OAAO,OAAO;CAGjC,aAAa,OAAO,MAAM,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,EAC7E,aACE,yHACJ,CAAC;CACD,cAAc,OAAO,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,EACpD,aAAa,4CACf,CAAC;CACD,cAAc,OAAO,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,EACpD,aAAa,uCACf,CAAC;AACH,CAAC;;;;;;;;AAiBD,MAAa,SAAS,OAAO,OAAO,EAClC,WAAW,OAAO,OAAO,OAAO,QAAQA,eAA8B,EACxE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqDD,MAAa,QAAQC,KAAW,MAAM;CACpC,aACE;CACF,OAAO;CACP,QAAQ;AACV,CAAC;;;;;;;;;AAUD,MAAa,aAAa,OAAc,aAAqD,EAC3F,WAAW,OAAO,YAAY,MAAM,YAAY,KAAK,OAAO,CAAC,IAAI,OAAO,CAAC,CAAC,EAC5E;AAoBA,MAAM,eAAe,OAAO,oBAAoB,MAAM;;;;;;;AAQtD,MAAa,SACX,QACA,UAC+B;CAC/B,IAAI,CAACC,eAA8B,KAAK,GAAG,OAAO;CAElD,MAAM,UAAU,IAAY,MAA+B;EACzD,MAAM,QAAQ,OAAO,IAAI,EAAE;EAE3B,OAAO,UAAU,KAAA,IAAY,SAAS,IAAI,IAAI,MAAM,CAAC,CAAC,IAAI,IAAI,EAAE,KAAK,CAAC;CACxE;CAEA,IAAI,UAAU,SAAS,OAAO,mBAAmB,GAC/C,OAAO,OAAO,IAAI,MAAM,EAAE,IACtB,SACA,IAAI,IAAI,MAAM,CAAC,CAAC,IAAI,MAAM,IAAI;EAC5B,SAAS;EACT,SAAS,KAAA;EACT,QAAQ,KAAA;EACR,UAAU;EACV,QAAQ,KAAA;CACV,CAAC;CAGP,IAAI,UAAU,SAAS,OAAO,kBAAkB,GAC9C,OAAO,OAAO,MAAM,KAAK,WAAW;EAClC,GAAG;EACH,SAAS,MAAM;EACf,QAAQ,MAAM;EACd,UAAU;CACZ,EAAE;CAKJ,IAAI,UAAU,SAAS,OAAO,aAAa,KAAK,MAAM,SAAA,YACpD,OAAO,OAAO,MAAM,aAAa,MAAM,KAAK,GAAG;EAC7C,cAAc;EACd,SAAS,EAAE,gBAAgB;GACzB,MAAM,OAAO,IAAI,IAAI,MAAM;GAE3B,KAAK,MAAM,CAAC,IAAI,YAAY,OAAO,QAAQ,SAAS,GAAG;IACrD,MAAM,QAAQ,OAAO,IAAI,EAAE;IAE3B,IAAI,UAAU,KAAA,KAAa,MAAM,YAAY,KAAA,GAAW,KAAK,IAAI,IAAI;KAAE,GAAG;KAAO;KAAS,QAAQ,MAAM;IAAG,CAAC;GAC9G;GAEA,OAAO;EACT;CACF,CAAC;CAGH,IAAI,UAAU,SAAS,OAAO,YAAY,GAAG;EAC3C,MAAM,KAAKC,WAAsB,MAAM,MAAM;EAC7C,MAAM,QAAQ,OAAO,IAAI,EAAE;EAE3B,OAAO,UAAU,KAAA,KAAa,UAAU,SAAS,MAAM,QAAQ,QAAQ,MAAM,KAAK,MAAM,YAAY,aAChG,OAAO,KAAK,aAAa;GAAE,GAAG;GAAS,QAAQ;EAAM,EAAE,IACvD;CACN;CAEA,OAAO;AACT;;;;;;;AAQA,MAAa,eAAe,YAAgF;CAC1G,IAAI,sBAAkC,IAAI,IAAI;CAE9C,KAAK,MAAM,SAAS,SAAS,MAAM,MAAM,KAAK,MAAM,KAAK;CAEzD,OAAO;AACT"}
@@ -1,37 +0,0 @@
1
- import * as Schema from "effect/Schema";
2
- declare namespace DecisionId_d_exports {
3
- export { DecisionId, fromCallId, fromKey };
4
- }
5
- /**
6
- * Schema for decision ids of the form `` `decision:${uuid}` ``, branded.
7
- *
8
- * @category schemas
9
- * @since 0.1.0
10
- */
11
- export declare const DecisionId: Schema.brand<Schema.TemplateLiteral<readonly ["decision:", Schema.String]>, "~effect-assistant/DecisionId">;
12
- /**
13
- * Represents a decision id.
14
- *
15
- * @category models
16
- * @since 0.1.0
17
- */
18
- export type DecisionId = typeof DecisionId.Type;
19
- /**
20
- * Creates the decision id for a key. The same key always gives the same id, so a decision that is
21
- * requested again is stored only once.
22
- *
23
- * @category constructors
24
- * @since 0.1.0
25
- */
26
- export declare const fromKey: (key: string) => DecisionId;
27
- /**
28
- * Returns the decision id for a tool call that waits for the user's decision, derived from the
29
- * call's id.
30
- *
31
- * @category constructors
32
- * @since 0.1.0
33
- */
34
- export declare const fromCallId: (callId: string) => DecisionId;
35
- //#endregion
36
- export { DecisionId_d_exports };
37
- //# sourceMappingURL=DecisionId.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DecisionId.d.ts","names":[],"sources":["../src/DecisionId.ts"],"mappings":";;;;;;;;;;qBAiBa,YAAU,OAAA,MAAA,OAAA,uCAAA,OAAA;;;;;;;YAUX,oBAAoB,WAAW;;;;;;;;qBAS9B,UAAO,gBAAkB;;;;;;;;qBASzB,aAAU,mBAAqB"}
@@ -1,44 +0,0 @@
1
- import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
- import { Uuid, fromKey as fromKey$1 } from "./internal/uuid.js";
3
- import * as Schema from "effect/Schema";
4
- //#region src/DecisionId.ts
5
- /**
6
- * This module provides the id of a decision the user is asked to make, which is `decision:`
7
- * followed by a UUID.
8
- *
9
- * The model passes the id to a decision block, and the user's answer refers to it.
10
- *
11
- * @since 0.1.0
12
- */
13
- var DecisionId_exports = /* @__PURE__ */ __exportAll({
14
- DecisionId: () => DecisionId,
15
- fromCallId: () => fromCallId,
16
- fromKey: () => fromKey
17
- });
18
- /**
19
- * Schema for decision ids of the form `` `decision:${uuid}` ``, branded.
20
- *
21
- * @category schemas
22
- * @since 0.1.0
23
- */
24
- const DecisionId = Schema.TemplateLiteral(["decision:", Uuid]).pipe(Schema.brand("~effect-assistant/DecisionId"));
25
- /**
26
- * Creates the decision id for a key. The same key always gives the same id, so a decision that is
27
- * requested again is stored only once.
28
- *
29
- * @category constructors
30
- * @since 0.1.0
31
- */
32
- const fromKey = (key) => DecisionId.make(`decision:${fromKey$1(key)}`);
33
- /**
34
- * Returns the decision id for a tool call that waits for the user's decision, derived from the
35
- * call's id.
36
- *
37
- * @category constructors
38
- * @since 0.1.0
39
- */
40
- const fromCallId = (callId) => fromKey(`tool-call:${callId}`);
41
- //#endregion
42
- export { DecisionId, DecisionId_exports, fromCallId, fromKey };
43
-
44
- //# sourceMappingURL=DecisionId.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DecisionId.js","names":["Uuid.Uuid","Uuid.fromKey"],"sources":["../src/DecisionId.ts"],"sourcesContent":["/**\n * This module provides the id of a decision the user is asked to make, which is `decision:`\n * followed by a UUID.\n *\n * The model passes the id to a decision block, and the user's answer refers to it.\n *\n * @since 0.1.0\n */\nimport * as Schema from \"effect/Schema\"\nimport * as Uuid from \"./internal/uuid.ts\"\n\n/**\n * Schema for decision ids of the form `` `decision:${uuid}` ``, branded.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const DecisionId = Schema.TemplateLiteral([\"decision:\", Uuid.Uuid]).pipe(\n Schema.brand(\"~effect-assistant/DecisionId\")\n)\n\n/**\n * Represents a decision id.\n *\n * @category models\n * @since 0.1.0\n */\nexport type DecisionId = typeof DecisionId.Type\n\n/**\n * Creates the decision id for a key. The same key always gives the same id, so a decision that is\n * requested again is stored only once.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const fromKey = (key: string): DecisionId => DecisionId.make(`decision:${Uuid.fromKey(key)}`)\n\n/**\n * Returns the decision id for a tool call that waits for the user's decision, derived from the\n * call's id.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const fromCallId = (callId: string): DecisionId => fromKey(`tool-call:${callId}`)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAiBA,MAAa,aAAa,OAAO,gBAAgB,CAAC,aAAaA,IAAS,CAAC,CAAC,CAAC,KACzE,OAAO,MAAM,8BAA8B,CAC7C;;;;;;;;AAiBA,MAAa,WAAW,QAA4B,WAAW,KAAK,YAAYC,UAAa,GAAG,GAAG;;;;;;;;AASnG,MAAa,cAAc,WAA+B,QAAQ,aAAa,QAAQ"}
@@ -1,66 +0,0 @@
1
- import { isLibraryEvent } from "../AssistantEvent.js";
2
- import { Answer, Props, fromEntries, kind } from "../Decision.js";
3
- import { fromEntries as fromEntries$1 } from "../BlockKit.js";
4
- import * as Predicate from "effect/Predicate";
5
- import * as Context from "effect/Context";
6
- import * as Schema from "effect/Schema";
7
- import * as Data from "effect/Data";
8
- import * as Option from "effect/Option";
9
- import * as Response from "effect/ai/Response";
10
- //#region src/internal/decisions.ts
11
- /** @internal */
12
- const TurnDecisions = Context.Reference("effect-assistant/TurnDecisions", { defaultValue: Option.none });
13
- const Verdicts = Data.taggedEnum();
14
- const store = Verdicts.Store();
15
- const refuse = (reason) => Verdicts.Refuse({ reason });
16
- const decodeProps = Schema.decodeUnknownOption(Props);
17
- const decodeAnswer = Schema.decodeUnknownOption(Answer);
18
- const messageOf = (entries, id) => entries.map(({ event }) => event).find((event) => isLibraryEvent(event) && Predicate.isTagged(event, "AssistantMessage") && event.id === id);
19
- const answerVerdict = (entries, answer) => {
20
- const message = messageOf(entries, answer.messageId);
21
- const onDecisionBlock = message?.block?.kind === kind;
22
- if (!onDecisionBlock && answer.kind !== "decision") return store;
23
- if (message?.block === void 0 || !onDecisionBlock || answer.kind !== "decision") return refuse(`${answer.messageId} has no decision block.`);
24
- if (fromEntries$1(entries).get(message.id)?.open !== true) return refuse(`The block on ${message.id} is closed.`);
25
- const props = decodeProps(message.block.props);
26
- const value = decodeAnswer(answer.value);
27
- if (Option.isNone(props) || Option.isNone(value)) return refuse(`That isn't an answer to the block on ${message.id}.`);
28
- const asked = props.value.decisionIds;
29
- const given = Object.keys(value.value.decisions);
30
- if (given.length !== asked.length || !given.every((id) => asked.some((askedId) => askedId === id))) return refuse(`An answer decides exactly the decisions its block asks for: ${asked.join(", ")}.`);
31
- const states = fromEntries(entries);
32
- const decided = [];
33
- for (const id of asked) {
34
- const state = states.get(id);
35
- const outcome = value.value.decisions[id];
36
- if (state === void 0 || outcome === void 0) return refuse(`No decision ${id}.`);
37
- if (state.outcome !== void 0) return refuse(`${id} is already decided.`);
38
- decided.push({
39
- request: state.request,
40
- outcome
41
- });
42
- }
43
- return Verdicts.Decide({
44
- decided,
45
- answer: answer.id
46
- });
47
- };
48
- /** @internal */
49
- const verdict = (entries, input) => isLibraryEvent(input) && Predicate.isTagged(input, "BlockAnswer") ? answerVerdict(entries, input) : store;
50
- /** @internal */
51
- const unresolved = (entries) => [...fromEntries(entries).values()].flatMap((state) => state.outcome !== void 0 && state.answer !== void 0 && !state.resolved ? [{
52
- request: state.request,
53
- outcome: state.outcome,
54
- answer: state.answer
55
- }] : []);
56
- /** @internal */
57
- const approvedCalls = (entries) => [...fromEntries(entries).values()].flatMap(({ request, outcome, resolved, result }) => resolved && outcome === "approved" && result === void 0 ? [Response.makePart("tool-call", {
58
- id: request.origin.callId,
59
- name: request.origin.tool,
60
- params: request.origin.params,
61
- providerExecuted: false
62
- })] : []);
63
- //#endregion
64
- export { TurnDecisions, approvedCalls, unresolved, verdict };
65
-
66
- //# sourceMappingURL=decisions.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"decisions.js","names":["Decision.Props","Decision.Answer","AssistantEvent.isLibraryEvent","Decision.kind","BlockKit.fromEntries","Decision.fromEntries"],"sources":["../../src/internal/decisions.ts"],"sourcesContent":["import * as Response from \"effect/ai/Response\"\nimport * as Context from \"effect/Context\"\nimport * as Data from \"effect/Data\"\nimport type * as Effect from \"effect/Effect\"\nimport * as Option from \"effect/Option\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport * as AssistantEvent from \"../AssistantEvent.ts\"\nimport * as BlockKit from \"../BlockKit.ts\"\nimport * as Decision from \"../Decision.ts\"\nimport type { InputId } from \"../InputId.ts\"\n\n// Only a turn's loop parks calls and runs approved ones. A turn's specialists inherit its context, so their runs set\n// it back to none.\n/** @internal */\nexport const TurnDecisions = Context.Reference<\n Option.Option<{\n readonly approved: Effect.Effect<ReadonlyArray<AssistantEvent.ToolCallPart>>\n }>\n>(\"effect-assistant/TurnDecisions\", { defaultValue: Option.none })\n\n/** @internal */\nexport interface Decided {\n readonly request: AssistantEvent.DecisionRequested\n readonly outcome: AssistantEvent.DecisionOutcome\n}\n\n/** @internal */\nexport type Verdict = Data.TaggedEnum<{\n Store: Record<never, never>\n Refuse: { readonly reason: string }\n Decide: { readonly decided: ReadonlyArray<Decided>; readonly answer: InputId }\n}>\n\nconst Verdicts = Data.taggedEnum<Verdict>()\n\nconst store = Verdicts.Store()\n\nconst refuse = (reason: string) => Verdicts.Refuse({ reason })\n\nconst decodeProps = Schema.decodeUnknownOption(Decision.Props)\n\nconst decodeAnswer = Schema.decodeUnknownOption(Decision.Answer)\n\nconst messageOf = (entries: ReadonlyArray<AssistantEvent.AnyEntry>, id: string) =>\n entries\n .map(({ event }) => event)\n .find(\n (event): event is AssistantEvent.AssistantMessage =>\n AssistantEvent.isLibraryEvent(event) && Predicate.isTagged(event, \"AssistantMessage\") && event.id === id\n )\n\nconst answerVerdict = (entries: ReadonlyArray<AssistantEvent.AnyEntry>, answer: AssistantEvent.BlockAnswer) => {\n const message = messageOf(entries, answer.messageId)\n const onDecisionBlock = message?.block?.kind === Decision.kind\n\n if (!onDecisionBlock && answer.kind !== Decision.kind) return store\n\n if (message?.block === undefined || !onDecisionBlock || answer.kind !== Decision.kind) {\n return refuse(`${answer.messageId} has no decision block.`)\n }\n\n if (BlockKit.fromEntries(entries).get(message.id)?.open !== true)\n return refuse(`The block on ${message.id} is closed.`)\n\n const props = decodeProps(message.block.props)\n const value = decodeAnswer(answer.value)\n\n if (Option.isNone(props) || Option.isNone(value)) return refuse(`That isn't an answer to the block on ${message.id}.`)\n\n const asked = props.value.decisionIds\n const given = Object.keys(value.value.decisions)\n\n if (given.length !== asked.length || !given.every((id) => asked.some((askedId) => askedId === id))) {\n return refuse(`An answer decides exactly the decisions its block asks for: ${asked.join(\", \")}.`)\n }\n\n const states = Decision.fromEntries(entries)\n const decided: Array<Decided> = []\n\n for (const id of asked) {\n const state = states.get(id)\n const outcome = value.value.decisions[id]\n\n if (state === undefined || outcome === undefined) return refuse(`No decision ${id}.`)\n\n if (state.outcome !== undefined) return refuse(`${id} is already decided.`)\n\n decided.push({ request: state.request, outcome })\n }\n\n return Verdicts.Decide({ decided, answer: answer.id })\n}\n\n/** @internal */\nexport const verdict = (\n entries: ReadonlyArray<AssistantEvent.AnyEntry>,\n input: AssistantEvent.Input | AssistantEvent.StoredAppEvent\n): Verdict =>\n AssistantEvent.isLibraryEvent(input) && Predicate.isTagged(input, \"BlockAnswer\")\n ? answerVerdict(entries, input)\n : store\n\n// A restart can cut the chat off between storing an answer and resolving what it decided.\n/** @internal */\nexport const unresolved = (\n entries: ReadonlyArray<AssistantEvent.AnyEntry>\n): ReadonlyArray<Decided & { readonly answer: InputId }> =>\n [...Decision.fromEntries(entries).values()].flatMap((state) =>\n state.outcome !== undefined && state.answer !== undefined && !state.resolved\n ? [{ request: state.request, outcome: state.outcome, answer: state.answer }]\n : []\n )\n\n// They run with the ids and params the model gave them, before the model's next step.\n/** @internal */\nexport const approvedCalls = (\n entries: ReadonlyArray<AssistantEvent.AnyEntry>\n): ReadonlyArray<AssistantEvent.ToolCallPart> =>\n [...Decision.fromEntries(entries).values()].flatMap(({ request, outcome, resolved, result }) =>\n resolved && outcome === \"approved\" && result === undefined\n ? [\n Response.makePart(\"tool-call\", {\n id: request.origin.callId,\n name: request.origin.tool,\n params: request.origin.params,\n providerExecuted: false\n })\n ]\n : []\n )\n"],"mappings":";;;;;;;;;;;AAeA,MAAa,gBAAgB,QAAQ,UAInC,kCAAkC,EAAE,cAAc,OAAO,KAAK,CAAC;AAejE,MAAM,WAAW,KAAK,WAAoB;AAE1C,MAAM,QAAQ,SAAS,MAAM;AAE7B,MAAM,UAAU,WAAmB,SAAS,OAAO,EAAE,OAAO,CAAC;AAE7D,MAAM,cAAc,OAAO,oBAAoBA,KAAc;AAE7D,MAAM,eAAe,OAAO,oBAAoBC,MAAe;AAE/D,MAAM,aAAa,SAAiD,OAClE,QACG,KAAK,EAAE,YAAY,KAAK,CAAC,CACzB,MACE,UACCC,eAA8B,KAAK,KAAK,UAAU,SAAS,OAAO,kBAAkB,KAAK,MAAM,OAAO,EAC1G;AAEJ,MAAM,iBAAiB,SAAiD,WAAuC;CAC7G,MAAM,UAAU,UAAU,SAAS,OAAO,SAAS;CACnD,MAAM,kBAAkB,SAAS,OAAO,SAASC;CAEjD,IAAI,CAAC,mBAAmB,OAAO,SAAS,YAAe,OAAO;CAE9D,IAAI,SAAS,UAAU,KAAA,KAAa,CAAC,mBAAmB,OAAO,SAAS,YACtE,OAAO,OAAO,GAAG,OAAO,UAAU,wBAAwB;CAG5D,IAAIC,cAAqB,OAAO,CAAC,CAAC,IAAI,QAAQ,EAAE,CAAC,EAAE,SAAS,MAC1D,OAAO,OAAO,gBAAgB,QAAQ,GAAG,YAAY;CAEvD,MAAM,QAAQ,YAAY,QAAQ,MAAM,KAAK;CAC7C,MAAM,QAAQ,aAAa,OAAO,KAAK;CAEvC,IAAI,OAAO,OAAO,KAAK,KAAK,OAAO,OAAO,KAAK,GAAG,OAAO,OAAO,wCAAwC,QAAQ,GAAG,EAAE;CAErH,MAAM,QAAQ,MAAM,MAAM;CAC1B,MAAM,QAAQ,OAAO,KAAK,MAAM,MAAM,SAAS;CAE/C,IAAI,MAAM,WAAW,MAAM,UAAU,CAAC,MAAM,OAAO,OAAO,MAAM,MAAM,YAAY,YAAY,EAAE,CAAC,GAC/F,OAAO,OAAO,+DAA+D,MAAM,KAAK,IAAI,EAAE,EAAE;CAGlG,MAAM,SAASC,YAAqB,OAAO;CAC3C,MAAM,UAA0B,CAAC;CAEjC,KAAK,MAAM,MAAM,OAAO;EACtB,MAAM,QAAQ,OAAO,IAAI,EAAE;EAC3B,MAAM,UAAU,MAAM,MAAM,UAAU;EAEtC,IAAI,UAAU,KAAA,KAAa,YAAY,KAAA,GAAW,OAAO,OAAO,eAAe,GAAG,EAAE;EAEpF,IAAI,MAAM,YAAY,KAAA,GAAW,OAAO,OAAO,GAAG,GAAG,qBAAqB;EAE1E,QAAQ,KAAK;GAAE,SAAS,MAAM;GAAS;EAAQ,CAAC;CAClD;CAEA,OAAO,SAAS,OAAO;EAAE;EAAS,QAAQ,OAAO;CAAG,CAAC;AACvD;;AAGA,MAAa,WACX,SACA,UAEAH,eAA8B,KAAK,KAAK,UAAU,SAAS,OAAO,aAAa,IAC3E,cAAc,SAAS,KAAK,IAC5B;;AAIN,MAAa,cACX,YAEA,CAAC,GAAGG,YAAqB,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,UACnD,MAAM,YAAY,KAAA,KAAa,MAAM,WAAW,KAAA,KAAa,CAAC,MAAM,WAChE,CAAC;CAAE,SAAS,MAAM;CAAS,SAAS,MAAM;CAAS,QAAQ,MAAM;AAAO,CAAC,IACzE,CAAC,CACP;;AAIF,MAAa,iBACX,YAEA,CAAC,GAAGA,YAAqB,OAAO,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,EAAE,SAAS,SAAS,UAAU,aACjF,YAAY,YAAY,cAAc,WAAW,KAAA,IAC7C,CACE,SAAS,SAAS,aAAa;CAC7B,IAAI,QAAQ,OAAO;CACnB,MAAM,QAAQ,OAAO;CACrB,QAAQ,QAAQ,OAAO;CACvB,kBAAkB;AACpB,CAAC,CACH,IACA,CAAC,CACP"}
package/src/AppEvent.ts DELETED
@@ -1,134 +0,0 @@
1
- /**
2
- * Registers an application's own events with an assistant.
3
- *
4
- * An app event is a tagged schema for something the application reports into a chat, such as a
5
- * workflow's progress, a webhook, a summary for compaction, or the draft the user opened.
6
- * {@link make} registers one with two choices: whether storing it wakes a turn (`wakes`), and
7
- * how the model reads it (`render`).
8
- *
9
- * @since 0.1.0
10
- */
11
- import * as Predicate from "effect/Predicate"
12
- import type * as Schema from "effect/Schema"
13
- import * as SchemaAST from "effect/SchemaAST"
14
-
15
- /**
16
- * Schema for one of the application's own events.
17
- *
18
- * It is a tagged struct or class (`Schema.TaggedStruct`, `Schema.TaggedClass`) that needs no
19
- * services.
20
- *
21
- * @category models
22
- * @since 0.1.0
23
- */
24
- export type EventSchema = Schema.Codec<{ readonly _tag: string }, { readonly _tag: string }> & {
25
- readonly fields: { readonly _tag: { readonly ast: SchemaAST.AST } }
26
- }
27
-
28
- /**
29
- * Describes how the model reads an event.
30
- *
31
- * `"json"` shows the event's tag and fields as JSON. A function shows the text it returns for the
32
- * event.
33
- *
34
- * @category models
35
- * @since 0.1.0
36
- */
37
- export type Render<A> = "json" | ((event: A) => string)
38
-
39
- /**
40
- * Represents one of the application's events, registered with an assistant.
41
- *
42
- * It holds the event's schema and tag, whether storing it wakes a turn, and how the model reads
43
- * it. A `render` of `undefined` means the model doesn't read it.
44
- *
45
- * @category models
46
- * @since 0.1.0
47
- */
48
- export interface AppEvent<S extends EventSchema = EventSchema> {
49
- readonly schema: S
50
- readonly tag: string
51
- readonly wakes: boolean
52
- readonly render: Render<S["Type"]> | undefined
53
- }
54
-
55
- /**
56
- * Represents any registered event, for generic constraints.
57
- *
58
- * @category utility types
59
- * @since 0.1.0
60
- */
61
- export type Any = AppEvent<any>
62
-
63
- /**
64
- * Extracts the type of a registered event's values.
65
- *
66
- * @category utility types
67
- * @since 0.1.0
68
- */
69
- export type Type<E extends Any> = E["schema"]["Type"]
70
-
71
- const tagOf = (schema: EventSchema): string => {
72
- const ast = schema.fields._tag.ast
73
-
74
- if (SchemaAST.isLiteral(ast) && Predicate.isString(ast.literal)) return ast.literal
75
-
76
- throw new Error("An app event is a tagged struct or class.")
77
- }
78
-
79
- /**
80
- * Registers one of the application's events with an assistant.
81
- *
82
- * **Details**
83
- *
84
- * Storing the event wakes a turn only when `wakes` is `true`; it defaults to `false`. `render`
85
- * defaults to `"json"` for an event that wakes a turn. An event that doesn't wake a turn and has
86
- * no `render` isn't read by the model.
87
- *
88
- * The schema must be a tagged struct or class whose `_tag` is a string literal; `make` throws
89
- * otherwise.
90
- *
91
- * **Example** (Registering an event that wakes a turn)
92
- *
93
- * ```ts
94
- * import { AppEvent, Assistant, InputId } from "effect-assistant"
95
- * import * as Schema from "effect/Schema"
96
- *
97
- * class OrderShipped extends Schema.TaggedClass<OrderShipped>()("OrderShipped", {
98
- * id: InputId.InputId,
99
- * orderId: Schema.String,
100
- * carrier: Schema.String
101
- * }) {}
102
- *
103
- * export const MyAssistant = Assistant.make("my-assistant", {
104
- * events: [
105
- * AppEvent.make(OrderShipped, {
106
- * wakes: true,
107
- * render: (shipped) =>
108
- * `Order ${shipped.orderId} shipped with ${shipped.carrier}. Tell the user if it matters.`
109
- * })
110
- * ]
111
- * })
112
- * ```
113
- *
114
- * @category constructors
115
- * @since 0.1.0
116
- */
117
- export const make = <S extends EventSchema>(
118
- schema: S,
119
- options?: {
120
- /** Whether storing it starts a turn, like a user's message. Default false. */
121
- readonly wakes?: boolean | undefined
122
- /** How the model reads it in its history. */
123
- readonly render?: Render<S["Type"]> | undefined
124
- }
125
- ): AppEvent<S> => {
126
- const wakes = options?.wakes ?? false
127
-
128
- return {
129
- schema,
130
- tag: tagOf(schema),
131
- wakes,
132
- render: options?.render ?? (wakes ? "json" : undefined)
133
- }
134
- }