effect-assistant 0.3.0 → 0.5.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 (91) hide show
  1. package/dist/Assistant.d.ts +5 -11
  2. package/dist/Assistant.d.ts.map +1 -1
  3. package/dist/Assistant.js.map +1 -1
  4. package/dist/AssistantEvent.d.ts +66 -7
  5. package/dist/AssistantEvent.d.ts.map +1 -1
  6. package/dist/AssistantEvent.js +74 -9
  7. package/dist/AssistantEvent.js.map +1 -1
  8. package/dist/AssistantLoop.d.ts +4 -2
  9. package/dist/AssistantLoop.d.ts.map +1 -1
  10. package/dist/AssistantLoop.js +4 -2
  11. package/dist/AssistantLoop.js.map +1 -1
  12. package/dist/Block.d.ts +63 -1
  13. package/dist/Block.d.ts.map +1 -1
  14. package/dist/Block.js +63 -2
  15. package/dist/Block.js.map +1 -1
  16. package/dist/BlockKit.d.ts +25 -3
  17. package/dist/BlockKit.d.ts.map +1 -1
  18. package/dist/BlockKit.js +14 -12
  19. package/dist/BlockKit.js.map +1 -1
  20. package/dist/Compaction.d.ts +1 -1
  21. package/dist/Compaction.d.ts.map +1 -1
  22. package/dist/Compaction.js +11 -4
  23. package/dist/Compaction.js.map +1 -1
  24. package/dist/Skill.d.ts +85 -43
  25. package/dist/Skill.d.ts.map +1 -1
  26. package/dist/Skill.js +93 -44
  27. package/dist/Skill.js.map +1 -1
  28. package/dist/Specialist.d.ts +6 -9
  29. package/dist/Specialist.d.ts.map +1 -1
  30. package/dist/Specialist.js.map +1 -1
  31. package/dist/Timeline.d.ts +44 -6
  32. package/dist/Timeline.d.ts.map +1 -1
  33. package/dist/Timeline.js +87 -16
  34. package/dist/Timeline.js.map +1 -1
  35. package/dist/ToolApproval.d.ts +146 -0
  36. package/dist/ToolApproval.d.ts.map +1 -0
  37. package/dist/ToolApproval.js +201 -0
  38. package/dist/ToolApproval.js.map +1 -0
  39. package/dist/ToolDiscovery.d.ts +6 -4
  40. package/dist/ToolDiscovery.d.ts.map +1 -1
  41. package/dist/ToolDiscovery.js +5 -4
  42. package/dist/ToolDiscovery.js.map +1 -1
  43. package/dist/ToolResult.d.ts +56 -0
  44. package/dist/ToolResult.d.ts.map +1 -0
  45. package/dist/ToolResult.js +49 -0
  46. package/dist/ToolResult.js.map +1 -0
  47. package/dist/index.d.ts +4 -2
  48. package/dist/index.js +6 -4
  49. package/dist/internal/chat.js +4 -1
  50. package/dist/internal/chat.js.map +1 -1
  51. package/dist/internal/history.js +28 -3
  52. package/dist/internal/history.js.map +1 -1
  53. package/dist/internal/loop.d.ts +10 -5
  54. package/dist/internal/loop.d.ts.map +1 -1
  55. package/dist/internal/loop.js +60 -21
  56. package/dist/internal/loop.js.map +1 -1
  57. package/dist/internal/specialists.js +9 -16
  58. package/dist/internal/specialists.js.map +1 -1
  59. package/dist/internal/toolkit.d.ts +11 -7
  60. package/dist/internal/toolkit.d.ts.map +1 -1
  61. package/dist/internal/toolkit.js +74 -21
  62. package/dist/internal/toolkit.js.map +1 -1
  63. package/dist/internal/tools.js +39 -6
  64. package/dist/internal/tools.js.map +1 -1
  65. package/dist/internal/turns.d.ts.map +1 -1
  66. package/dist/internal/turns.js +24 -16
  67. package/dist/internal/turns.js.map +1 -1
  68. package/package.json +1 -1
  69. package/src/Assistant.ts +7 -13
  70. package/src/AssistantEvent.ts +73 -8
  71. package/src/AssistantLoop.ts +4 -2
  72. package/src/Block.ts +82 -1
  73. package/src/BlockKit.ts +37 -4
  74. package/src/Compaction.ts +19 -2
  75. package/src/Skill.ts +134 -57
  76. package/src/Specialist.ts +8 -11
  77. package/src/Timeline.ts +120 -21
  78. package/src/ToolApproval.ts +249 -0
  79. package/src/ToolDiscovery.ts +8 -3
  80. package/src/ToolResult.ts +80 -0
  81. package/src/index.ts +10 -0
  82. package/src/internal/chat.ts +11 -1
  83. package/src/internal/history.ts +58 -3
  84. package/src/internal/loop.ts +138 -35
  85. package/src/internal/specialists.ts +7 -13
  86. package/src/internal/toolkit.ts +102 -35
  87. package/src/internal/tools.ts +81 -5
  88. package/src/internal/turns.ts +31 -10
  89. package/dist/internal/skills.js +0 -33
  90. package/dist/internal/skills.js.map +0 -1
  91. package/src/internal/skills.ts +0 -48
