effect-assistant 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +22 -2
- package/dist/AppEvent.d.ts +111 -0
- package/dist/AppEvent.d.ts.map +1 -0
- package/dist/AppEvent.js +71 -0
- package/dist/AppEvent.js.map +1 -0
- package/dist/Assistant.d.ts +403 -0
- package/dist/Assistant.d.ts.map +1 -0
- package/dist/Assistant.js +126 -0
- package/dist/Assistant.js.map +1 -0
- package/dist/AssistantActivity.d.ts +85 -0
- package/dist/AssistantActivity.d.ts.map +1 -0
- package/dist/AssistantActivity.js +105 -0
- package/dist/AssistantActivity.js.map +1 -0
- package/dist/AssistantEngine.d.ts +116 -0
- package/dist/AssistantEngine.d.ts.map +1 -0
- package/dist/AssistantEngine.js +255 -0
- package/dist/AssistantEngine.js.map +1 -0
- package/dist/AssistantEvent.d.ts +614 -0
- package/dist/AssistantEvent.d.ts.map +1 -0
- package/dist/AssistantEvent.js +523 -0
- package/dist/AssistantEvent.js.map +1 -0
- package/dist/AssistantLoop.d.ts +171 -0
- package/dist/AssistantLoop.d.ts.map +1 -0
- package/dist/AssistantLoop.js +108 -0
- package/dist/AssistantLoop.js.map +1 -0
- package/dist/AssistantToolCall.d.ts +32 -0
- package/dist/AssistantToolCall.d.ts.map +1 -0
- package/dist/AssistantToolCall.js +37 -0
- package/dist/AssistantToolCall.js.map +1 -0
- package/dist/Block.d.ts +69 -0
- package/dist/Block.d.ts.map +1 -0
- package/dist/Block.js +39 -0
- package/dist/Block.js.map +1 -0
- package/dist/BlockKit.d.ts +184 -0
- package/dist/BlockKit.d.ts.map +1 -0
- package/dist/BlockKit.js +151 -0
- package/dist/BlockKit.js.map +1 -0
- package/dist/ChatId.d.ts +31 -0
- package/dist/ChatId.d.ts.map +1 -0
- package/dist/ChatId.js +36 -0
- package/dist/ChatId.js.map +1 -0
- package/dist/ChatLog.d.ts +109 -0
- package/dist/ChatLog.d.ts.map +1 -0
- package/dist/ChatLog.js +177 -0
- package/dist/ChatLog.js.map +1 -0
- package/dist/ChatView.d.ts +459 -0
- package/dist/ChatView.d.ts.map +1 -0
- package/dist/ChatView.js +496 -0
- package/dist/ChatView.js.map +1 -0
- package/dist/Chats.d.ts +110 -0
- package/dist/Chats.d.ts.map +1 -0
- package/dist/Chats.js +98 -0
- package/dist/Chats.js.map +1 -0
- package/dist/Compaction.d.ts +105 -0
- package/dist/Compaction.d.ts.map +1 -0
- package/dist/Compaction.js +133 -0
- package/dist/Compaction.js.map +1 -0
- package/dist/CurrentChat.d.ts +40 -0
- package/dist/CurrentChat.d.ts.map +1 -0
- package/dist/CurrentChat.js +33 -0
- package/dist/CurrentChat.js.map +1 -0
- package/dist/Decision.d.ts +145 -0
- package/dist/Decision.d.ts.map +1 -0
- package/dist/Decision.js +178 -0
- package/dist/Decision.js.map +1 -0
- package/dist/DecisionId.d.ts +37 -0
- package/dist/DecisionId.d.ts.map +1 -0
- package/dist/DecisionId.js +44 -0
- package/dist/DecisionId.js.map +1 -0
- package/dist/InputId.d.ts +38 -0
- package/dist/InputId.d.ts.map +1 -0
- package/dist/InputId.js +43 -0
- package/dist/InputId.js.map +1 -0
- package/dist/Instructions.d.ts +56 -0
- package/dist/Instructions.d.ts.map +1 -0
- package/dist/Instructions.js +50 -0
- package/dist/Instructions.js.map +1 -0
- package/dist/Memory.d.ts +190 -0
- package/dist/Memory.d.ts.map +1 -0
- package/dist/Memory.js +216 -0
- package/dist/Memory.js.map +1 -0
- package/dist/RunId.d.ts +41 -0
- package/dist/RunId.d.ts.map +1 -0
- package/dist/RunId.js +46 -0
- package/dist/RunId.js.map +1 -0
- package/dist/Skill.d.ts +72 -0
- package/dist/Skill.d.ts.map +1 -0
- package/dist/Skill.js +58 -0
- package/dist/Skill.js.map +1 -0
- package/dist/Specialist.d.ts +267 -0
- package/dist/Specialist.d.ts.map +1 -0
- package/dist/Specialist.js +119 -0
- package/dist/Specialist.js.map +1 -0
- package/dist/ToolDiscovery.d.ts +108 -0
- package/dist/ToolDiscovery.d.ts.map +1 -0
- package/dist/ToolDiscovery.js +139 -0
- package/dist/ToolDiscovery.js.map +1 -0
- package/dist/ToolFailure.d.ts +66 -0
- package/dist/ToolFailure.d.ts.map +1 -0
- package/dist/ToolFailure.js +79 -0
- package/dist/ToolFailure.js.map +1 -0
- package/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +26 -0
- package/dist/internal/chat.js +202 -0
- package/dist/internal/chat.js.map +1 -0
- package/dist/internal/decisions.js +66 -0
- package/dist/internal/decisions.js.map +1 -0
- package/dist/internal/events.d.ts +46 -0
- package/dist/internal/events.d.ts.map +1 -0
- package/dist/internal/events.js +65 -0
- package/dist/internal/events.js.map +1 -0
- package/dist/internal/history.js +185 -0
- package/dist/internal/history.js.map +1 -0
- package/dist/internal/instructions.js +11 -0
- package/dist/internal/instructions.js.map +1 -0
- package/dist/internal/loop.d.ts +73 -0
- package/dist/internal/loop.d.ts.map +1 -0
- package/dist/internal/loop.js +166 -0
- package/dist/internal/loop.js.map +1 -0
- package/dist/internal/schema.js +14 -0
- package/dist/internal/schema.js.map +1 -0
- package/dist/internal/skills.js +28 -0
- package/dist/internal/skills.js.map +1 -0
- package/dist/internal/specialists.js +273 -0
- package/dist/internal/specialists.js.map +1 -0
- package/dist/internal/telemetry.js +85 -0
- package/dist/internal/telemetry.js.map +1 -0
- package/dist/internal/toolkit.d.ts +76 -0
- package/dist/internal/toolkit.d.ts.map +1 -0
- package/dist/internal/toolkit.js +129 -0
- package/dist/internal/toolkit.js.map +1 -0
- package/dist/internal/tools.js +132 -0
- package/dist/internal/tools.js.map +1 -0
- package/dist/internal/turns.d.ts +64 -0
- package/dist/internal/turns.d.ts.map +1 -0
- package/dist/internal/turns.js +221 -0
- package/dist/internal/turns.js.map +1 -0
- package/dist/internal/uuid.js +45 -0
- package/dist/internal/uuid.js.map +1 -0
- package/dist/internal/writer.d.ts +12 -0
- package/dist/internal/writer.d.ts.map +1 -0
- package/package.json +51 -3
- package/src/AppEvent.ts +134 -0
- package/src/Assistant.ts +589 -0
- package/src/AssistantActivity.ts +150 -0
- package/src/AssistantEngine.ts +343 -0
- package/src/AssistantEvent.ts +635 -0
- package/src/AssistantLoop.ts +207 -0
- package/src/AssistantToolCall.ts +40 -0
- package/src/Block.ts +84 -0
- package/src/BlockKit.ts +311 -0
- package/src/ChatId.ts +36 -0
- package/src/ChatLog.ts +247 -0
- package/src/ChatView.ts +658 -0
- package/src/Chats.ts +122 -0
- package/src/Compaction.ts +224 -0
- package/src/CurrentChat.ts +47 -0
- package/src/Decision.ts +241 -0
- package/src/DecisionId.ts +46 -0
- package/src/InputId.ts +43 -0
- package/src/Instructions.ts +72 -0
- package/src/Memory.ts +276 -0
- package/src/RunId.ts +46 -0
- package/src/Skill.ts +91 -0
- package/src/Specialist.ts +355 -0
- package/src/ToolDiscovery.ts +187 -0
- package/src/ToolFailure.ts +74 -0
- package/src/index.ts +130 -0
- package/src/internal/chat.ts +372 -0
- package/src/internal/decisions.ts +131 -0
- package/src/internal/events.ts +100 -0
- package/src/internal/history.ts +366 -0
- package/src/internal/instructions.ts +9 -0
- package/src/internal/loop.ts +344 -0
- package/src/internal/schema.ts +25 -0
- package/src/internal/skills.ts +37 -0
- package/src/internal/specialists.ts +414 -0
- package/src/internal/telemetry.ts +125 -0
- package/src/internal/toolkit.ts +231 -0
- package/src/internal/tools.ts +210 -0
- package/src/internal/turns.ts +429 -0
- package/src/internal/uuid.ts +50 -0
- package/src/internal/writer.ts +12 -0
package/dist/Memory.d.ts
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import { ChatId } from "./ChatId.js";
|
|
2
|
+
import { CurrentChat } from "./CurrentChat.js";
|
|
3
|
+
import { ToolFailure, ToolFailure_d_exports } from "./ToolFailure.js";
|
|
4
|
+
import * as Context from "effect/Context";
|
|
5
|
+
import * as Effect from "effect/Effect";
|
|
6
|
+
import * as Layer from "effect/Layer";
|
|
7
|
+
import * as Schema from "effect/Schema";
|
|
8
|
+
import * as Tool from "effect/ai/Tool";
|
|
9
|
+
import * as Toolkit from "effect/ai/Toolkit";
|
|
10
|
+
import * as DateTime from "effect/DateTime";
|
|
11
|
+
declare namespace Memory_d_exports {
|
|
12
|
+
export { Fact, MemoryStore, NewFact, Tools, layerMemory, layerTools, render };
|
|
13
|
+
}
|
|
14
|
+
declare const Fact_base: Schema.Class<Fact, Schema.Struct<{
|
|
15
|
+
readonly id: Schema.String;
|
|
16
|
+
readonly text: Schema.String;
|
|
17
|
+
readonly expiresAt: Schema.optional<Schema.DateTimeUtc>;
|
|
18
|
+
}>, {}>;
|
|
19
|
+
/**
|
|
20
|
+
* Represents a fact the assistant remembers.
|
|
21
|
+
*
|
|
22
|
+
* It holds the fact's id, one short sentence, and when the fact stops mattering, if it does.
|
|
23
|
+
*
|
|
24
|
+
* @category schemas
|
|
25
|
+
* @since 0.1.0
|
|
26
|
+
*/
|
|
27
|
+
export declare class Fact extends Fact_base {}
|
|
28
|
+
/**
|
|
29
|
+
* Represents a fact to keep, as the `remember` tool hands it to the store.
|
|
30
|
+
*
|
|
31
|
+
* @category models
|
|
32
|
+
* @since 0.1.0
|
|
33
|
+
*/
|
|
34
|
+
export interface NewFact {
|
|
35
|
+
readonly text: string;
|
|
36
|
+
readonly expiresAt?: DateTime.Utc | undefined;
|
|
37
|
+
/** The id of a fact this one replaces. */
|
|
38
|
+
readonly replaces?: string | undefined;
|
|
39
|
+
}
|
|
40
|
+
declare const MemoryStore_base: Context.ServiceClass<MemoryStore, "effect-assistant/Memory/MemoryStore", {
|
|
41
|
+
/** Returns the unexpired facts a chat should know. */
|
|
42
|
+
readonly facts: (chatId: ChatId) => Effect.Effect<ReadonlyArray<Fact>>;
|
|
43
|
+
/** Keeps a fact for the chat's owner, and returns its id. */
|
|
44
|
+
readonly remember: (chatId: ChatId, fact: NewFact) => Effect.Effect<string>;
|
|
45
|
+
/**
|
|
46
|
+
* Drops a fact. Fails with a message for the model when the chat's owner has no fact with
|
|
47
|
+
* that id.
|
|
48
|
+
*/
|
|
49
|
+
readonly forget: (chatId: ChatId, id: string) => Effect.Effect<void, ToolFailure>;
|
|
50
|
+
/** Returns the chat owner's facts that match a query, best first. */
|
|
51
|
+
readonly recall: (chatId: ChatId, query: string) => Effect.Effect<ReadonlyArray<Fact>>;
|
|
52
|
+
}>;
|
|
53
|
+
/**
|
|
54
|
+
* Service that keeps facts, implemented by the application.
|
|
55
|
+
*
|
|
56
|
+
* Every method receives the chat it's for, and the application decides whose facts that means
|
|
57
|
+
* (the chat's user, their team, ...).
|
|
58
|
+
*
|
|
59
|
+
* @category services
|
|
60
|
+
* @since 0.1.0
|
|
61
|
+
*/
|
|
62
|
+
export declare class MemoryStore extends MemoryStore_base {}
|
|
63
|
+
/**
|
|
64
|
+
* Renders facts as the model reads them, for a turn's instructions.
|
|
65
|
+
*
|
|
66
|
+
* Each fact is listed with its id, so the model can replace or forget it. The result is an empty
|
|
67
|
+
* string when there are no facts.
|
|
68
|
+
*
|
|
69
|
+
* @see {@link Tools} for an example
|
|
70
|
+
*
|
|
71
|
+
* @category utils
|
|
72
|
+
* @since 0.1.0
|
|
73
|
+
*/
|
|
74
|
+
export declare const render: (facts: ReadonlyArray<Fact>) => string;
|
|
75
|
+
/**
|
|
76
|
+
* Layer that provides a {@link MemoryStore} in memory, for tests and local runs.
|
|
77
|
+
*
|
|
78
|
+
* Every chat shares one set of facts.
|
|
79
|
+
*
|
|
80
|
+
* @category layers
|
|
81
|
+
* @since 0.1.0
|
|
82
|
+
*/
|
|
83
|
+
export declare const layerMemory: Layer.Layer<MemoryStore>;
|
|
84
|
+
/**
|
|
85
|
+
* Toolkit with the `remember`, `forget`, and `recall` tools.
|
|
86
|
+
*
|
|
87
|
+
* **Details**
|
|
88
|
+
*
|
|
89
|
+
* Merge it into the loop's toolkit, and provide {@link layerTools} and a {@link MemoryStore}. Show
|
|
90
|
+
* the facts in the turn's instructions with {@link render}.
|
|
91
|
+
*
|
|
92
|
+
* **Example** (Giving an assistant memory)
|
|
93
|
+
*
|
|
94
|
+
* ```ts
|
|
95
|
+
* import { Assistant, Memory } from "effect-assistant"
|
|
96
|
+
* import * as Effect from "effect/Effect"
|
|
97
|
+
* import * as Layer from "effect/Layer"
|
|
98
|
+
* import * as Stream from "effect/Stream"
|
|
99
|
+
*
|
|
100
|
+
* export const MyAssistant = Assistant.make("my-assistant")
|
|
101
|
+
*
|
|
102
|
+
* const MyAssistantLive = MyAssistant.toLayer(
|
|
103
|
+
* Effect.gen(function* () {
|
|
104
|
+
* const memory = yield* Memory.MemoryStore
|
|
105
|
+
*
|
|
106
|
+
* return (turn) =>
|
|
107
|
+
* Stream.unwrap(
|
|
108
|
+
* Effect.map(memory.facts(turn.chatId), (facts) =>
|
|
109
|
+
* turn.loop({
|
|
110
|
+
* instructions: `You help a small team.\n\n${Memory.render(facts)}`,
|
|
111
|
+
* toolkit: Memory.Tools
|
|
112
|
+
* })
|
|
113
|
+
* )
|
|
114
|
+
* ).pipe(Stream.provideService(Memory.MemoryStore, memory))
|
|
115
|
+
* })
|
|
116
|
+
* ).pipe(Layer.provide(Memory.layerTools), Layer.provide(Memory.layerMemory))
|
|
117
|
+
* ```
|
|
118
|
+
*
|
|
119
|
+
* @category tools
|
|
120
|
+
* @since 0.1.0
|
|
121
|
+
*/
|
|
122
|
+
export declare const Tools: Toolkit.Toolkit<{
|
|
123
|
+
readonly forget: Tool.Tool<"forget", {
|
|
124
|
+
readonly parameters: Schema.Struct<{
|
|
125
|
+
readonly id: Schema.String;
|
|
126
|
+
}>;
|
|
127
|
+
readonly success: Schema.String;
|
|
128
|
+
readonly failure: typeof ToolFailure;
|
|
129
|
+
readonly failureMode: "error";
|
|
130
|
+
}, CurrentChat | MemoryStore>;
|
|
131
|
+
readonly recall: Tool.Tool<"recall", {
|
|
132
|
+
readonly parameters: Schema.Struct<{
|
|
133
|
+
readonly query: Schema.String;
|
|
134
|
+
}>;
|
|
135
|
+
readonly success: Schema.$Array<Schema.String>;
|
|
136
|
+
readonly failure: typeof ToolFailure;
|
|
137
|
+
readonly failureMode: "error";
|
|
138
|
+
}, CurrentChat | MemoryStore>;
|
|
139
|
+
readonly remember: Tool.Tool<"remember", {
|
|
140
|
+
readonly parameters: Schema.Struct<{
|
|
141
|
+
readonly text: Schema.String;
|
|
142
|
+
readonly until: Schema.optional<Schema.String>;
|
|
143
|
+
readonly replaces: Schema.optional<Schema.String>;
|
|
144
|
+
}>;
|
|
145
|
+
readonly success: Schema.String;
|
|
146
|
+
readonly failure: typeof ToolFailure;
|
|
147
|
+
readonly failureMode: "error";
|
|
148
|
+
}, CurrentChat | MemoryStore>;
|
|
149
|
+
}>;
|
|
150
|
+
/**
|
|
151
|
+
* Layer that provides the handlers of {@link Tools}.
|
|
152
|
+
*
|
|
153
|
+
* The handlers call the {@link MemoryStore} with the chat they run in.
|
|
154
|
+
*
|
|
155
|
+
* @see {@link Tools} for an example
|
|
156
|
+
*
|
|
157
|
+
* @category layers
|
|
158
|
+
* @since 0.1.0
|
|
159
|
+
*/
|
|
160
|
+
export declare const layerTools: Layer.Layer<Tool.HandlersFor<{
|
|
161
|
+
readonly forget: Tool.Tool<"forget", {
|
|
162
|
+
readonly parameters: Schema.Struct<{
|
|
163
|
+
readonly id: Schema.String;
|
|
164
|
+
}>;
|
|
165
|
+
readonly success: Schema.String;
|
|
166
|
+
readonly failure: typeof ToolFailure;
|
|
167
|
+
readonly failureMode: "error";
|
|
168
|
+
}, CurrentChat | MemoryStore>;
|
|
169
|
+
readonly recall: Tool.Tool<"recall", {
|
|
170
|
+
readonly parameters: Schema.Struct<{
|
|
171
|
+
readonly query: Schema.String;
|
|
172
|
+
}>;
|
|
173
|
+
readonly success: Schema.$Array<Schema.String>;
|
|
174
|
+
readonly failure: typeof ToolFailure;
|
|
175
|
+
readonly failureMode: "error";
|
|
176
|
+
}, CurrentChat | MemoryStore>;
|
|
177
|
+
readonly remember: Tool.Tool<"remember", {
|
|
178
|
+
readonly parameters: Schema.Struct<{
|
|
179
|
+
readonly text: Schema.String;
|
|
180
|
+
readonly until: Schema.optional<Schema.String>;
|
|
181
|
+
readonly replaces: Schema.optional<Schema.String>;
|
|
182
|
+
}>;
|
|
183
|
+
readonly success: Schema.String;
|
|
184
|
+
readonly failure: typeof ToolFailure;
|
|
185
|
+
readonly failureMode: "error";
|
|
186
|
+
}, CurrentChat | MemoryStore>;
|
|
187
|
+
}>, never, never>;
|
|
188
|
+
//#endregion
|
|
189
|
+
export { Memory_d_exports };
|
|
190
|
+
//# sourceMappingURL=Memory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Memory.d.ts","names":[],"sources":["../src/Memory.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;qBAiCa,aAAa;;;;;;;iBAYT;WACN;WACA,YAAY,SAAS;;WAErB;;;;WAgBS,QAAC,QAAQ,WAAW,OAAO,OAAO,cAAc;;WAE7C,WAAC,QAAQ,QAAQ,MAAM,YAAY,OAAO;;;;;WAK5C,SAAC,QAAQ,QAAQ,eAAe,OAAO,aAAa;;WAEpD,SAAC,QAAQ,QAAQ,kBAAkB,OAAO,OAAO,cAAc;;;;;;;;;;;qBAbvE,oBAAoB;;;;;;;;;;;;qBAiCpB,SAAM,OAAW,cAAc;;;;;;;;;qBA4B/B,aAAa,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA+GzB,OAAK,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAeL,YAAU,MAAA,MAAA,KAAA"}
|
package/dist/Memory.js
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { make } from "./internal/uuid.js";
|
|
3
|
+
import { CurrentChat } from "./CurrentChat.js";
|
|
4
|
+
import { ToolFailure, fail } from "./ToolFailure.js";
|
|
5
|
+
import * as Context from "effect/Context";
|
|
6
|
+
import * as Effect from "effect/Effect";
|
|
7
|
+
import * as Layer from "effect/Layer";
|
|
8
|
+
import * as Schema from "effect/Schema";
|
|
9
|
+
import * as Option from "effect/Option";
|
|
10
|
+
import * as Clock from "effect/Clock";
|
|
11
|
+
import * as Ref from "effect/Ref";
|
|
12
|
+
import * as Tool from "effect/ai/Tool";
|
|
13
|
+
import * as Toolkit from "effect/ai/Toolkit";
|
|
14
|
+
import * as DateTime from "effect/DateTime";
|
|
15
|
+
//#region src/Memory.ts
|
|
16
|
+
/**
|
|
17
|
+
* Keeps facts an assistant remembers across chats.
|
|
18
|
+
*
|
|
19
|
+
* The model keeps facts with the `remember` tool, finds them with `recall`, and drops them with
|
|
20
|
+
* `forget` ({@link Tools}). Where facts are stored and who shares them is up to the application,
|
|
21
|
+
* which implements {@link MemoryStore}; every method receives the chat it's for. {@link render}
|
|
22
|
+
* shows the facts in a turn's instructions.
|
|
23
|
+
*
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*/
|
|
26
|
+
var Memory_exports = /* @__PURE__ */ __exportAll({
|
|
27
|
+
Fact: () => Fact,
|
|
28
|
+
MemoryStore: () => MemoryStore,
|
|
29
|
+
Tools: () => Tools,
|
|
30
|
+
layerMemory: () => layerMemory,
|
|
31
|
+
layerTools: () => layerTools,
|
|
32
|
+
render: () => render
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Represents a fact the assistant remembers.
|
|
36
|
+
*
|
|
37
|
+
* It holds the fact's id, one short sentence, and when the fact stops mattering, if it does.
|
|
38
|
+
*
|
|
39
|
+
* @category schemas
|
|
40
|
+
* @since 0.1.0
|
|
41
|
+
*/
|
|
42
|
+
var Fact = class extends Schema.Class("effect-assistant/Memory/Fact")({
|
|
43
|
+
id: Schema.String,
|
|
44
|
+
text: Schema.String,
|
|
45
|
+
expiresAt: Schema.optional(Schema.DateTimeUtc)
|
|
46
|
+
}) {};
|
|
47
|
+
/**
|
|
48
|
+
* Service that keeps facts, implemented by the application.
|
|
49
|
+
*
|
|
50
|
+
* Every method receives the chat it's for, and the application decides whose facts that means
|
|
51
|
+
* (the chat's user, their team, ...).
|
|
52
|
+
*
|
|
53
|
+
* @category services
|
|
54
|
+
* @since 0.1.0
|
|
55
|
+
*/
|
|
56
|
+
var MemoryStore = class extends Context.Service()("effect-assistant/Memory/MemoryStore") {};
|
|
57
|
+
const day = (at) => DateTime.formatIsoDateUtc(at);
|
|
58
|
+
const line = (fact) => `- [${fact.id}] ${fact.text}${fact.expiresAt === void 0 ? "" : ` (until ${day(fact.expiresAt)})`}`;
|
|
59
|
+
/**
|
|
60
|
+
* Renders facts as the model reads them, for a turn's instructions.
|
|
61
|
+
*
|
|
62
|
+
* Each fact is listed with its id, so the model can replace or forget it. The result is an empty
|
|
63
|
+
* string when there are no facts.
|
|
64
|
+
*
|
|
65
|
+
* @see {@link Tools} for an example
|
|
66
|
+
*
|
|
67
|
+
* @category utils
|
|
68
|
+
* @since 0.1.0
|
|
69
|
+
*/
|
|
70
|
+
const render = (facts) => facts.length === 0 ? "" : `<memory>\nWhat you remember from earlier chats. Use it without saying where it came from; when their data or what they say now disagrees, that wins.\n${facts.map(line).join("\n")}\n</memory>`;
|
|
71
|
+
const words = (text) => text.toLowerCase().split(/[^\p{L}\p{N}]+/u).filter((word) => word.length > 2);
|
|
72
|
+
const matches = (fact, query) => {
|
|
73
|
+
const own = words(fact.text);
|
|
74
|
+
return query.filter((word) => own.some((w) => w.startsWith(word) || word.startsWith(w))).length;
|
|
75
|
+
};
|
|
76
|
+
const live = (now) => (fact) => fact.expiresAt === void 0 || DateTime.toEpochMillis(fact.expiresAt) > now;
|
|
77
|
+
/**
|
|
78
|
+
* Layer that provides a {@link MemoryStore} in memory, for tests and local runs.
|
|
79
|
+
*
|
|
80
|
+
* Every chat shares one set of facts.
|
|
81
|
+
*
|
|
82
|
+
* @category layers
|
|
83
|
+
* @since 0.1.0
|
|
84
|
+
*/
|
|
85
|
+
const layerMemory = Layer.effect(MemoryStore, Effect.gen(function* () {
|
|
86
|
+
const all = yield* Ref.make([]);
|
|
87
|
+
const current = Effect.gen(function* () {
|
|
88
|
+
const now = yield* Clock.currentTimeMillis;
|
|
89
|
+
return (yield* Ref.get(all)).filter(live(now));
|
|
90
|
+
});
|
|
91
|
+
return MemoryStore.of({
|
|
92
|
+
facts: () => current,
|
|
93
|
+
remember: Effect.fnUntraced(function* (_chatId, fact) {
|
|
94
|
+
const id = (yield* current).find((kept) => kept.text === fact.text.trim())?.id ?? `f-${(yield* make).slice(0, 8)}`;
|
|
95
|
+
const kept = new Fact({
|
|
96
|
+
id,
|
|
97
|
+
text: fact.text.trim(),
|
|
98
|
+
expiresAt: fact.expiresAt
|
|
99
|
+
});
|
|
100
|
+
yield* Ref.update(all, (facts) => [kept, ...facts.filter((old) => old.id !== id && old.id !== fact.replaces)]);
|
|
101
|
+
return id;
|
|
102
|
+
}),
|
|
103
|
+
forget: Effect.fnUntraced(function* (_chatId, id) {
|
|
104
|
+
if (!(yield* current).some((fact) => fact.id === id)) return yield* fail(`Nothing remembered as ${id}.`);
|
|
105
|
+
yield* Ref.update(all, (facts) => facts.filter((fact) => fact.id !== id));
|
|
106
|
+
}),
|
|
107
|
+
recall: Effect.fnUntraced(function* (_chatId, query) {
|
|
108
|
+
const wanted = words(query);
|
|
109
|
+
return (yield* current).map((fact) => ({
|
|
110
|
+
fact,
|
|
111
|
+
score: matches(fact, wanted)
|
|
112
|
+
})).filter(({ score }) => score > 0).sort((a, b) => b.score - a.score).slice(0, 10).map(({ fact }) => fact);
|
|
113
|
+
})
|
|
114
|
+
});
|
|
115
|
+
}));
|
|
116
|
+
const Remember = Tool.make("remember", {
|
|
117
|
+
description: `Remember something for later chats. Only what you can't look up again and that will still matter: a preference, a standing decision, how they like to work ("Rotterdam's copy is always Dutch"). For something short-lived ("out of office until Friday"), pass until. Not records your tools can read (orders, locations, budgets, people), not the state of a task in progress, and nothing you'd only need in this chat. One fact per call, in one short sentence that stands on its own. When it changes one you already have, pass that one's id as replaces.`,
|
|
118
|
+
parameters: Schema.Struct({
|
|
119
|
+
text: Schema.String,
|
|
120
|
+
until: Schema.optional(Schema.String).annotate({ description: "For something short-lived: the last day it matters, as YYYY-MM-DD." }),
|
|
121
|
+
replaces: Schema.optional(Schema.String).annotate({ description: "The id of a fact this one replaces." })
|
|
122
|
+
}),
|
|
123
|
+
success: Schema.String,
|
|
124
|
+
failure: ToolFailure,
|
|
125
|
+
dependencies: [CurrentChat, MemoryStore]
|
|
126
|
+
});
|
|
127
|
+
const Forget = Tool.make("forget", {
|
|
128
|
+
description: "Forget a fact you remember, by its id, when they ask or it's no longer true.",
|
|
129
|
+
parameters: Schema.Struct({ id: Schema.String }),
|
|
130
|
+
success: Schema.String,
|
|
131
|
+
failure: ToolFailure,
|
|
132
|
+
dependencies: [CurrentChat, MemoryStore]
|
|
133
|
+
});
|
|
134
|
+
const Recall = Tool.make("recall", {
|
|
135
|
+
description: "Search what you remember, by words that would be in it.",
|
|
136
|
+
parameters: Schema.Struct({ query: Schema.String }),
|
|
137
|
+
success: Schema.Array(Schema.String),
|
|
138
|
+
failure: ToolFailure,
|
|
139
|
+
dependencies: [CurrentChat, MemoryStore]
|
|
140
|
+
});
|
|
141
|
+
/**
|
|
142
|
+
* Toolkit with the `remember`, `forget`, and `recall` tools.
|
|
143
|
+
*
|
|
144
|
+
* **Details**
|
|
145
|
+
*
|
|
146
|
+
* Merge it into the loop's toolkit, and provide {@link layerTools} and a {@link MemoryStore}. Show
|
|
147
|
+
* the facts in the turn's instructions with {@link render}.
|
|
148
|
+
*
|
|
149
|
+
* **Example** (Giving an assistant memory)
|
|
150
|
+
*
|
|
151
|
+
* ```ts
|
|
152
|
+
* import { Assistant, Memory } from "effect-assistant"
|
|
153
|
+
* import * as Effect from "effect/Effect"
|
|
154
|
+
* import * as Layer from "effect/Layer"
|
|
155
|
+
* import * as Stream from "effect/Stream"
|
|
156
|
+
*
|
|
157
|
+
* export const MyAssistant = Assistant.make("my-assistant")
|
|
158
|
+
*
|
|
159
|
+
* const MyAssistantLive = MyAssistant.toLayer(
|
|
160
|
+
* Effect.gen(function* () {
|
|
161
|
+
* const memory = yield* Memory.MemoryStore
|
|
162
|
+
*
|
|
163
|
+
* return (turn) =>
|
|
164
|
+
* Stream.unwrap(
|
|
165
|
+
* Effect.map(memory.facts(turn.chatId), (facts) =>
|
|
166
|
+
* turn.loop({
|
|
167
|
+
* instructions: `You help a small team.\n\n${Memory.render(facts)}`,
|
|
168
|
+
* toolkit: Memory.Tools
|
|
169
|
+
* })
|
|
170
|
+
* )
|
|
171
|
+
* ).pipe(Stream.provideService(Memory.MemoryStore, memory))
|
|
172
|
+
* })
|
|
173
|
+
* ).pipe(Layer.provide(Memory.layerTools), Layer.provide(Memory.layerMemory))
|
|
174
|
+
* ```
|
|
175
|
+
*
|
|
176
|
+
* @category tools
|
|
177
|
+
* @since 0.1.0
|
|
178
|
+
*/
|
|
179
|
+
const Tools = Toolkit.make(Remember, Forget, Recall);
|
|
180
|
+
const endOf = (date) => /^\d{4}-\d{2}-\d{2}$/.test(date) ? DateTime.make(`${date}T23:59:59Z`) : Option.none();
|
|
181
|
+
/**
|
|
182
|
+
* Layer that provides the handlers of {@link Tools}.
|
|
183
|
+
*
|
|
184
|
+
* The handlers call the {@link MemoryStore} with the chat they run in.
|
|
185
|
+
*
|
|
186
|
+
* @see {@link Tools} for an example
|
|
187
|
+
*
|
|
188
|
+
* @category layers
|
|
189
|
+
* @since 0.1.0
|
|
190
|
+
*/
|
|
191
|
+
const layerTools = Tools.toLayer({
|
|
192
|
+
remember: Effect.fnUntraced(function* ({ text, until, replaces }) {
|
|
193
|
+
const chat = yield* CurrentChat;
|
|
194
|
+
const store = yield* MemoryStore;
|
|
195
|
+
const expiresAt = until === void 0 ? Option.none() : endOf(until);
|
|
196
|
+
if (until !== void 0 && Option.isNone(expiresAt)) return yield* fail(`until must be a date as YYYY-MM-DD, not ${until}.`);
|
|
197
|
+
return `Remembered as ${yield* store.remember(chat.chatId, {
|
|
198
|
+
text,
|
|
199
|
+
expiresAt: Option.getOrUndefined(expiresAt),
|
|
200
|
+
replaces
|
|
201
|
+
})}.`;
|
|
202
|
+
}),
|
|
203
|
+
forget: Effect.fnUntraced(function* ({ id }) {
|
|
204
|
+
const chat = yield* CurrentChat;
|
|
205
|
+
yield* (yield* MemoryStore).forget(chat.chatId, id);
|
|
206
|
+
return `Forgot ${id}.`;
|
|
207
|
+
}),
|
|
208
|
+
recall: Effect.fnUntraced(function* ({ query }) {
|
|
209
|
+
const chat = yield* CurrentChat;
|
|
210
|
+
return (yield* (yield* MemoryStore).recall(chat.chatId, query)).map(line);
|
|
211
|
+
})
|
|
212
|
+
});
|
|
213
|
+
//#endregion
|
|
214
|
+
export { Fact, MemoryStore, Memory_exports, Tools, layerMemory, layerTools, render };
|
|
215
|
+
|
|
216
|
+
//# sourceMappingURL=Memory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Memory.js","names":["Uuid.make","ToolFailure.fail","ToolFailure.ToolFailure"],"sources":["../src/Memory.ts"],"sourcesContent":["/**\n * Keeps facts an assistant remembers across chats.\n *\n * The model keeps facts with the `remember` tool, finds them with `recall`, and drops them with\n * `forget` ({@link Tools}). Where facts are stored and who shares them is up to the application,\n * which implements {@link MemoryStore}; every method receives the chat it's for. {@link render}\n * shows the facts in a turn's instructions.\n *\n * @since 0.1.0\n */\nimport * as Tool from \"effect/ai/Tool\"\nimport * as Toolkit from \"effect/ai/Toolkit\"\nimport * as Clock from \"effect/Clock\"\nimport * as Context from \"effect/Context\"\nimport * as DateTime from \"effect/DateTime\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Option from \"effect/Option\"\nimport * as Ref from \"effect/Ref\"\nimport * as Schema from \"effect/Schema\"\nimport type { ChatId } from \"./ChatId.ts\"\nimport { CurrentChat } from \"./CurrentChat.ts\"\nimport * as Uuid from \"./internal/uuid.ts\"\nimport * as ToolFailure from \"./ToolFailure.ts\"\n\n/**\n * Represents a fact the assistant remembers.\n *\n * It holds the fact's id, one short sentence, and when the fact stops mattering, if it does.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport class Fact extends Schema.Class<Fact>(\"effect-assistant/Memory/Fact\")({\n id: Schema.String,\n text: Schema.String,\n expiresAt: Schema.optional(Schema.DateTimeUtc)\n}) {}\n\n/**\n * Represents a fact to keep, as the `remember` tool hands it to the store.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface NewFact {\n readonly text: string\n readonly expiresAt?: DateTime.Utc | undefined\n /** The id of a fact this one replaces. */\n readonly replaces?: string | undefined\n}\n\n/**\n * Service that keeps facts, implemented by the application.\n *\n * Every method receives the chat it's for, and the application decides whose facts that means\n * (the chat's user, their team, ...).\n *\n * @category services\n * @since 0.1.0\n */\nexport class MemoryStore extends Context.Service<\n MemoryStore,\n {\n /** Returns the unexpired facts a chat should know. */\n readonly facts: (chatId: ChatId) => Effect.Effect<ReadonlyArray<Fact>>\n /** Keeps a fact for the chat's owner, and returns its id. */\n readonly remember: (chatId: ChatId, fact: NewFact) => Effect.Effect<string>\n /**\n * Drops a fact. Fails with a message for the model when the chat's owner has no fact with\n * that id.\n */\n readonly forget: (chatId: ChatId, id: string) => Effect.Effect<void, ToolFailure.ToolFailure>\n /** Returns the chat owner's facts that match a query, best first. */\n readonly recall: (chatId: ChatId, query: string) => Effect.Effect<ReadonlyArray<Fact>>\n }\n>()(\"effect-assistant/Memory/MemoryStore\") {}\n\nconst day = (at: DateTime.Utc): string => DateTime.formatIsoDateUtc(at)\n\nconst line = (fact: Fact): string =>\n `- [${fact.id}] ${fact.text}${fact.expiresAt === undefined ? \"\" : ` (until ${day(fact.expiresAt)})`}`\n\n/**\n * Renders facts as the model reads them, for a turn's instructions.\n *\n * Each fact is listed with its id, so the model can replace or forget it. The result is an empty\n * string when there are no facts.\n *\n * @see {@link Tools} for an example\n *\n * @category utils\n * @since 0.1.0\n */\nexport const render = (facts: ReadonlyArray<Fact>): string =>\n facts.length === 0\n ? \"\"\n : `<memory>\\nWhat you remember from earlier chats. Use it without saying where it came from; when their data or what they say now disagrees, that wins.\\n${facts.map(line).join(\"\\n\")}\\n</memory>`\n\nconst words = (text: string): ReadonlyArray<string> =>\n text\n .toLowerCase()\n .split(/[^\\p{L}\\p{N}]+/u)\n .filter((word) => word.length > 2)\n\nconst matches = (fact: Fact, query: ReadonlyArray<string>): number => {\n const own = words(fact.text)\n\n return query.filter((word) => own.some((w) => w.startsWith(word) || word.startsWith(w))).length\n}\n\nconst live = (now: number) => (fact: Fact) =>\n fact.expiresAt === undefined || DateTime.toEpochMillis(fact.expiresAt) > now\n\n/**\n * Layer that provides a {@link MemoryStore} in memory, for tests and local runs.\n *\n * Every chat shares one set of facts.\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layerMemory: Layer.Layer<MemoryStore> = Layer.effect(\n MemoryStore,\n Effect.gen(function* () {\n // Newest first.\n const all = yield* Ref.make<ReadonlyArray<Fact>>([])\n\n const current = Effect.gen(function* () {\n const now = yield* Clock.currentTimeMillis\n\n return (yield* Ref.get(all)).filter(live(now))\n })\n\n return MemoryStore.of({\n facts: () => current,\n remember: Effect.fnUntraced(function* (_chatId: ChatId, fact: NewFact) {\n const same = (yield* current).find((kept) => kept.text === fact.text.trim())\n const id = same?.id ?? `f-${(yield* Uuid.make).slice(0, 8)}`\n const kept = new Fact({ id, text: fact.text.trim(), expiresAt: fact.expiresAt })\n\n yield* Ref.update(all, (facts) => [kept, ...facts.filter((old) => old.id !== id && old.id !== fact.replaces)])\n\n return id\n }),\n forget: Effect.fnUntraced(function* (_chatId: ChatId, id: string) {\n if (!(yield* current).some((fact) => fact.id === id))\n return yield* ToolFailure.fail(`Nothing remembered as ${id}.`)\n\n yield* Ref.update(all, (facts) => facts.filter((fact) => fact.id !== id))\n }),\n recall: Effect.fnUntraced(function* (_chatId: ChatId, query: string) {\n const wanted = words(query)\n\n return (yield* current)\n .map((fact) => ({ fact, score: matches(fact, wanted) }))\n .filter(({ score }) => score > 0)\n .sort((a, b) => b.score - a.score)\n .slice(0, 10)\n .map(({ fact }) => fact)\n })\n })\n })\n)\n\nconst Remember = Tool.make(\"remember\", {\n description: `Remember something for later chats. Only what you can't look up again and that will still matter: a preference, a standing decision, how they like to work (\"Rotterdam's copy is always Dutch\"). For something short-lived (\"out of office until Friday\"), pass until. Not records your tools can read (orders, locations, budgets, people), not the state of a task in progress, and nothing you'd only need in this chat. One fact per call, in one short sentence that stands on its own. When it changes one you already have, pass that one's id as replaces.`,\n parameters: Schema.Struct({\n text: Schema.String,\n until: Schema.optional(Schema.String).annotate({\n description: \"For something short-lived: the last day it matters, as YYYY-MM-DD.\"\n }),\n replaces: Schema.optional(Schema.String).annotate({ description: \"The id of a fact this one replaces.\" })\n }),\n success: Schema.String,\n failure: ToolFailure.ToolFailure,\n dependencies: [CurrentChat, MemoryStore]\n})\n\nconst Forget = Tool.make(\"forget\", {\n description: \"Forget a fact you remember, by its id, when they ask or it's no longer true.\",\n parameters: Schema.Struct({ id: Schema.String }),\n success: Schema.String,\n failure: ToolFailure.ToolFailure,\n dependencies: [CurrentChat, MemoryStore]\n})\n\nconst Recall = Tool.make(\"recall\", {\n description: \"Search what you remember, by words that would be in it.\",\n parameters: Schema.Struct({ query: Schema.String }),\n success: Schema.Array(Schema.String),\n failure: ToolFailure.ToolFailure,\n dependencies: [CurrentChat, MemoryStore]\n})\n\n/**\n * Toolkit with the `remember`, `forget`, and `recall` tools.\n *\n * **Details**\n *\n * Merge it into the loop's toolkit, and provide {@link layerTools} and a {@link MemoryStore}. Show\n * the facts in the turn's instructions with {@link render}.\n *\n * **Example** (Giving an assistant memory)\n *\n * ```ts\n * import { Assistant, Memory } from \"effect-assistant\"\n * import * as Effect from \"effect/Effect\"\n * import * as Layer from \"effect/Layer\"\n * import * as Stream from \"effect/Stream\"\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * const MyAssistantLive = MyAssistant.toLayer(\n * Effect.gen(function* () {\n * const memory = yield* Memory.MemoryStore\n *\n * return (turn) =>\n * Stream.unwrap(\n * Effect.map(memory.facts(turn.chatId), (facts) =>\n * turn.loop({\n * instructions: `You help a small team.\\n\\n${Memory.render(facts)}`,\n * toolkit: Memory.Tools\n * })\n * )\n * ).pipe(Stream.provideService(Memory.MemoryStore, memory))\n * })\n * ).pipe(Layer.provide(Memory.layerTools), Layer.provide(Memory.layerMemory))\n * ```\n *\n * @category tools\n * @since 0.1.0\n */\nexport const Tools = Toolkit.make(Remember, Forget, Recall)\n\nconst endOf = (date: string): Option.Option<DateTime.Utc> =>\n /^\\d{4}-\\d{2}-\\d{2}$/.test(date) ? DateTime.make(`${date}T23:59:59Z`) : Option.none()\n\n/**\n * Layer that provides the handlers of {@link Tools}.\n *\n * The handlers call the {@link MemoryStore} with the chat they run in.\n *\n * @see {@link Tools} for an example\n *\n * @category layers\n * @since 0.1.0\n */\nexport const layerTools = Tools.toLayer({\n remember: Effect.fnUntraced(function* ({ text, until, replaces }) {\n const chat = yield* CurrentChat\n const store = yield* MemoryStore\n const expiresAt = until === undefined ? Option.none() : endOf(until)\n\n if (until !== undefined && Option.isNone(expiresAt)) {\n return yield* ToolFailure.fail(`until must be a date as YYYY-MM-DD, not ${until}.`)\n }\n\n const id = yield* store.remember(chat.chatId, { text, expiresAt: Option.getOrUndefined(expiresAt), replaces })\n\n return `Remembered as ${id}.`\n }),\n forget: Effect.fnUntraced(function* ({ id }) {\n const chat = yield* CurrentChat\n\n yield* (yield* MemoryStore).forget(chat.chatId, id)\n\n return `Forgot ${id}.`\n }),\n recall: Effect.fnUntraced(function* ({ query }) {\n const chat = yield* CurrentChat\n const found = yield* (yield* MemoryStore).recall(chat.chatId, query)\n\n return found.map(line)\n })\n})\n"],"mappings":"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"}
|
package/dist/RunId.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import * as Effect from "effect/Effect";
|
|
2
|
+
import * as Schema from "effect/Schema";
|
|
3
|
+
declare namespace RunId_d_exports {
|
|
4
|
+
export { RunId, fromKey, make };
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Schema for run ids of the form `` `run:${uuid}` ``, branded.
|
|
8
|
+
*
|
|
9
|
+
* @category schemas
|
|
10
|
+
* @since 0.1.0
|
|
11
|
+
*/
|
|
12
|
+
export declare const RunId: Schema.brand<Schema.TemplateLiteral<readonly ["run:", Schema.String]>, "~effect-assistant/RunId">;
|
|
13
|
+
/**
|
|
14
|
+
* Represents a run id.
|
|
15
|
+
*
|
|
16
|
+
* @category models
|
|
17
|
+
* @since 0.1.0
|
|
18
|
+
*/
|
|
19
|
+
export type RunId = typeof RunId.Type;
|
|
20
|
+
/**
|
|
21
|
+
* Creates a new random run id using Effect's `Random`.
|
|
22
|
+
*
|
|
23
|
+
* @category constructors
|
|
24
|
+
* @since 0.1.0
|
|
25
|
+
*/
|
|
26
|
+
export declare const make: () => Effect.Effect<RunId>;
|
|
27
|
+
/**
|
|
28
|
+
* Creates the run id for a key. The same key always gives the same id.
|
|
29
|
+
*
|
|
30
|
+
* **When to use**
|
|
31
|
+
*
|
|
32
|
+
* Use it for a run that a tool call starts, with the call's `AssistantToolCall.idempotencyKey` as
|
|
33
|
+
* the key, so running the call again finds the same run.
|
|
34
|
+
*
|
|
35
|
+
* @category constructors
|
|
36
|
+
* @since 0.1.0
|
|
37
|
+
*/
|
|
38
|
+
export declare const fromKey: (key: string) => RunId;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { RunId_d_exports };
|
|
41
|
+
//# sourceMappingURL=RunId.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunId.d.ts","names":[],"sources":["../src/RunId.ts"],"mappings":";;;;;;;;;;;qBAgBa,OAAK,OAAA,MAAA,OAAA,kCAAA,OAAA;;;;;;;YAQN,eAAe,MAAM;;;;;;;qBAQpB,YAAW,OAAO,OAAO;;;;;;;;;;;;qBAazB,UAAO,gBAAkB"}
|
package/dist/RunId.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import { Uuid, fromKey as fromKey$1, make as make$1 } from "./internal/uuid.js";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Schema from "effect/Schema";
|
|
5
|
+
//#region src/RunId.ts
|
|
6
|
+
/**
|
|
7
|
+
* This module provides the id of a background run, such as a specialist run or a workflow started
|
|
8
|
+
* from a tool. A run id is `run:` followed by a UUID.
|
|
9
|
+
*
|
|
10
|
+
* @since 0.1.0
|
|
11
|
+
*/
|
|
12
|
+
var RunId_exports = /* @__PURE__ */ __exportAll({
|
|
13
|
+
RunId: () => RunId,
|
|
14
|
+
fromKey: () => fromKey,
|
|
15
|
+
make: () => make
|
|
16
|
+
});
|
|
17
|
+
/**
|
|
18
|
+
* Schema for run ids of the form `` `run:${uuid}` ``, branded.
|
|
19
|
+
*
|
|
20
|
+
* @category schemas
|
|
21
|
+
* @since 0.1.0
|
|
22
|
+
*/
|
|
23
|
+
const RunId = Schema.TemplateLiteral(["run:", Uuid]).pipe(Schema.brand("~effect-assistant/RunId"));
|
|
24
|
+
/**
|
|
25
|
+
* Creates a new random run id using Effect's `Random`.
|
|
26
|
+
*
|
|
27
|
+
* @category constructors
|
|
28
|
+
* @since 0.1.0
|
|
29
|
+
*/
|
|
30
|
+
const make = () => Effect.map(make$1, (uuid) => RunId.make(`run:${uuid}`));
|
|
31
|
+
/**
|
|
32
|
+
* Creates the run id for a key. The same key always gives the same id.
|
|
33
|
+
*
|
|
34
|
+
* **When to use**
|
|
35
|
+
*
|
|
36
|
+
* Use it for a run that a tool call starts, with the call's `AssistantToolCall.idempotencyKey` as
|
|
37
|
+
* the key, so running the call again finds the same run.
|
|
38
|
+
*
|
|
39
|
+
* @category constructors
|
|
40
|
+
* @since 0.1.0
|
|
41
|
+
*/
|
|
42
|
+
const fromKey = (key) => RunId.make(`run:${fromKey$1(key)}`);
|
|
43
|
+
//#endregion
|
|
44
|
+
export { RunId, RunId_exports, fromKey, make };
|
|
45
|
+
|
|
46
|
+
//# sourceMappingURL=RunId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RunId.js","names":["Uuid.Uuid","Uuid.make","Uuid.fromKey"],"sources":["../src/RunId.ts"],"sourcesContent":["/**\n * This module provides the id of a background run, such as a specialist run or a workflow started\n * from a tool. A run id is `run:` followed by a UUID.\n *\n * @since 0.1.0\n */\nimport * as Effect from \"effect/Effect\"\nimport * as Schema from \"effect/Schema\"\nimport * as Uuid from \"./internal/uuid.ts\"\n\n/**\n * Schema for run ids of the form `` `run:${uuid}` ``, branded.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const RunId = Schema.TemplateLiteral([\"run:\", Uuid.Uuid]).pipe(Schema.brand(\"~effect-assistant/RunId\"))\n\n/**\n * Represents a run id.\n *\n * @category models\n * @since 0.1.0\n */\nexport type RunId = typeof RunId.Type\n\n/**\n * Creates a new random run id using Effect's `Random`.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = (): Effect.Effect<RunId> => Effect.map(Uuid.make, (uuid) => RunId.make(`run:${uuid}`))\n\n/**\n * Creates the run id for a key. The same key always gives the same id.\n *\n * **When to use**\n *\n * Use it for a run that a tool call starts, with the call's `AssistantToolCall.idempotencyKey` as\n * the key, so running the call again finds the same run.\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const fromKey = (key: string): RunId => RunId.make(`run:${Uuid.fromKey(key)}`)\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAgBA,MAAa,QAAQ,OAAO,gBAAgB,CAAC,QAAQA,IAAS,CAAC,CAAC,CAAC,KAAK,OAAO,MAAM,yBAAyB,CAAC;;;;;;;AAgB7G,MAAa,aAAmC,OAAO,IAAIC,SAAY,SAAS,MAAM,KAAK,OAAO,MAAM,CAAC;;;;;;;;;;;;AAazG,MAAa,WAAW,QAAuB,MAAM,KAAK,OAAOC,UAAa,GAAG,GAAG"}
|
package/dist/Skill.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { Instructions, Instructions_d_exports } from "./Instructions.js";
|
|
2
|
+
declare namespace Skill_d_exports {
|
|
3
|
+
export { Services, Skill, make, withCatalog };
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Represents a skill.
|
|
7
|
+
*
|
|
8
|
+
* `R` is the services its instructions need when they're loaded.
|
|
9
|
+
*
|
|
10
|
+
* @category models
|
|
11
|
+
* @since 0.1.0
|
|
12
|
+
*/
|
|
13
|
+
export interface Skill<R = never> {
|
|
14
|
+
readonly name: string;
|
|
15
|
+
/** When to use it, in one line. This is all the model sees until it loads the skill. */
|
|
16
|
+
readonly description: string;
|
|
17
|
+
/** Text, or an Effect resolved each time the skill is loaded. */
|
|
18
|
+
readonly instructions: Instructions<R>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Creates a skill from its name, a description of when to use it, and its instructions.
|
|
22
|
+
*
|
|
23
|
+
* **Details**
|
|
24
|
+
*
|
|
25
|
+
* Write the description as a trigger ("Use when…"), since it's all the model sees until it loads
|
|
26
|
+
* the skill. The instructions are text, or an Effect that is resolved each time the skill is
|
|
27
|
+
* loaded.
|
|
28
|
+
*
|
|
29
|
+
* **Example** (Defining a playbook for ordering campaigns)
|
|
30
|
+
*
|
|
31
|
+
* ```ts
|
|
32
|
+
* import { Skill } from "effect-assistant"
|
|
33
|
+
*
|
|
34
|
+
* const orderingCampaigns = Skill.make("Ordering a campaign", {
|
|
35
|
+
* description: "Use when the user wants to order or start a campaign.",
|
|
36
|
+
* instructions: `1. Pick the product with list_campaign_products.
|
|
37
|
+
* 2. You need who it should reach and a budget. Ask for what's missing, one question at a time.
|
|
38
|
+
* 3. When you have both, call start_campaign.`
|
|
39
|
+
* })
|
|
40
|
+
*
|
|
41
|
+
* const MyAssistantLive = MyAssistant.toLayer((turn) =>
|
|
42
|
+
* turn.loop({ instructions, skills: [orderingCampaigns] })
|
|
43
|
+
* )
|
|
44
|
+
* ```
|
|
45
|
+
*
|
|
46
|
+
* @category constructors
|
|
47
|
+
* @since 0.1.0
|
|
48
|
+
*/
|
|
49
|
+
export declare const make: <R = never>(name: string, options: {
|
|
50
|
+
/** When to use it, in one line. This is all the model sees until it loads the skill. */
|
|
51
|
+
readonly description: string;
|
|
52
|
+
/** Text, or an Effect resolved each time the skill is loaded. */
|
|
53
|
+
readonly instructions: Instructions<R>;
|
|
54
|
+
}) => Skill<R>;
|
|
55
|
+
/**
|
|
56
|
+
* Extracts the services that skills need when they're loaded.
|
|
57
|
+
*
|
|
58
|
+
* @category utility types
|
|
59
|
+
* @since 0.1.0
|
|
60
|
+
*/
|
|
61
|
+
export type Services<S> = S extends Skill<infer R> ? R : never;
|
|
62
|
+
/**
|
|
63
|
+
* Returns the prompt with the skills' catalog appended, or the prompt unchanged when there are no
|
|
64
|
+
* skills.
|
|
65
|
+
*
|
|
66
|
+
* @category utils
|
|
67
|
+
* @since 0.1.0
|
|
68
|
+
*/
|
|
69
|
+
export declare const withCatalog: <R>(prompt: string, skills: ReadonlyArray<Skill<R>>) => string;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { Skill_d_exports };
|
|
72
|
+
//# sourceMappingURL=Skill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skill.d.ts","names":[],"sources":["../src/Skill.ts"],"mappings":";;;;;;;;;;;;iBAmBiB,MAAM;WACZ;;WAEA;;WAEA,cAAc,aAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgCtC,OAAQ,WAAS,cAChB;;WAGD;;WAEA,cAAc,aAA0B;MAElD,MAAM;;;;;;;YAQG,SAAS,KAAK,UAAU,YAAY,KAAK;;;;;;;;qBASxC,cAAe,GAAC,gBAAgB,QAAU,cAAc,MAAM"}
|
package/dist/Skill.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
//#region src/Skill.ts
|
|
3
|
+
var Skill_exports = /* @__PURE__ */ __exportAll({
|
|
4
|
+
make: () => make,
|
|
5
|
+
withCatalog: () => withCatalog
|
|
6
|
+
});
|
|
7
|
+
/**
|
|
8
|
+
* Creates a skill from its name, a description of when to use it, and its instructions.
|
|
9
|
+
*
|
|
10
|
+
* **Details**
|
|
11
|
+
*
|
|
12
|
+
* Write the description as a trigger ("Use when…"), since it's all the model sees until it loads
|
|
13
|
+
* the skill. The instructions are text, or an Effect that is resolved each time the skill is
|
|
14
|
+
* loaded.
|
|
15
|
+
*
|
|
16
|
+
* **Example** (Defining a playbook for ordering campaigns)
|
|
17
|
+
*
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { Skill } from "effect-assistant"
|
|
20
|
+
*
|
|
21
|
+
* const orderingCampaigns = Skill.make("Ordering a campaign", {
|
|
22
|
+
* description: "Use when the user wants to order or start a campaign.",
|
|
23
|
+
* instructions: `1. Pick the product with list_campaign_products.
|
|
24
|
+
* 2. You need who it should reach and a budget. Ask for what's missing, one question at a time.
|
|
25
|
+
* 3. When you have both, call start_campaign.`
|
|
26
|
+
* })
|
|
27
|
+
*
|
|
28
|
+
* const MyAssistantLive = MyAssistant.toLayer((turn) =>
|
|
29
|
+
* turn.loop({ instructions, skills: [orderingCampaigns] })
|
|
30
|
+
* )
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @category constructors
|
|
34
|
+
* @since 0.1.0
|
|
35
|
+
*/
|
|
36
|
+
const make = (name, options) => ({
|
|
37
|
+
name,
|
|
38
|
+
description: options.description,
|
|
39
|
+
instructions: options.instructions
|
|
40
|
+
});
|
|
41
|
+
/**
|
|
42
|
+
* Returns the prompt with the skills' catalog appended, or the prompt unchanged when there are no
|
|
43
|
+
* skills.
|
|
44
|
+
*
|
|
45
|
+
* @category utils
|
|
46
|
+
* @since 0.1.0
|
|
47
|
+
*/
|
|
48
|
+
const withCatalog = (prompt, skills) => skills.length === 0 ? prompt : [
|
|
49
|
+
prompt,
|
|
50
|
+
"",
|
|
51
|
+
"## Skills",
|
|
52
|
+
"Playbooks for common tasks. When one matches what you're doing, load it with load_skill in the same step as your first lookups, and follow it.",
|
|
53
|
+
...skills.map((skill) => `- ${skill.name}: ${skill.description}`)
|
|
54
|
+
].join("\n");
|
|
55
|
+
//#endregion
|
|
56
|
+
export { Skill_exports, make, withCatalog };
|
|
57
|
+
|
|
58
|
+
//# sourceMappingURL=Skill.js.map
|