@@ -0,0 +1,146 @@
1
+ import { AnyEntry, ApprovalDecision, ApprovalRequested, AssistantEvent_d_exports, ToolOutcome } from "./AssistantEvent.js";
2
+ import { CurrentChat } from "./CurrentChat.js";
3
+ import { InputId, InputId_d_exports } from "./InputId.js";
4
+ import * as Effect from "effect/Effect";
5
+ declare namespace ToolApproval_d_exports {
6
+ export { State, Status, apply, approve, closeStale, decisionId, fromEntries, reject, staleApprovals };
7
+ }
8
+ /**
9
+ * Represents where a call that waits for approval stands: `"pending"` until the user decides,
10
+ * then `"approved"` or `"rejected"`, or `"expired"` when the user moved on.
11
+ *
12
+ * @category models
13
+ * @since 0.4.0
14
+ */
15
+ export type Status = "pending" | "approved" | "rejected" | "expired";
16
+ /**
17
+ * Represents a tool call that waited, or waits, for the user's approval.
18
+ *
19
+ * @category models
20
+ * @since 0.4.0
21
+ */
22
+ export interface State {
23
+ readonly request: ApprovalRequested;
24
+ /** When the call started waiting, in epoch milliseconds. */
25
+ readonly at: number;
26
+ readonly status: Status;
27
+ /** The user's reason, when they rejected it with one. */
28
+ readonly reason: string | undefined;
29
+ /** How the approved call went, once it ran. */
30
+ readonly outcome: ToolOutcome | undefined;
31
+ }
32
+ /**
33
+ * Returns the approvals after one more entry. Fold a chat's entries in order, or use
34
+ * {@link fromEntries}.
35
+ *
36
+ * **Details**
37
+ *
38
+ * The first of a call's decision and its expiry counts: anything after it changes nothing.
39
+ *
40
+ * @category combinators
41
+ * @since 0.4.0
42
+ */
43
+ export declare const apply: (states: ReadonlyMap<string, State>, entry: AnyEntry) => ReadonlyMap<string, State>;
44
+ /**
45
+ * Returns every call that waited for approval in a chat, by call id, with where it stands.
46
+ *
47
+ * @category constructors
48
+ * @since 0.4.0
49
+ */
50
+ export declare const fromEntries: (entries: ReadonlyArray<AnyEntry>) => ReadonlyMap<string, State>;
51
+ /**
52
+ * The id of a decision on a call: the same for every decision on it, so the chat stores one.
53
+ *
54
+ * @category utils
55
+ * @since 0.4.0
56
+ */
57
+ export declare const decisionId: (callId: string) => InputId;
58
+ /**
59
+ * Returns the input that approves a call waiting for the user's approval, to submit like a
60
+ * message. `approval` is the call's item on the chat's timeline, or anything with the call's id.
61
+ *
62
+ * **Example** (Approve and reject buttons on the client)
63
+ *
64
+ * ```tsx
65
+ * import { ToolApproval } from "effect-assistant"
66
+ *
67
+ * const buttons = (approval: { readonly id: string; readonly status: ToolApproval.Status }) =>
68
+ * approval.status === "pending" ? (
69
+ * <>
70
+ * <button onClick={() => submit(ToolApproval.approve(approval))}>Approve</button>
71
+ * <button onClick={() => submit(ToolApproval.reject(approval, { reason: "Not this week" }))}>Reject</button>
72
+ * </>
73
+ * ) : null
74
+ * ```
75
+ *
76
+ * @category constructors
77
+ * @since 0.4.0
78
+ */
79
+ export declare const approve: (approval: {
80
+ readonly id: string;
81
+ }) => ApprovalDecision;
82
+ /**
83
+ * Returns the input that rejects a call waiting for the user's approval, with an optional short
84
+ * reason the model reads.
85
+ *
86
+ * @see {@link approve} for an example
87
+ *
88
+ * @category constructors
89
+ * @since 0.4.0
90
+ */
91
+ export declare const reject: (approval: {
92
+ readonly id: string;
93
+ }, options?: {
94
+ readonly reason?: string | undefined;
95
+ }) => ApprovalDecision;
96
+ /**
97
+ * Returns the ids of the calls still waiting for approval after the user typed the given number
98
+ * of messages without deciding them.
99
+ *
100
+ * **Details**
101
+ *
102
+ * These are the calls {@link closeStale} closes.
103
+ *
104
+ * @category utils
105
+ * @since 0.4.0
106
+ */
107
+ export declare const staleApprovals: (entries: ReadonlyArray<AnyEntry>, options: {
108
+ readonly messages: number;
109
+ }) => ReadonlyArray<string>;
110
+ /**
111
+ * Closes the calls the user moved on from, which still wait for approval after the given number
112
+ * of typed messages: they expire, and won't run.
113
+ *
114
+ * **Details**
115
+ *
116
+ * Run it from a turn, before or after its loop, like `BlockKit.closeStale`. It records an
117
+ * `ApprovalsExpired` event: the timeline shows the calls as expired, the model reads that they
118
+ * weren't approved, and a decision that arrives later isn't stored.
119
+ *
120
+ * **Example** (Closing calls the user moved on from, and stale blocks, every turn)
121
+ *
122
+ * ```ts
123
+ * import { BlockKit, ToolApproval } from "effect-assistant"
124
+ * import * as Effect from "effect/Effect"
125
+ *
126
+ * const MyAssistantLive = MyAssistant.toLayer(
127
+ * Effect.fn(function* (turn) {
128
+ * yield* BlockKit.closeStale({ messages: 10 })
129
+ * yield* ToolApproval.closeStale({ messages: 10 })
130
+ *
131
+ * return turn.loop({ instructions, toolkit: MyTools })
132
+ * })
133
+ * )
134
+ * ```
135
+ *
136
+ * @see {@link staleApprovals} for the calls it closes
137
+ *
138
+ * @category utils
139
+ * @since 0.4.0
140
+ */
141
+ export declare const closeStale: (options: {
142
+ readonly messages: number;
143
+ }) => Effect.Effect<void, never, CurrentChat>;
144
+ //#endregion
145
+ export { ToolApproval_d_exports };
146
+ //# sourceMappingURL=ToolApproval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolApproval.d.ts","names":[],"sources":["../src/ToolApproval.ts"],"mappings":";;;;;;;;;;;;;;YA0BY;;;;;;;iBAQK;WACN,SAAS;;WAET;WACA,QAAQ;;WAER;;WAEA,SAAS;;;;;;;;;;;;;qBAmBP,QAAK,QACR,oBAAoB,QAAM,OAC3B,aACN,oBAAoB;;;;;;;qBA0DV,cAAW,SAAa,cAAc,cAA2B,oBAAoB;;;;;;;qBASrF,aAAU,mBAAqB;;;;;;;;;;;;;;;;;;;;;;qBAuB/B,UAAO;WAAyB;MAAe;;;;;;;;;;qBAY/C,SAAM;WACI;GAAY;WACZ;MACpB;;;;;;;;;;;;qBAqBU,iBAAc,SAChB,cAAc,WAAwB;WAC3B;MACnB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkDU,aAAU;WAAsD;MAK3E,OAAA,oBAAA"}
@@ -0,0 +1,201 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import { fromKey } from "./InputId.js";
3
+ import { ApprovalDecision, ApprovalsExpired, isLibraryEvent } from "./AssistantEvent.js";
4
+ import { CurrentChat } from "./CurrentChat.js";
5
+ import * as Effect from "effect/Effect";
6
+ import * as Predicate from "effect/Predicate";
7
+ //#region src/ToolApproval.ts
8
+ /**
9
+ * Tool calls that wait for the user's approval.
10
+ *
11
+ * A tool made with Effect's `needsApproval` doesn't run when the model calls it in a turn: the
12
+ * call waits ({@link AssistantEvent.ApprovalRequested}), the turn ends, and the chat's timeline
13
+ * shows it to the user. Their decision, built with {@link approve} or {@link reject} and submitted
14
+ * like a message, wakes a turn: an approved call runs then, with its params and id, and a rejected
15
+ * one doesn't. A call the user moved on from expires ({@link closeStale}, like `BlockKit.closeStale`). On the timeline, every
16
+ * call is an item with its tool's name and where it stands: only the yes or no, since the
17
+ * assistant's message says what it asks.
18
+ *
19
+ * @since 0.4.0
20
+ */
21
+ var ToolApproval_exports = /* @__PURE__ */ __exportAll({
22
+ apply: () => apply,
23
+ approve: () => approve,
24
+ closeStale: () => closeStale,
25
+ decisionId: () => decisionId,
26
+ fromEntries: () => fromEntries,
27
+ reject: () => reject,
28
+ staleApprovals: () => staleApprovals
29
+ });
30
+ const decided = (state, decision) => decision.reason === void 0 ? {
31
+ ...state,
32
+ status: decision.decision
33
+ } : {
34
+ ...state,
35
+ status: decision.decision,
36
+ reason: decision.reason
37
+ };
38
+ /**
39
+ * Returns the approvals after one more entry. Fold a chat's entries in order, or use
40
+ * {@link fromEntries}.
41
+ *
42
+ * **Details**
43
+ *
44
+ * The first of a call's decision and its expiry counts: anything after it changes nothing.
45
+ *
46
+ * @category combinators
47
+ * @since 0.4.0
48
+ */
49
+ const apply = (states, entry) => {
50
+ const { event } = entry;
51
+ if (!isLibraryEvent(event)) return states;
52
+ if (Predicate.isTagged(event, "ApprovalRequested")) return states.has(event.callId) ? states : new Map(states).set(event.callId, {
53
+ request: event,
54
+ at: entry.at,
55
+ status: "pending",
56
+ reason: void 0,
57
+ outcome: void 0
58
+ });
59
+ if (Predicate.isTagged(event, "ApprovalDecision")) {
60
+ const state = states.get(event.callId);
61
+ return state === void 0 || state.status !== "pending" ? states : new Map(states).set(event.callId, decided(state, event));
62
+ }
63
+ if (Predicate.isTagged(event, "ApprovalsExpired")) {
64
+ const expired = event.callIds.flatMap((callId) => {
65
+ const state = states.get(callId);
66
+ return state === void 0 || state.status !== "pending" ? [] : [{
67
+ ...state,
68
+ status: "expired"
69
+ }];
70
+ });
71
+ if (expired.length === 0) return states;
72
+ const next = new Map(states);
73
+ for (const state of expired) next.set(state.request.callId, state);
74
+ return next;
75
+ }
76
+ if (Predicate.isTagged(event, "ToolResult")) {
77
+ const state = states.get(event.callId);
78
+ return state === void 0 || state.status !== "approved" ? states : new Map(states).set(event.callId, {
79
+ ...state,
80
+ outcome: event.outcome
81
+ });
82
+ }
83
+ return states;
84
+ };
85
+ /**
86
+ * Returns every call that waited for approval in a chat, by call id, with where it stands.
87
+ *
88
+ * @category constructors
89
+ * @since 0.4.0
90
+ */
91
+ const fromEntries = (entries) => entries.reduce(apply, /* @__PURE__ */ new Map());
92
+ /**
93
+ * The id of a decision on a call: the same for every decision on it, so the chat stores one.
94
+ *
95
+ * @category utils
96
+ * @since 0.4.0
97
+ */
98
+ const decisionId = (callId) => fromKey(`approval:${callId}`);
99
+ /**
100
+ * Returns the input that approves a call waiting for the user's approval, to submit like a
101
+ * message. `approval` is the call's item on the chat's timeline, or anything with the call's id.
102
+ *
103
+ * **Example** (Approve and reject buttons on the client)
104
+ *
105
+ * ```tsx
106
+ * import { ToolApproval } from "effect-assistant"
107
+ *
108
+ * const buttons = (approval: { readonly id: string; readonly status: ToolApproval.Status }) =>
109
+ * approval.status === "pending" ? (
110
+ * <>
111
+ * <button onClick={() => submit(ToolApproval.approve(approval))}>Approve</button>
112
+ * <button onClick={() => submit(ToolApproval.reject(approval, { reason: "Not this week" }))}>Reject</button>
113
+ * </>
114
+ * ) : null
115
+ * ```
116
+ *
117
+ * @category constructors
118
+ * @since 0.4.0
119
+ */
120
+ const approve = (approval) => ApprovalDecision.make({
121
+ id: decisionId(approval.id),
122
+ callId: approval.id,
123
+ decision: "approved"
124
+ });
125
+ /**
126
+ * Returns the input that rejects a call waiting for the user's approval, with an optional short
127
+ * reason the model reads.
128
+ *
129
+ * @see {@link approve} for an example
130
+ *
131
+ * @category constructors
132
+ * @since 0.4.0
133
+ */
134
+ const reject = (approval, options) => options?.reason === void 0 ? ApprovalDecision.make({
135
+ id: decisionId(approval.id),
136
+ callId: approval.id,
137
+ decision: "rejected"
138
+ }) : ApprovalDecision.make({
139
+ id: decisionId(approval.id),
140
+ callId: approval.id,
141
+ decision: "rejected",
142
+ reason: options.reason
143
+ });
144
+ /**
145
+ * Returns the ids of the calls still waiting for approval after the user typed the given number
146
+ * of messages without deciding them.
147
+ *
148
+ * **Details**
149
+ *
150
+ * These are the calls {@link closeStale} closes.
151
+ *
152
+ * @category utils
153
+ * @since 0.4.0
154
+ */
155
+ const staleApprovals = (entries, options) => {
156
+ return [...fromEntries(entries).values()].flatMap((state) => {
157
+ if (state.status !== "pending") return [];
158
+ const requested = entries.findIndex(({ event }) => isLibraryEvent(event) && Predicate.isTagged(event, "ApprovalRequested") && event.callId === state.request.callId);
159
+ return entries.slice(requested + 1).filter(({ event }) => Predicate.isTagged(event, "UserMessage")).length >= options.messages ? [state.request.callId] : [];
160
+ });
161
+ };
162
+ /**
163
+ * Closes the calls the user moved on from, which still wait for approval after the given number
164
+ * of typed messages: they expire, and won't run.
165
+ *
166
+ * **Details**
167
+ *
168
+ * Run it from a turn, before or after its loop, like `BlockKit.closeStale`. It records an
169
+ * `ApprovalsExpired` event: the timeline shows the calls as expired, the model reads that they
170
+ * weren't approved, and a decision that arrives later isn't stored.
171
+ *
172
+ * **Example** (Closing calls the user moved on from, and stale blocks, every turn)
173
+ *
174
+ * ```ts
175
+ * import { BlockKit, ToolApproval } from "effect-assistant"
176
+ * import * as Effect from "effect/Effect"
177
+ *
178
+ * const MyAssistantLive = MyAssistant.toLayer(
179
+ * Effect.fn(function* (turn) {
180
+ * yield* BlockKit.closeStale({ messages: 10 })
181
+ * yield* ToolApproval.closeStale({ messages: 10 })
182
+ *
183
+ * return turn.loop({ instructions, toolkit: MyTools })
184
+ * })
185
+ * )
186
+ * ```
187
+ *
188
+ * @see {@link staleApprovals} for the calls it closes
189
+ *
190
+ * @category utils
191
+ * @since 0.4.0
192
+ */
193
+ const closeStale = Effect.fn(function* (options) {
194
+ const chat = yield* CurrentChat;
195
+ const stale = staleApprovals(yield* chat.entries, options);
196
+ if (stale.length > 0) yield* chat.append(ApprovalsExpired.make({ callIds: stale }));
197
+ });
198
+ //#endregion
199
+ export { ToolApproval_exports, apply, approve, closeStale, decisionId, fromEntries, reject, staleApprovals };
200
+
201
+ //# sourceMappingURL=ToolApproval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolApproval.js","names":["AssistantEvent.isLibraryEvent","InputId.fromKey"],"sources":["../src/ToolApproval.ts"],"sourcesContent":["/**\n * Tool calls that wait for the user's approval.\n *\n * A tool made with Effect's `needsApproval` doesn't run when the model calls it in a turn: the\n * call waits ({@link AssistantEvent.ApprovalRequested}), the turn ends, and the chat's timeline\n * shows it to the user. Their decision, built with {@link approve} or {@link reject} and submitted\n * like a message, wakes a turn: an approved call runs then, with its params and id, and a rejected\n * one doesn't. A call the user moved on from expires ({@link closeStale}, like `BlockKit.closeStale`). On the timeline, every\n * call is an item with its tool's name and where it stands: only the yes or no, since the\n * assistant's message says what it asks.\n *\n * @since 0.4.0\n */\nimport * as Effect from \"effect/Effect\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as AssistantEvent from \"./AssistantEvent.ts\"\nimport { CurrentChat } from \"./CurrentChat.ts\"\nimport * as InputId from \"./InputId.ts\"\n\n/**\n * Represents where a call that waits for approval stands: `\"pending\"` until the user decides,\n * then `\"approved\"` or `\"rejected\"`, or `\"expired\"` when the user moved on.\n *\n * @category models\n * @since 0.4.0\n */\nexport type Status = \"pending\" | \"approved\" | \"rejected\" | \"expired\"\n\n/**\n * Represents a tool call that waited, or waits, for the user's approval.\n *\n * @category models\n * @since 0.4.0\n */\nexport interface State {\n readonly request: AssistantEvent.ApprovalRequested\n /** When the call started waiting, in epoch milliseconds. */\n readonly at: number\n readonly status: Status\n /** The user's reason, when they rejected it with one. */\n readonly reason: string | undefined\n /** How the approved call went, once it ran. */\n readonly outcome: AssistantEvent.ToolOutcome | undefined\n}\n\nconst decided = (state: State, decision: AssistantEvent.ApprovalDecision): State =>\n decision.reason === undefined\n ? { ...state, status: decision.decision }\n : { ...state, status: decision.decision, reason: decision.reason }\n\n/**\n * Returns the approvals after one more entry. Fold a chat's entries in order, or use\n * {@link fromEntries}.\n *\n * **Details**\n *\n * The first of a call's decision and its expiry counts: anything after it changes nothing.\n *\n * @category combinators\n * @since 0.4.0\n */\nexport const apply = (\n states: ReadonlyMap<string, State>,\n entry: AssistantEvent.AnyEntry\n): ReadonlyMap<string, State> => {\n const { event } = entry\n\n if (!AssistantEvent.isLibraryEvent(event)) return states\n\n if (Predicate.isTagged(event, \"ApprovalRequested\")) {\n return states.has(event.callId)\n ? states\n : new Map(states).set(event.callId, {\n request: event,\n at: entry.at,\n status: \"pending\",\n reason: undefined,\n outcome: undefined\n })\n }\n\n if (Predicate.isTagged(event, \"ApprovalDecision\")) {\n const state = states.get(event.callId)\n\n return state === undefined || state.status !== \"pending\"\n ? states\n : new Map(states).set(event.callId, decided(state, event))\n }\n\n if (Predicate.isTagged(event, \"ApprovalsExpired\")) {\n const expired = event.callIds.flatMap((callId) => {\n const state = states.get(callId)\n\n return state === undefined || state.status !== \"pending\" ? [] : [{ ...state, status: \"expired\" as const }]\n })\n\n if (expired.length === 0) return states\n\n const next = new Map(states)\n\n for (const state of expired) next.set(state.request.callId, state)\n\n return next\n }\n\n if (Predicate.isTagged(event, \"ToolResult\")) {\n const state = states.get(event.callId)\n\n return state === undefined || state.status !== \"approved\"\n ? states\n : new Map(states).set(event.callId, { ...state, outcome: event.outcome })\n }\n\n return states\n}\n\n/**\n * Returns every call that waited for approval in a chat, by call id, with where it stands.\n *\n * @category constructors\n * @since 0.4.0\n */\nexport const fromEntries = (entries: ReadonlyArray<AssistantEvent.AnyEntry>): ReadonlyMap<string, State> =>\n entries.reduce(apply, new Map<string, State>())\n\n/**\n * The id of a decision on a call: the same for every decision on it, so the chat stores one.\n *\n * @category utils\n * @since 0.4.0\n */\nexport const decisionId = (callId: string): InputId.InputId => InputId.fromKey(`approval:${callId}`)\n\n/**\n * Returns the input that approves a call waiting for the user's approval, to submit like a\n * message. `approval` is the call's item on the chat's timeline, or anything with the call's id.\n *\n * **Example** (Approve and reject buttons on the client)\n *\n * ```tsx\n * import { ToolApproval } from \"effect-assistant\"\n *\n * const buttons = (approval: { readonly id: string; readonly status: ToolApproval.Status }) =>\n * approval.status === \"pending\" ? (\n * <>\n * <button onClick={() => submit(ToolApproval.approve(approval))}>Approve</button>\n * <button onClick={() => submit(ToolApproval.reject(approval, { reason: \"Not this week\" }))}>Reject</button>\n * </>\n * ) : null\n * ```\n *\n * @category constructors\n * @since 0.4.0\n */\nexport const approve = (approval: { readonly id: string }): AssistantEvent.ApprovalDecision =>\n AssistantEvent.ApprovalDecision.make({ id: decisionId(approval.id), callId: approval.id, decision: \"approved\" })\n\n/**\n * Returns the input that rejects a call waiting for the user's approval, with an optional short\n * reason the model reads.\n *\n * @see {@link approve} for an example\n *\n * @category constructors\n * @since 0.4.0\n */\nexport const reject = (\n approval: { readonly id: string },\n options?: { readonly reason?: string | undefined }\n): AssistantEvent.ApprovalDecision =>\n options?.reason === undefined\n ? AssistantEvent.ApprovalDecision.make({ id: decisionId(approval.id), callId: approval.id, decision: \"rejected\" })\n : AssistantEvent.ApprovalDecision.make({\n id: decisionId(approval.id),\n callId: approval.id,\n decision: \"rejected\",\n reason: options.reason\n })\n\n/**\n * Returns the ids of the calls still waiting for approval after the user typed the given number\n * of messages without deciding them.\n *\n * **Details**\n *\n * These are the calls {@link closeStale} closes.\n *\n * @category utils\n * @since 0.4.0\n */\nexport const staleApprovals = (\n entries: ReadonlyArray<AssistantEvent.AnyEntry>,\n options: { readonly messages: number }\n): ReadonlyArray<string> => {\n const states = fromEntries(entries)\n\n return [...states.values()].flatMap((state) => {\n if (state.status !== \"pending\") return []\n\n const requested = entries.findIndex(\n ({ event }) =>\n AssistantEvent.isLibraryEvent(event) &&\n Predicate.isTagged(event, \"ApprovalRequested\") &&\n event.callId === state.request.callId\n )\n\n const typed = entries.slice(requested + 1).filter(({ event }) => Predicate.isTagged(event, \"UserMessage\")).length\n\n return typed >= options.messages ? [state.request.callId] : []\n })\n}\n\n/**\n * Closes the calls the user moved on from, which still wait for approval after the given number\n * of typed messages: they expire, and won't run.\n *\n * **Details**\n *\n * Run it from a turn, before or after its loop, like `BlockKit.closeStale`. It records an\n * `ApprovalsExpired` event: the timeline shows the calls as expired, the model reads that they\n * weren't approved, and a decision that arrives later isn't stored.\n *\n * **Example** (Closing calls the user moved on from, and stale blocks, every turn)\n *\n * ```ts\n * import { BlockKit, ToolApproval } from \"effect-assistant\"\n * import * as Effect from \"effect/Effect\"\n *\n * const MyAssistantLive = MyAssistant.toLayer(\n * Effect.fn(function* (turn) {\n * yield* BlockKit.closeStale({ messages: 10 })\n * yield* ToolApproval.closeStale({ messages: 10 })\n *\n * return turn.loop({ instructions, toolkit: MyTools })\n * })\n * )\n * ```\n *\n * @see {@link staleApprovals} for the calls it closes\n *\n * @category utils\n * @since 0.4.0\n */\nexport const closeStale = Effect.fn(function* (options: { readonly messages: number }) {\n const chat = yield* CurrentChat\n const stale = staleApprovals(yield* chat.entries, options)\n\n if (stale.length > 0) yield* chat.append(AssistantEvent.ApprovalsExpired.make({ callIds: stale }))\n})\n"],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { AssistantToolCall } from "./AssistantToolCall.js";
2
+ import { ToolServices, toolkit_d_exports } from "./internal/toolkit.js";
2
3
  import * as Schema from "effect/Schema";
3
4
  import * as Tool from "effect/ai/Tool";
4
5
  import * as Toolkit from "effect/ai/Toolkit";
@@ -14,8 +15,9 @@ declare namespace ToolDiscovery_d_exports {
14
15
  * the tools' handlers. A catalog tool's services are `execute_tool`'s, so the turn provides them
15
16
  * as it does for any tool.
16
17
  *
17
- * A catalog tool with Effect's `needsApproval` set fails the layer when it is built, as it would
18
- * fail a loop: the library doesn't run calls that wait for approval.
18
+ * A catalog tool with Effect's `needsApproval` set fails the layer when it is built: a call
19
+ * through `execute_tool` can't wait for the user's approval. Give such a tool to the loop's toolkit
20
+ * directly (see `ToolApproval`).
19
21
  *
20
22
  * **Example** (Finding rarely used tools when needed)
21
23
  *
@@ -50,7 +52,7 @@ export declare const make: <T extends Record<string, Tool.Any>>(_catalog: Toolki
50
52
  readonly success: Schema.Codec<Schema.Json, Schema.Json, never, never>;
51
53
  readonly failure: Schema.Codec<Schema.Json, Schema.Json, never, never>;
52
54
  readonly failureMode: "error";
53
- }, AssistantToolCall | Exclude<Tool.HandlerServices<T[keyof T]>, AssistantToolCall>>;
55
+ }, AssistantToolCall | ToolServices<T>>;
54
56
  readonly search_tools: Tool.Tool<"search_tools", {
55
57
  readonly parameters: Schema.Struct<{
56
58
  readonly query: Schema.String;
@@ -88,7 +90,7 @@ export declare const layer: <T extends Record<string, Tool.Any>>(catalog: Toolki
88
90
  readonly success: Schema.Codec<Schema.Json, Schema.Json, never, never>;
89
91
  readonly failure: Schema.Codec<Schema.Json, Schema.Json, never, never>;
90
92
  readonly failureMode: "error";
91
- }, AssistantToolCall | Exclude<Tool.HandlerServices<T[keyof T]>, AssistantToolCall>>;
93
+ }, AssistantToolCall | ToolServices<T>>;
92
94
  readonly search_tools: Tool.Tool<"search_tools", {
93
95
  readonly parameters: Schema.Struct<{
94
96
  readonly query: Schema.String;
@@ -1 +1 @@
1
- {"version":3,"file":"ToolDiscovery.d.ts","names":[],"sources":["../src/ToolDiscovery.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA2Ha,OAAQ,UAAU,eAAe,KAAK,MAAI,UAE3C,QAAQ,QAAQ,OAAE,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkBjB,QAAS,UAAU,eAAe,KAAK,MAAI,SAAW,QAAQ,QAAQ,8BAAE,MAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;WAmClF,QAAA,KAAA,YAAA,2BAAA"}
1
+ {"version":3,"file":"ToolDiscovery.d.ts","names":[],"sources":["../src/ToolDiscovery.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA4Ha,OAAQ,UAAU,eAAe,KAAK,MAAI,UAE3C,QAAQ,QAAQ,OAAE,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkBjB,QAAS,UAAU,eAAe,KAAK,MAAI,SAAW,QAAQ,QAAQ,8BAAE,MAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;WAuClF,QAAA,KAAA,YAAA,2BAAA"}
@@ -1,7 +1,7 @@
1
1
  import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
2
  import { toJson } from "./internal/schema.js";
3
3
  import { AssistantToolCall } from "./AssistantToolCall.js";
4
- import { needingApproval, needsApprovalMessage, runNative } from "./internal/toolkit.js";
4
+ import { needingApproval, runNative } from "./internal/toolkit.js";
5
5
  import * as Effect from "effect/Effect";
6
6
  import * as Schema from "effect/Schema";
7
7
  import * as Response from "effect/ai/Response";
@@ -67,8 +67,9 @@ const requiring = () => (tool) => tool;
67
67
  * the tools' handlers. A catalog tool's services are `execute_tool`'s, so the turn provides them
68
68
  * as it does for any tool.
69
69
  *
70
- * A catalog tool with Effect's `needsApproval` set fails the layer when it is built, as it would
71
- * fail a loop: the library doesn't run calls that wait for approval.
70
+ * A catalog tool with Effect's `needsApproval` set fails the layer when it is built: a call
71
+ * through `execute_tool` can't wait for the user's approval. Give such a tool to the loop's toolkit
72
+ * directly (see `ToolApproval`).
72
73
  *
73
74
  * **Example** (Finding rarely used tools when needed)
74
75
  *
@@ -114,7 +115,7 @@ const layer = (catalog) => make(catalog).toLayer(Effect.gen(function* () {
114
115
  const resolved = yield* catalog;
115
116
  const definitions = Object.values(resolved.tools);
116
117
  const needingApproval$1 = needingApproval(definitions);
117
- if (needingApproval$1.length > 0) return yield* Effect.die(needsApprovalMessage(needingApproval$1));
118
+ if (needingApproval$1.length > 0) return yield* Effect.die(`${needingApproval$1.join(", ")} ${needingApproval$1.length === 1 ? "sets" : "set"} needsApproval, and a call through execute_tool can't wait for the user's approval. Give it to the loop's toolkit instead of ToolDiscovery's catalog.`);
118
119
  return {
119
120
  search_tools: ({ query }) => Effect.sync(() => search(definitions, query, 5).map((tool) => ({
120
121
  name: tool.name,
@@ -1 +1 @@
1
- {"version":3,"file":"ToolDiscovery.js","names":["needingApproval","Toolkits.needingApproval","Toolkits.needsApprovalMessage","Toolkits.runNative"],"sources":["../src/ToolDiscovery.ts"],"sourcesContent":["/**\n * Turns a catalog toolkit into two tools, so the prompt doesn't carry every tool definition.\n *\n * `search_tools` finds tools by what the model needs to do and returns their names, descriptions,\n * and input schemas. `execute_tool` validates an input and runs one of them. {@link make} returns\n * the two tools as a native toolkit, and {@link layer} their handlers.\n *\n * @since 0.1.0\n */\nimport * as Response from \"effect/ai/Response\"\nimport * as Tool from \"effect/ai/Tool\"\nimport * as Toolkit from \"effect/ai/Toolkit\"\nimport * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\nimport { AssistantToolCall } from \"./AssistantToolCall.ts\"\nimport { toJson } from \"./internal/schema.ts\"\nimport * as Toolkits from \"./internal/toolkit.ts\"\n\nconst words = (text: string): ReadonlySet<string> =>\n new Set(\n text\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((word) => word.length >= 3)\n )\n\nconst score = (query: ReadonlySet<string>, text: string): number => {\n const target = [...words(text)]\n\n const matches = (word: string) =>\n target.some((t) => t === word || (word.length >= 4 && (t.startsWith(word) || word.startsWith(t))))\n\n return [...query].filter(matches).length\n}\n\n// Everything when nothing matches, so the model can pick or search again.\nconst search = (tools: ReadonlyArray<Tool.Any>, query: string, limit: number): ReadonlyArray<Tool.Any> => {\n const queryWords = words(query)\n\n const ranked = tools\n .flatMap((tool) => {\n const hits = score(queryWords, `${tool.name} ${Tool.getDescription(tool) ?? \"\"}`)\n\n return hits > 0 ? [{ tool, score: hits }] : []\n })\n .sort((a, b) => b.score - a.score)\n\n return (ranked.length > 0 ? ranked.map((hit) => hit.tool) : tools).slice(0, limit)\n}\n\nconst SearchTools = Tool.make(\"search_tools\", {\n description:\n \"Search for more tools by what you need to do. Returns their names, descriptions, and input schemas; call one with execute_tool.\",\n parameters: Schema.Struct({\n query: Schema.String.annotate({ description: \"What you need to do, in a few words.\" })\n }),\n success: Schema.Array(\n Schema.Struct({\n name: Schema.String,\n description: Schema.optional(Schema.String),\n inputSchema: Schema.Json\n })\n )\n})\n\nconst ExecuteTool = Tool.make(\"execute_tool\", {\n description: \"Run a tool found with search_tools. Pass its name and an input matching its input schema.\",\n parameters: Schema.Struct({\n name: Schema.String,\n input: Schema.Record(Schema.String, Schema.Json)\n }),\n success: Schema.Json,\n // The tool's failure is this call's, so the loop sees it failed (a `wait: true` message doesn't\n // end the turn).\n failure: Schema.Json,\n dependencies: [AssistantToolCall]\n})\n\n// A tool's requirements are a covariant phantom type, so one that needs nothing is one that needs\n// any.\nconst requiring =\n <R>() =>\n <N extends string, C extends (Tool.Any extends Tool.Tool<string, infer K, unknown> ? K : never), R0>(\n tool: Tool.Tool<N, C, R0>\n ): Tool.Tool<N, C, R0 | R> =>\n tool\n\n/**\n * Creates the `search_tools` and `execute_tool` tools over a catalog toolkit, as a native toolkit.\n *\n * **Details**\n *\n * Merge the toolkit into the loop's, and provide {@link layer} for the same catalog, which has\n * the tools' handlers. A catalog tool's services are `execute_tool`'s, so the turn provides them\n * as it does for any tool.\n *\n * A catalog tool with Effect's `needsApproval` set fails the layer when it is built, as it would\n * fail a loop: the library doesn't run calls that wait for approval.\n *\n * **Example** (Finding rarely used tools when needed)\n *\n * ```ts\n * import { ToolDiscovery } from \"effect-assistant\"\n * import * as Toolkit from \"effect/ai/Toolkit\"\n * import * as Layer from \"effect/Layer\"\n *\n * // OfficeTools is a big toolkit, found when needed. CommonTools stays in the prompt.\n * const OfficeDiscovery = ToolDiscovery.make(OfficeTools)\n * const OfficeDiscoveryLive = ToolDiscovery.layer(OfficeTools).pipe(Layer.provide(OfficeToolsLive))\n *\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({\n * instructions,\n * toolkit: Toolkit.merge(CommonTools, OfficeDiscovery)\n * })\n * ).pipe(Layer.provide([CommonToolsLive, OfficeDiscoveryLive]))\n * ```\n *\n * @see {@link layer} for the tools' handlers\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <T extends Record<string, Tool.Any>>(\n // Only its type is used here, for `execute_tool`'s services: `layer` runs its tools.\n _catalog: Toolkit.Toolkit<T>\n) => Toolkit.make(SearchTools, requiring<Toolkits.ToolServices<T>>()(ExecuteTool))\n\n/**\n * Creates the layer with the handlers of the `search_tools` and `execute_tool` tools over a\n * catalog toolkit.\n *\n * **Details**\n *\n * The layer needs the catalog's handlers. It provides the handlers of the toolkit that\n * {@link make} returns for the same catalog: handlers are keyed by tool name, so the two calls\n * don't need to share a value. Give both the same catalog.\n *\n * @see {@link make} for the toolkit and an example\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer = <T extends Record<string, Tool.Any>>(catalog: Toolkit.Toolkit<T>) =>\n make(catalog).toLayer(\n Effect.gen(function* () {\n const resolved = yield* catalog\n const definitions = Object.values(resolved.tools)\n const needingApproval = Toolkits.needingApproval(definitions)\n\n if (needingApproval.length > 0) return yield* Effect.die(Toolkits.needsApprovalMessage(needingApproval))\n\n return {\n search_tools: ({ query }) =>\n Effect.sync(() =>\n search(definitions, query, 5).map((tool) => ({\n name: tool.name,\n description: Tool.getDescription(tool),\n inputSchema: toJson(Tool.getJsonSchema(tool))\n }))\n ),\n execute_tool: Effect.fnUntraced(function* ({ name, input }) {\n // Named after the call that runs it: the same id when a crash runs that call again.\n const outer = yield* AssistantToolCall\n\n const call = Response.makePart(\"tool-call\", {\n id: `${outer.callId}:${name}`,\n name,\n params: input,\n providerExecuted: false\n })\n\n const { outcome, result } = yield* Toolkits.runNative(resolved, call)\n\n return outcome === \"failure\" ? yield* Effect.fail(result) : result\n })\n }\n })\n )\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAkBA,MAAM,SAAS,SACb,IAAI,IACF,KACG,YAAY,CAAC,CACb,MAAM,YAAY,CAAC,CACnB,QAAQ,SAAS,KAAK,UAAU,CAAC,CACtC;AAEF,MAAM,SAAS,OAA4B,SAAyB;CAClE,MAAM,SAAS,CAAC,GAAG,MAAM,IAAI,CAAC;CAE9B,MAAM,WAAW,SACf,OAAO,MAAM,MAAM,MAAM,QAAS,KAAK,UAAU,MAAM,EAAE,WAAW,IAAI,KAAK,KAAK,WAAW,CAAC,EAAG;CAEnG,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC;AACpC;AAGA,MAAM,UAAU,OAAgC,OAAe,UAA2C;CACxG,MAAM,aAAa,MAAM,KAAK;CAE9B,MAAM,SAAS,MACZ,SAAS,SAAS;EACjB,MAAM,OAAO,MAAM,YAAY,GAAG,KAAK,KAAK,GAAG,KAAK,eAAe,IAAI,KAAK,IAAI;EAEhF,OAAO,OAAO,IAAI,CAAC;GAAE;GAAM,OAAO;EAAK,CAAC,IAAI,CAAC;CAC/C,CAAC,CAAC,CACD,MAAM,GAAG,MAAM,EAAE,QAAQ,EAAE,KAAK;CAEnC,QAAQ,OAAO,SAAS,IAAI,OAAO,KAAK,QAAQ,IAAI,IAAI,IAAI,MAAA,CAAO,MAAM,GAAG,KAAK;AACnF;AAEA,MAAM,cAAc,KAAK,KAAK,gBAAgB;CAC5C,aACE;CACF,YAAY,OAAO,OAAO,EACxB,OAAO,OAAO,OAAO,SAAS,EAAE,aAAa,uCAAuC,CAAC,EACvF,CAAC;CACD,SAAS,OAAO,MACd,OAAO,OAAO;EACZ,MAAM,OAAO;EACb,aAAa,OAAO,SAAS,OAAO,MAAM;EAC1C,aAAa,OAAO;CACtB,CAAC,CACH;AACF,CAAC;AAED,MAAM,cAAc,KAAK,KAAK,gBAAgB;CAC5C,aAAa;CACb,YAAY,OAAO,OAAO;EACxB,MAAM,OAAO;EACb,OAAO,OAAO,OAAO,OAAO,QAAQ,OAAO,IAAI;CACjD,CAAC;CACD,SAAS,OAAO;CAGhB,SAAS,OAAO;CAChB,cAAc,CAAC,iBAAiB;AAClC,CAAC;AAID,MAAM,mBAGF,SAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsCJ,MAAa,QAEX,aACG,QAAQ,KAAK,aAAa,UAAoC,CAAC,CAAC,WAAW,CAAC;;;;;;;;;;;;;;;;AAiBjF,MAAa,SAA6C,YACxD,KAAK,OAAO,CAAC,CAAC,QACZ,OAAO,IAAI,aAAa;CACtB,MAAM,WAAW,OAAO;CACxB,MAAM,cAAc,OAAO,OAAO,SAAS,KAAK;CAChD,MAAMA,oBAAkBC,gBAAyB,WAAW;CAE5D,IAAID,kBAAgB,SAAS,GAAG,OAAO,OAAO,OAAO,IAAIE,qBAA8BF,iBAAe,CAAC;CAEvG,OAAO;EACL,eAAe,EAAE,YACf,OAAO,WACL,OAAO,aAAa,OAAO,CAAC,CAAC,CAAC,KAAK,UAAU;GAC3C,MAAM,KAAK;GACX,aAAa,KAAK,eAAe,IAAI;GACrC,aAAa,OAAO,KAAK,cAAc,IAAI,CAAC;EAC9C,EAAE,CACJ;EACF,cAAc,OAAO,WAAW,WAAW,EAAE,MAAM,SAAS;GAE1D,MAAM,QAAQ,OAAO;GAErB,MAAM,OAAO,SAAS,SAAS,aAAa;IAC1C,IAAI,GAAG,MAAM,OAAO,GAAG;IACvB;IACA,QAAQ;IACR,kBAAkB;GACpB,CAAC;GAED,MAAM,EAAE,SAAS,WAAW,OAAOG,UAAmB,UAAU,IAAI;GAEpE,OAAO,YAAY,YAAY,OAAO,OAAO,KAAK,MAAM,IAAI;EAC9D,CAAC;CACH;AACF,CAAC,CACH"}
1
+ {"version":3,"file":"ToolDiscovery.js","names":["needingApproval","Toolkits.needingApproval","Toolkits.runNative"],"sources":["../src/ToolDiscovery.ts"],"sourcesContent":["/**\n * Turns a catalog toolkit into two tools, so the prompt doesn't carry every tool definition.\n *\n * `search_tools` finds tools by what the model needs to do and returns their names, descriptions,\n * and input schemas. `execute_tool` validates an input and runs one of them. {@link make} returns\n * the two tools as a native toolkit, and {@link layer} their handlers.\n *\n * @since 0.1.0\n */\nimport * as Response from \"effect/ai/Response\"\nimport * as Tool from \"effect/ai/Tool\"\nimport * as Toolkit from \"effect/ai/Toolkit\"\nimport * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\nimport { AssistantToolCall } from \"./AssistantToolCall.ts\"\nimport { toJson } from \"./internal/schema.ts\"\nimport * as Toolkits from \"./internal/toolkit.ts\"\n\nconst words = (text: string): ReadonlySet<string> =>\n new Set(\n text\n .toLowerCase()\n .split(/[^a-z0-9]+/)\n .filter((word) => word.length >= 3)\n )\n\nconst score = (query: ReadonlySet<string>, text: string): number => {\n const target = [...words(text)]\n\n const matches = (word: string) =>\n target.some((t) => t === word || (word.length >= 4 && (t.startsWith(word) || word.startsWith(t))))\n\n return [...query].filter(matches).length\n}\n\n// Everything when nothing matches, so the model can pick or search again.\nconst search = (tools: ReadonlyArray<Tool.Any>, query: string, limit: number): ReadonlyArray<Tool.Any> => {\n const queryWords = words(query)\n\n const ranked = tools\n .flatMap((tool) => {\n const hits = score(queryWords, `${tool.name} ${Tool.getDescription(tool) ?? \"\"}`)\n\n return hits > 0 ? [{ tool, score: hits }] : []\n })\n .sort((a, b) => b.score - a.score)\n\n return (ranked.length > 0 ? ranked.map((hit) => hit.tool) : tools).slice(0, limit)\n}\n\nconst SearchTools = Tool.make(\"search_tools\", {\n description:\n \"Search for more tools by what you need to do. Returns their names, descriptions, and input schemas; call one with execute_tool.\",\n parameters: Schema.Struct({\n query: Schema.String.annotate({ description: \"What you need to do, in a few words.\" })\n }),\n success: Schema.Array(\n Schema.Struct({\n name: Schema.String,\n description: Schema.optional(Schema.String),\n inputSchema: Schema.Json\n })\n )\n})\n\nconst ExecuteTool = Tool.make(\"execute_tool\", {\n description: \"Run a tool found with search_tools. Pass its name and an input matching its input schema.\",\n parameters: Schema.Struct({\n name: Schema.String,\n input: Schema.Record(Schema.String, Schema.Json)\n }),\n success: Schema.Json,\n // The tool's failure is this call's, so the loop sees it failed (a `wait: true` message doesn't\n // end the turn).\n failure: Schema.Json,\n dependencies: [AssistantToolCall]\n})\n\n// A tool's requirements are a covariant phantom type, so one that needs nothing is one that needs\n// any.\nconst requiring =\n <R>() =>\n <N extends string, C extends (Tool.Any extends Tool.Tool<string, infer K, unknown> ? K : never), R0>(\n tool: Tool.Tool<N, C, R0>\n ): Tool.Tool<N, C, R0 | R> =>\n tool\n\n/**\n * Creates the `search_tools` and `execute_tool` tools over a catalog toolkit, as a native toolkit.\n *\n * **Details**\n *\n * Merge the toolkit into the loop's, and provide {@link layer} for the same catalog, which has\n * the tools' handlers. A catalog tool's services are `execute_tool`'s, so the turn provides them\n * as it does for any tool.\n *\n * A catalog tool with Effect's `needsApproval` set fails the layer when it is built: a call\n * through `execute_tool` can't wait for the user's approval. Give such a tool to the loop's toolkit\n * directly (see `ToolApproval`).\n *\n * **Example** (Finding rarely used tools when needed)\n *\n * ```ts\n * import { ToolDiscovery } from \"effect-assistant\"\n * import * as Toolkit from \"effect/ai/Toolkit\"\n * import * as Layer from \"effect/Layer\"\n *\n * // OfficeTools is a big toolkit, found when needed. CommonTools stays in the prompt.\n * const OfficeDiscovery = ToolDiscovery.make(OfficeTools)\n * const OfficeDiscoveryLive = ToolDiscovery.layer(OfficeTools).pipe(Layer.provide(OfficeToolsLive))\n *\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({\n * instructions,\n * toolkit: Toolkit.merge(CommonTools, OfficeDiscovery)\n * })\n * ).pipe(Layer.provide([CommonToolsLive, OfficeDiscoveryLive]))\n * ```\n *\n * @see {@link layer} for the tools' handlers\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <T extends Record<string, Tool.Any>>(\n // Only its type is used here, for `execute_tool`'s services: `layer` runs its tools.\n _catalog: Toolkit.Toolkit<T>\n) => Toolkit.make(SearchTools, requiring<Toolkits.ToolServices<T>>()(ExecuteTool))\n\n/**\n * Creates the layer with the handlers of the `search_tools` and `execute_tool` tools over a\n * catalog toolkit.\n *\n * **Details**\n *\n * The layer needs the catalog's handlers. It provides the handlers of the toolkit that\n * {@link make} returns for the same catalog: handlers are keyed by tool name, so the two calls\n * don't need to share a value. Give both the same catalog.\n *\n * @see {@link make} for the toolkit and an example\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layer = <T extends Record<string, Tool.Any>>(catalog: Toolkit.Toolkit<T>) =>\n make(catalog).toLayer(\n Effect.gen(function* () {\n const resolved = yield* catalog\n const definitions = Object.values(resolved.tools)\n const needingApproval = Toolkits.needingApproval(definitions)\n\n if (needingApproval.length > 0) {\n return yield* Effect.die(\n `${needingApproval.join(\", \")} ${needingApproval.length === 1 ? \"sets\" : \"set\"} needsApproval, and a call through execute_tool can't wait for the user's approval. Give it to the loop's toolkit instead of ToolDiscovery's catalog.`\n )\n }\n\n return {\n search_tools: ({ query }) =>\n Effect.sync(() =>\n search(definitions, query, 5).map((tool) => ({\n name: tool.name,\n description: Tool.getDescription(tool),\n inputSchema: toJson(Tool.getJsonSchema(tool))\n }))\n ),\n execute_tool: Effect.fnUntraced(function* ({ name, input }) {\n // Named after the call that runs it: the same id when a crash runs that call again.\n const outer = yield* AssistantToolCall\n\n const call = Response.makePart(\"tool-call\", {\n id: `${outer.callId}:${name}`,\n name,\n params: input,\n providerExecuted: false\n })\n\n const { outcome, result } = yield* Toolkits.runNative(resolved, call)\n\n return outcome === \"failure\" ? yield* Effect.fail(result) : result\n })\n }\n })\n )\n"],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ import * as Context from "effect/Context";
2
+ import * as Schema from "effect/Schema";
3
+ import * as Tool from "effect/ai/Tool";
4
+ declare namespace ToolResult_d_exports {
5
+ export { ModelView, modelView };
6
+ }
7
+ type Schemas = {
8
+ readonly parameters: Schema.Top;
9
+ readonly success: Schema.Top;
10
+ readonly failure: Schema.Top;
11
+ readonly failureMode: Tool.FailureMode;
12
+ };
13
+ declare const ModelView_base: Context.ServiceClass<ModelView, "effect-assistant/ToolResult/ModelView", (success: any) => Schema.Json>;
14
+ /**
15
+ * Annotation for what the model reads of a tool's success, set with {@link modelView}.
16
+ *
17
+ * @category annotations
18
+ * @since 0.5.0
19
+ */
20
+ export declare class ModelView extends ModelView_base {}
21
+ /**
22
+ * Sets what the model reads of a tool's success. The chat's log keeps the whole success.
23
+ *
24
+ * **Details**
25
+ *
26
+ * The view gets the success as the tool's success schema decodes it, and returns the JSON the
27
+ * model reads instead. Failures reach the model as they are.
28
+ *
29
+ * **Example** (Keeping image URLs out of the model's context)
30
+ *
31
+ * ```ts
32
+ * import * as Tool from "effect/ai/Tool"
33
+ * import * as Schema from "effect/Schema"
34
+ * import { ToolResult } from "effect-assistant"
35
+ *
36
+ * const Asset = Schema.Struct({ id: Schema.String, name: Schema.String, imageUrl: Schema.String })
37
+ *
38
+ * export const SearchAssets = ToolResult.modelView(
39
+ * Tool.make("search_assets", {
40
+ * parameters: Schema.Struct({ query: Schema.String }),
41
+ * success: Schema.Struct({ items: Schema.Array(Asset) })
42
+ * }),
43
+ * (result) => ({ items: result.items.map(({ id, name }) => ({ id, name })) })
44
+ * )
45
+ * ```
46
+ *
47
+ * @category annotations
48
+ * @since 0.5.0
49
+ */
50
+ export declare const modelView: {
51
+ <Config extends Schemas>(view: (success: Config["success"]["Type"]) => Schema.Json): <Name extends string, R>(tool: Tool.Tool<Name, Config, R>) => Tool.Tool<Name, Config, R>;
52
+ <Name extends string, Config extends Schemas, R>(tool: Tool.Tool<Name, Config, R>, view: (success: Config["success"]["Type"]) => Schema.Json): Tool.Tool<Name, Config, R>;
53
+ };
54
+ //#endregion
55
+ export { ToolResult_d_exports };
56
+ //# sourceMappingURL=ToolResult.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolResult.d.ts","names":[],"sources":["../src/ToolResult.ts"],"mappings":";;;;;;KAmBK;WACM,YAAY,OAAO;WACnB,SAAS,OAAO;WAChB,SAAS,OAAO;WAChB,aAAa,KAAK;;cASuC,gBAAA,QAAA,aAAA,qDAAA,iBAAQ,OAAO;;;;;;;qBAAtE,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAiClB;GACV,eAAe,SACd,OAAO,SAAS,8BAA8B,OAAO,QACnD,qBAAqB,GAAG,MAAM,KAAK,KAAK,MAAM,QAAQ,OAAO,KAAK,KAAK,MAAM,QAAQ;GACxF,qBAAqB,eAAe,SAAS,GAC5C,MAAM,KAAK,KAAK,MAAM,QAAQ,IAC9B,OAAO,SAAS,8BAA8B,OAAO,OACpD,KAAK,KAAK,MAAM,QAAQ"}
@@ -0,0 +1,49 @@
1
+ import { __exportAll } from "./_virtual/_rolldown/runtime.js";
2
+ import * as Context from "effect/Context";
3
+ import { dual } from "effect/Function";
4
+ //#region src/ToolResult.ts
5
+ var ToolResult_exports = /* @__PURE__ */ __exportAll({
6
+ ModelView: () => ModelView,
7
+ modelView: () => modelView
8
+ });
9
+ /**
10
+ * Annotation for what the model reads of a tool's success, set with {@link modelView}.
11
+ *
12
+ * @category annotations
13
+ * @since 0.5.0
14
+ */
15
+ var ModelView = class extends Context.Service()("effect-assistant/ToolResult/ModelView") {};
16
+ /**
17
+ * Sets what the model reads of a tool's success. The chat's log keeps the whole success.
18
+ *
19
+ * **Details**
20
+ *
21
+ * The view gets the success as the tool's success schema decodes it, and returns the JSON the
22
+ * model reads instead. Failures reach the model as they are.
23
+ *
24
+ * **Example** (Keeping image URLs out of the model's context)
25
+ *
26
+ * ```ts
27
+ * import * as Tool from "effect/ai/Tool"
28
+ * import * as Schema from "effect/Schema"
29
+ * import { ToolResult } from "effect-assistant"
30
+ *
31
+ * const Asset = Schema.Struct({ id: Schema.String, name: Schema.String, imageUrl: Schema.String })
32
+ *
33
+ * export const SearchAssets = ToolResult.modelView(
34
+ * Tool.make("search_assets", {
35
+ * parameters: Schema.Struct({ query: Schema.String }),
36
+ * success: Schema.Struct({ items: Schema.Array(Asset) })
37
+ * }),
38
+ * (result) => ({ items: result.items.map(({ id, name }) => ({ id, name })) })
39
+ * )
40
+ * ```
41
+ *
42
+ * @category annotations
43
+ * @since 0.5.0
44
+ */
45
+ const modelView = dual(2, (tool, view) => tool.annotate(ModelView, view));
46
+ //#endregion
47
+ export { ModelView, ToolResult_exports, modelView };
48
+
49
+ //# sourceMappingURL=ToolResult.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ToolResult.js","names":[],"sources":["../src/ToolResult.ts"],"sourcesContent":["/**\n * Shapes what the model reads of a tool's result.\n *\n * A tool's success goes into the chat's log in full. {@link modelView} gives the model a smaller\n * view of it, so fields only the app's UI needs (an image URL, a file id) stay out of its context\n * and out of what it might copy into its replies.\n *\n * A tool whose results the assistant's blocks show (`Block.fromToolResult`) also gets a `resultId`\n * in what the model reads. The model passes it in a `tool_result` block to show that result, and\n * the client draws it from the full result in the log.\n *\n * @since 0.5.0\n */\nimport type * as Tool from \"effect/ai/Tool\"\nimport * as Context from \"effect/Context\"\nimport { dual } from \"effect/Function\"\nimport type * as Schema from \"effect/Schema\"\n\n// The tool's schemas, as `Tool.Tool` constrains them.\ntype Schemas = {\n readonly parameters: Schema.Top\n readonly success: Schema.Top\n readonly failure: Schema.Top\n readonly failureMode: Tool.FailureMode\n}\n\n/**\n * Annotation for what the model reads of a tool's success, set with {@link modelView}.\n *\n * @category annotations\n * @since 0.5.0\n */\nexport class ModelView extends Context.Service<ModelView, (success: any) => Schema.Json>()(\n \"effect-assistant/ToolResult/ModelView\"\n) {}\n\n/**\n * Sets what the model reads of a tool's success. The chat's log keeps the whole success.\n *\n * **Details**\n *\n * The view gets the success as the tool's success schema decodes it, and returns the JSON the\n * model reads instead. Failures reach the model as they are.\n *\n * **Example** (Keeping image URLs out of the model's context)\n *\n * ```ts\n * import * as Tool from \"effect/ai/Tool\"\n * import * as Schema from \"effect/Schema\"\n * import { ToolResult } from \"effect-assistant\"\n *\n * const Asset = Schema.Struct({ id: Schema.String, name: Schema.String, imageUrl: Schema.String })\n *\n * export const SearchAssets = ToolResult.modelView(\n * Tool.make(\"search_assets\", {\n * parameters: Schema.Struct({ query: Schema.String }),\n * success: Schema.Struct({ items: Schema.Array(Asset) })\n * }),\n * (result) => ({ items: result.items.map(({ id, name }) => ({ id, name })) })\n * )\n * ```\n *\n * @category annotations\n * @since 0.5.0\n */\nexport const modelView: {\n <Config extends Schemas>(\n view: (success: Config[\"success\"][\"Type\"]) => Schema.Json\n ): <Name extends string, R>(tool: Tool.Tool<Name, Config, R>) => Tool.Tool<Name, Config, R>\n <Name extends string, Config extends Schemas, R>(\n tool: Tool.Tool<Name, Config, R>,\n view: (success: Config[\"success\"][\"Type\"]) => Schema.Json\n ): Tool.Tool<Name, Config, R>\n} = dual(\n 2,\n <Name extends string, Config extends Schemas, R>(\n tool: Tool.Tool<Name, Config, R>,\n view: (success: Config[\"success\"][\"Type\"]) => Schema.Json\n ): Tool.Tool<Name, Config, R> => tool.annotate(ModelView, view)\n)\n"],"mappings":";;;;;;;;;;;;;;AAgCA,IAAa,YAAb,cAA+B,QAAQ,QAAkD,CAAC,CACxF,uCACF,CAAC,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+BH,MAAa,YAQT,KACF,IAEE,MACA,SAC+B,KAAK,SAAS,WAAW,IAAI,CAChE"}
package/dist/index.d.ts CHANGED
@@ -9,7 +9,6 @@ import { Timeline_d_exports } from "./Timeline.js";
9
9
  import { CurrentChat_d_exports } from "./CurrentChat.js";
10
10
  import { BlockKit_d_exports } from "./BlockKit.js";
11
11
  import { RunId_d_exports } from "./RunId.js";
12
- import { Skill_d_exports } from "./Skill.js";
13
12
  import { Specialist_d_exports } from "./Specialist.js";
14
13
  import { AssistantEngine_d_exports } from "./AssistantEngine.js";
15
14
  import { Chats_d_exports } from "./Chats.js";
@@ -19,5 +18,8 @@ import { Compaction_d_exports } from "./Compaction.js";
19
18
  import { InputId_d_exports } from "./InputId.js";
20
19
  import { ToolFailure_d_exports } from "./ToolFailure.js";
21
20
  import { Memory_d_exports } from "./Memory.js";
21
+ import { Skill_d_exports } from "./Skill.js";
22
+ import { ToolApproval_d_exports } from "./ToolApproval.js";
22
23
  import { ToolDiscovery_d_exports } from "./ToolDiscovery.js";
23
- export { Assistant_d_exports as Assistant, AssistantActivity_d_exports as AssistantActivity, AssistantEngine_d_exports as AssistantEngine, AssistantEvent_d_exports as AssistantEvent, AssistantLoop_d_exports as AssistantLoop, AssistantToolCall_d_exports as AssistantToolCall, Block_d_exports as Block, BlockKit_d_exports as BlockKit, ChatId_d_exports as ChatId, ChatLog_d_exports as ChatLog, Chats_d_exports as Chats, Compaction_d_exports as Compaction, CurrentChat_d_exports as CurrentChat, InputId_d_exports as InputId, Instructions_d_exports as Instructions, Memory_d_exports as Memory, RunId_d_exports as RunId, Skill_d_exports as Skill, Specialist_d_exports as Specialist, Timeline_d_exports as Timeline, ToolDiscovery_d_exports as ToolDiscovery, ToolFailure_d_exports as ToolFailure };
24
+ import { ToolResult_d_exports } from "./ToolResult.js";
25
+ export { Assistant_d_exports as Assistant, AssistantActivity_d_exports as AssistantActivity, AssistantEngine_d_exports as AssistantEngine, AssistantEvent_d_exports as AssistantEvent, AssistantLoop_d_exports as AssistantLoop, AssistantToolCall_d_exports as AssistantToolCall, Block_d_exports as Block, BlockKit_d_exports as BlockKit, ChatId_d_exports as ChatId, ChatLog_d_exports as ChatLog, Chats_d_exports as Chats, Compaction_d_exports as Compaction, CurrentChat_d_exports as CurrentChat, InputId_d_exports as InputId, Instructions_d_exports as Instructions, Memory_d_exports as Memory, RunId_d_exports as RunId, Skill_d_exports as Skill, Specialist_d_exports as Specialist, Timeline_d_exports as Timeline, ToolApproval_d_exports as ToolApproval, ToolDiscovery_d_exports as ToolDiscovery, ToolFailure_d_exports as ToolFailure, ToolResult_d_exports as ToolResult };