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.
- package/dist/Assistant.d.ts +5 -11
- package/dist/Assistant.d.ts.map +1 -1
- package/dist/Assistant.js.map +1 -1
- package/dist/AssistantEvent.d.ts +66 -7
- package/dist/AssistantEvent.d.ts.map +1 -1
- package/dist/AssistantEvent.js +74 -9
- package/dist/AssistantEvent.js.map +1 -1
- package/dist/AssistantLoop.d.ts +4 -2
- package/dist/AssistantLoop.d.ts.map +1 -1
- package/dist/AssistantLoop.js +4 -2
- package/dist/AssistantLoop.js.map +1 -1
- package/dist/Block.d.ts +63 -1
- package/dist/Block.d.ts.map +1 -1
- package/dist/Block.js +63 -2
- package/dist/Block.js.map +1 -1
- package/dist/BlockKit.d.ts +25 -3
- package/dist/BlockKit.d.ts.map +1 -1
- package/dist/BlockKit.js +14 -12
- package/dist/BlockKit.js.map +1 -1
- package/dist/Compaction.d.ts +1 -1
- package/dist/Compaction.d.ts.map +1 -1
- package/dist/Compaction.js +11 -4
- package/dist/Compaction.js.map +1 -1
- package/dist/Skill.d.ts +85 -43
- package/dist/Skill.d.ts.map +1 -1
- package/dist/Skill.js +93 -44
- package/dist/Skill.js.map +1 -1
- package/dist/Specialist.d.ts +6 -9
- package/dist/Specialist.d.ts.map +1 -1
- package/dist/Specialist.js.map +1 -1
- package/dist/Timeline.d.ts +44 -6
- package/dist/Timeline.d.ts.map +1 -1
- package/dist/Timeline.js +87 -16
- package/dist/Timeline.js.map +1 -1
- package/dist/ToolApproval.d.ts +146 -0
- package/dist/ToolApproval.d.ts.map +1 -0
- package/dist/ToolApproval.js +201 -0
- package/dist/ToolApproval.js.map +1 -0
- package/dist/ToolDiscovery.d.ts +6 -4
- package/dist/ToolDiscovery.d.ts.map +1 -1
- package/dist/ToolDiscovery.js +5 -4
- package/dist/ToolDiscovery.js.map +1 -1
- package/dist/ToolResult.d.ts +56 -0
- package/dist/ToolResult.d.ts.map +1 -0
- package/dist/ToolResult.js +49 -0
- package/dist/ToolResult.js.map +1 -0
- package/dist/index.d.ts +4 -2
- package/dist/index.js +6 -4
- package/dist/internal/chat.js +4 -1
- package/dist/internal/chat.js.map +1 -1
- package/dist/internal/history.js +28 -3
- package/dist/internal/history.js.map +1 -1
- package/dist/internal/loop.d.ts +10 -5
- package/dist/internal/loop.d.ts.map +1 -1
- package/dist/internal/loop.js +60 -21
- package/dist/internal/loop.js.map +1 -1
- package/dist/internal/specialists.js +9 -16
- package/dist/internal/specialists.js.map +1 -1
- package/dist/internal/toolkit.d.ts +11 -7
- package/dist/internal/toolkit.d.ts.map +1 -1
- package/dist/internal/toolkit.js +74 -21
- package/dist/internal/toolkit.js.map +1 -1
- package/dist/internal/tools.js +39 -6
- package/dist/internal/tools.js.map +1 -1
- package/dist/internal/turns.d.ts.map +1 -1
- package/dist/internal/turns.js +24 -16
- package/dist/internal/turns.js.map +1 -1
- package/package.json +1 -1
- package/src/Assistant.ts +7 -13
- package/src/AssistantEvent.ts +73 -8
- package/src/AssistantLoop.ts +4 -2
- package/src/Block.ts +82 -1
- package/src/BlockKit.ts +37 -4
- package/src/Compaction.ts +19 -2
- package/src/Skill.ts +134 -57
- package/src/Specialist.ts +8 -11
- package/src/Timeline.ts +120 -21
- package/src/ToolApproval.ts +249 -0
- package/src/ToolDiscovery.ts +8 -3
- package/src/ToolResult.ts +80 -0
- package/src/index.ts +10 -0
- package/src/internal/chat.ts +11 -1
- package/src/internal/history.ts +58 -3
- package/src/internal/loop.ts +138 -35
- package/src/internal/specialists.ts +7 -13
- package/src/internal/toolkit.ts +102 -35
- package/src/internal/tools.ts +81 -5
- package/src/internal/turns.ts +31 -10
- package/dist/internal/skills.js +0 -33
- package/dist/internal/skills.js.map +0 -1
- package/src/internal/skills.ts +0 -48
package/dist/Assistant.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ import { Instructions_d_exports, Resolved } from "./Instructions.js";
|
|
|
4
4
|
import { AssistantLoop_d_exports, ChatHistory, Event, ToolkitServices } from "./AssistantLoop.js";
|
|
5
5
|
import { CurrentChat } from "./CurrentChat.js";
|
|
6
6
|
import { BlockKit, BlockKit_d_exports } from "./BlockKit.js";
|
|
7
|
-
import { Skill } from "./Skill.js";
|
|
8
7
|
import { Any as Any$1, CheckServices, HandlerOf, Runner, Specialist_d_exports, ToolHandlers } from "./Specialist.js";
|
|
9
8
|
import { AssistantEngine } from "./AssistantEngine.js";
|
|
10
9
|
import { Chats_d_exports, GetChatError } from "./Chats.js";
|
|
@@ -37,21 +36,16 @@ export type TurnServices = CurrentChat | Runner;
|
|
|
37
36
|
* @category models
|
|
38
37
|
* @since 0.1.0
|
|
39
38
|
*/
|
|
40
|
-
export interface LoopOptions<T extends Record<string, Tool.Any> = Record<never, never>,
|
|
39
|
+
export interface LoopOptions<T extends Record<string, Tool.Any> = Record<never, never>, Events = never> {
|
|
41
40
|
/** The assistant's role and rules. The loop places `Instructions.protocol` before them. */
|
|
42
41
|
readonly instructions: string | Resolved;
|
|
43
42
|
/**
|
|
44
43
|
* Tools the model can use in addition to the assistant's own. This is an `effect/ai` toolkit,
|
|
45
44
|
* and its handlers come from the layer. Combine several toolkits with `Toolkit.merge`, for
|
|
46
|
-
* example `Memory.Tools` or a `ToolDiscovery.make(...)` toolkit together
|
|
45
|
+
* example `Memory.Tools`, a `Skill.toolkit(...)`, or a `ToolDiscovery.make(...)` toolkit together
|
|
46
|
+
* with your own.
|
|
47
47
|
*/
|
|
48
48
|
readonly toolkit?: Toolkit.Toolkit<T> | undefined;
|
|
49
|
-
/**
|
|
50
|
-
* Playbooks the model can follow. The prompt lists them as a catalog, and the model loads one
|
|
51
|
-
* with `load_skill` when a task matches it. A skill made with `tools` is left out when the turn's
|
|
52
|
-
* tools lack one of them.
|
|
53
|
-
*/
|
|
54
|
-
readonly skills?: ReadonlyArray<Skill<RS>> | undefined;
|
|
55
49
|
/** The maximum number of model calls per turn. Defaults to 16. */
|
|
56
50
|
readonly maxSteps?: number | undefined;
|
|
57
51
|
/** The message the reply pass gives the model when the turn would end without a reply. */
|
|
@@ -165,10 +159,10 @@ export interface Turn<Events = never> {
|
|
|
165
159
|
readonly instructions: (instructions: string | Resolved) => Resolved;
|
|
166
160
|
/**
|
|
167
161
|
* Runs the agent loop over the chat. The loop uses `Instructions.protocol`, the assistant's own
|
|
168
|
-
* tools, and the instructions
|
|
162
|
+
* tools, and the instructions and tools in `options`. Every step is a tool call, and
|
|
169
163
|
* the loop ends with `replyIfOwed`.
|
|
170
164
|
*/
|
|
171
|
-
readonly loop: <T extends Record<string, Tool.Any> = Record<never, never
|
|
165
|
+
readonly loop: <T extends Record<string, Tool.Any> = Record<never, never>>(options: LoopOptions<T, Events>) => Stream.Stream<Event, AiError.AiError, LanguageModel.LanguageModel | TurnServices | ToolkitServices<T>>;
|
|
172
166
|
/**
|
|
173
167
|
* Runs one more pass when the turn would otherwise end without a reply to the user's latest
|
|
174
168
|
* message. In this pass the model can only reply.
|
package/dist/Assistant.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Assistant.d.ts","names":[],"sources":["../src/Assistant.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"Assistant.d.ts","names":[],"sources":["../src/Assistant.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;cAsCM;;;;;;;;YASM,eAAe,cAAc;;;;;;;iBAQxB,YAAY,UAAU,eAAe,KAAK,OAAO,sBAAsB;;WAE7E,uBAAuB;;;;;;;WAOvB,UAAU,QAAQ,QAAQ;;WAE1B;;WAEA;;;;;;WAMA,UAAU,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;YAkDrB,YAAY,mBACtB,SAAS,cAAc,MAAM,aAC1B,cAAc,MAAM,UAAU,OAAO;;;;;;;iBAQzB,MAAM;WACZ,QAAQ;WACR;WACA;WACA,OAAO,iBAAgC;;;;;;;;iBASjC;;WAEN,uBAAuB;;;;;WAKvB;;;;;;;;;;;iBAYM,KAAK;WACX,QAAQ;;;;;;;;;WASR,UAAU,OAAO,YAAY,YAAY,OAAO,OAAO;;;;;WAKvD,eAAe,uBAAuB,aAA0B;;;;;;WAMhE,OAAO,UAAU,eAAe,KAAK,OAAO,sBACnD,SAAS,YAAY,GAAG,YACrB,OAAO,OACV,OACA,QAAQ,SACR,cAAc,gBAAgB,eAAe,gBAA8B;;;;;;;;;WAUpE,cACP,SAAS,iBACN,OAAO,OAAO,OAAqB,QAAQ,SAAS,cAAc,gBAAgB;;;;;;;;;;;;YAa7E,QAAQ,WAAW,KAAK,GAAG,mBACrC,MAAM,KAAK,YAET,OAAO,OAAO,gBAA8B,KAC5C,OAAO,OAAO,OAAO,OAAO,gBAA8B,aAAa;;;;;;;;;YAU/D,gBAAgB,KAAK,QAAQ,GAAG,eAAe,cAAc,gBAAgB,KAAK;;;;;;;;iBAe7E,WAAW;WACjB,+BAA+B;;;;;;;;iBASzB,eAAe;WACrB,oCAAoC;;;;;;;;;;;;;iBAc9B,KAAK;WACX,QAAQ;;;;;WAKR,SAAS,OAAO,OAAO,cAAc,MAAM;;;;;;EAMpD,UAAU,QAAQ,cAAc,iBAAgC,UAAU,OAAO;;;;;;;;;;iBAWlE,QAAQ;;;;;;;;;;;;EAavB,OAAO,QAAQ,QAAQ,OAAO,QAAuB,SAAS,OAAO,aAAa;;;;;;;;;;;WAWzE,YACP,QAAQ,QACR;aAAqB;QAClB,OAAO,OAAO,MAAM;;;;;;;;;;;;;;WAchB,SAAS,QAAQ,WAAW,OAAO;;;;;;;;;;;;iBAa7B,UACf,8BACA,cAAc,eACd,wBACQ,QAAQ,QAAQ,WAAW,OAAO,QAAQ;YACxC,gBAAgB;WACjB,MAAM;WACN,QAAQ;;WAER,aAAa,cAAc;;WAE3B,QAAQ,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;WAmCtB,UAAU,WAAW,YAAY,WAAW,YACnD,QAAQ,QAAQ,GAAG,IAAI,UAAU,OAAO,OAAO,QAAQ,GAAG,IAAI,SAAS,GAAG,OACxE,cAAyB,QAAQ,gBAAgB,IAAI,KAAK,KAAK,eAAe,YAC7E,MAAM,MACT,WAAW,cAET,kBACA,cAAc,gBACd,UAAqB,SACrB,QAAQ,IAAI,MAAM,QAAQ,cAAc,eAAe,SACvD,aAAwB,IAAI;;;;;;;;;;;;;;;;;;;;;;;WAwBvB,aAAa,MAAM,MAAM,WAAW,cAAc;;;;;WAKlD,MAAM,QAAQ,QAAQ,eAAe,OAAO,KAAK;;WAEjD,OAAO,OAAO,MAAM,MAAM,SAAS,OAAO;;;;;;;;YASzC,MAAM;;;;;;;qBAQL,cAAW,eAAiB,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAqDjC,aACL,2BACA,cAAc,cAAc,4BAC5B,eAAe,cAAc,+BAA4C,MAEzE,MAAI;;WAGC,SAAS;;;;;WAKT,cAAc;;;;;;;WAOd,SAAS;MAEnB,UAAU,MAAM,eAAe"}
|
package/dist/Assistant.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Assistant.js","names":["AssistantEvent.AssistantEvent","AppEvents.make","AssistantEvent.isInput","AppEvents.encode","Chats.Chats","AppEvents.decodeEntry","Turns.register"],"sources":["../src/Assistant.ts"],"sourcesContent":["/**\n * This module provides `Assistant.make`, which defines an assistant that works in a chat the way a\n * colleague does: the user messages it, it works in the background with the app's tools, and it\n * messages the user back.\n *\n * A definition is what the rest of an app imports. Yielding it (`yield* MyAssistant`) returns the\n * assistant's {@link Service}, which submits inputs to chats and streams them back. Its `toLayer`\n * registers the handler that runs each {@link Turn} with the `AssistantEngine`, and its\n * `layerClient` provides the service without a handler. Code that runs inside a chat reads and\n * extends that chat through the definition's {@link Chat} key.\n *\n * @since 0.1.0\n */\nimport type * as AiError from \"effect/ai/AiError\"\nimport type * as LanguageModel from \"effect/ai/LanguageModel\"\nimport type * as Prompt from \"effect/ai/Prompt\"\nimport type * as Tool from \"effect/ai/Tool\"\nimport type * as Toolkit from \"effect/ai/Toolkit\"\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Filter from \"effect/Filter\"\nimport * as Layer from \"effect/Layer\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport type * as Scope from \"effect/Scope\"\nimport * as Stream from \"effect/Stream\"\nimport { AssistantEngine } from \"./AssistantEngine.ts\"\nimport * as AssistantEvent from \"./AssistantEvent.ts\"\nimport type * as AssistantLoop from \"./AssistantLoop.ts\"\nimport type * as BlockKit from \"./BlockKit.ts\"\nimport { ChatId } from \"./ChatId.ts\"\nimport * as Chats from \"./Chats.ts\"\nimport type { CurrentChat } from \"./CurrentChat.ts\"\nimport type * as Instructions from \"./Instructions.ts\"\nimport * as AppEvents from \"./internal/events.ts\"\nimport * as Turns from \"./internal/turns.ts\"\nimport type { Skill } from \"./Skill.ts\"\nimport type * as Specialist from \"./Specialist.ts\"\n\nconst TypeId = \"~effect-assistant/Assistant\" as const\n\n/**\n * Represents the services that a turn provides to its tools, its loop, and its specialists. These\n * are the turn's chat (`CurrentChat`) and the chat's specialist runner (`Specialist.Runner`).\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type TurnServices = CurrentChat | Specialist.Runner\n\n/**\n * Represents the options accepted by `turn.loop`.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface LoopOptions<T extends Record<string, Tool.Any> = Record<never, never>, RS = never, Events = never> {\n /** The assistant's role and rules. The loop places `Instructions.protocol` before them. */\n readonly instructions: string | Instructions.Resolved\n /**\n * Tools the model can use in addition to the assistant's own. This is an `effect/ai` toolkit,\n * and its handlers come from the layer. Combine several toolkits with `Toolkit.merge`, for\n * example `Memory.Tools` or a `ToolDiscovery.make(...)` toolkit together with your own.\n */\n readonly toolkit?: Toolkit.Toolkit<T> | undefined\n /**\n * Playbooks the model can follow. The prompt lists them as a catalog, and the model loads one\n * with `load_skill` when a task matches it. A skill made with `tools` is left out when the turn's\n * tools lack one of them.\n */\n readonly skills?: ReadonlyArray<Skill<RS>> | undefined\n /** The maximum number of model calls per turn. Defaults to 16. */\n readonly maxSteps?: number | undefined\n /** The message the reply pass gives the model when the turn would end without a reply. */\n readonly replyNudge?: string | undefined\n /**\n * Selects which of the chat's entries the model reads, for example only those since the last\n * summary, and maps the app's own events it should read into prompt messages. Defaults to all\n * entries, without the app's events.\n */\n readonly history?: HistoryView<Events> | undefined\n}\n\n/**\n * Represents a function that selects which of a chat's entries the model reads, and what else it\n * reads with them.\n *\n * **Details**\n *\n * The function receives the chat's entries, the app's own events among them, and returns, in\n * order, a mix of entries and `Prompt.Message`s. The model reads the returned entries the same way\n * it reads the full history, and reads each prompt message unchanged, where the view put it. The\n * model reads none of the app's events by itself: map those it should read to a message, and an\n * app event's entry left in the result is dropped.\n *\n * A message stands right after the entry before it: one that came after the model's last read, or\n * between a tool call and its result, moves after them, as an input does.\n *\n * **Example** (Telling the model about an order the user placed)\n *\n * ```ts\n * import { Assistant, InputId } from \"effect-assistant\"\n * import * as Prompt from \"effect/ai/Prompt\"\n * import * as Schema from \"effect/Schema\"\n *\n * class OrderPlaced extends Schema.TaggedClass<OrderPlaced>()(\"OrderPlaced\", {\n * id: InputId.InputId,\n * reference: Schema.String\n * }) {}\n *\n * const MyAssistant = Assistant.make(\"my-assistant\", { events: [OrderPlaced] })\n *\n * const withOrders: Assistant.HistoryView<OrderPlaced> = (entries) =>\n * entries.map((entry) =>\n * entry.event instanceof OrderPlaced\n * ? Prompt.userMessage({\n * content: [Prompt.textPart({ text: `The user placed order ${entry.event.reference}.` })]\n * })\n * : entry\n * )\n *\n * // An `OrderPlaced` that the API submits wakes a turn, which reads it as this note.\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({ instructions: \"Be brief.\", history: withOrders })\n * )\n * ```\n *\n * @category models\n * @since 0.1.0\n */\nexport type HistoryView<Events = never> = (\n entries: ReadonlyArray<Entry<Events>>\n) => ReadonlyArray<Entry<Events> | Prompt.Message>\n\n/**\n * Represents an entry in a chat's log, with the assistant's own events decoded to their types.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Entry<Events = never> {\n readonly chatId: ChatId\n readonly seq: number\n readonly at: number\n readonly event: AssistantEvent.AssistantEvent | Events\n}\n\n/**\n * Represents the options accepted by `turn.replyIfOwed`.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface ReplyOptions {\n /** The assistant's instructions, as passed to `turn.loop`. `Instructions.protocol` is added. */\n readonly instructions: string | Instructions.Resolved\n /**\n * The message given to the model after the history. Defaults to a message saying that it\n * hasn't replied yet and should reply now.\n */\n readonly nudge?: string | undefined\n}\n\n/**\n * Represents one turn, as the assistant's handler receives it.\n *\n * `Events` is the type of the app's own events that the assistant registered with its `events`\n * option.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Turn<Events = never> {\n readonly chatId: ChatId\n /**\n * Returns the model's history, built from the chat's entries (all of them, or those a view\n * keeps), together with how far into the chat it reaches.\n *\n * Read it before every model call, as the loop does. Each step records how far its model call\n * read, and the turn ends once it has handled what the model saw. An input that arrived after\n * that is handled by the next turn.\n */\n readonly history: (view?: HistoryView<Events>) => Effect.Effect<AssistantLoop.ChatHistory>\n /**\n * Returns the full system prompt for the given instructions. It contains\n * `Instructions.protocol`, the instructions, and the specialist runs that are working now.\n */\n readonly instructions: (instructions: string | Instructions.Resolved) => Instructions.Resolved\n /**\n * Runs the agent loop over the chat. The loop uses `Instructions.protocol`, the assistant's own\n * tools, and the instructions, tools, and skills in `options`. Every step is a tool call, and\n * the loop ends with `replyIfOwed`.\n */\n readonly loop: <T extends Record<string, Tool.Any> = Record<never, never>, RS = never>(\n options: LoopOptions<T, RS, Events>\n ) => Stream.Stream<\n AssistantLoop.Event,\n AiError.AiError,\n LanguageModel.LanguageModel | TurnServices | AssistantLoop.ToolkitServices<T> | RS\n >\n /**\n * Runs one more pass when the turn would otherwise end without a reply to the user's latest\n * message. In this pass the model can only reply.\n *\n * The stream is empty when no reply is owed, or when an input arrived that the next turn will\n * read. `loop` runs this pass with its own prompt and tools, so the pass reuses the cached\n * prompt.\n */\n readonly replyIfOwed: (\n options: ReplyOptions\n ) => Stream.Stream<AssistantLoop.Event, AiError.AiError, LanguageModel.LanguageModel | TurnServices>\n}\n\n/**\n * Represents an assistant's handler, which runs a turn and returns it as a stream of the loop's\n * events.\n *\n * The handler may return the stream directly or from an Effect. `R` is the services the stream\n * requires, and `RE` is the services the Effect requires.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Handler<R = never, RE = R, Events = never> = (\n turn: Turn<Events>\n) =>\n | Stream.Stream<AssistantLoop.Event, unknown, R>\n | Effect.Effect<Stream.Stream<AssistantLoop.Event, unknown, R>, unknown, RE>\n\n/**\n * Computes the services an assistant's handler needs beyond those its turns provide (the turn\n * services and `LanguageModel`) and its tools' handlers (which its layer requires). These are the\n * services that its build Effect must require.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type HandlerServices<R> = Exclude<R, TurnServices | LanguageModel.LanguageModel | Tool.Handler<string>>\n\nconst toStream = <R, RE>(\n result:\n | Stream.Stream<AssistantLoop.Event, unknown, R>\n | Effect.Effect<Stream.Stream<AssistantLoop.Event, unknown, R>, unknown, RE>\n): Stream.Stream<AssistantLoop.Event, unknown, R | RE> => (Effect.isEffect(result) ? Stream.unwrap(result) : result)\n\n/**\n * Identifies an assistant's service in a context. Each assistant has its own identifier, keyed by\n * its name.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Identifier<Name extends string> {\n readonly \"~effect-assistant/Assistant\": Name\n}\n\n/**\n * Identifies, in a context, the chat that an assistant's turns run in.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface ChatIdentifier<Name extends string> {\n readonly \"~effect-assistant/Assistant/Chat\": Name\n}\n\n/**\n * Represents the chat that a turn of this assistant runs in, typed with the assistant's events.\n *\n * Use `yield* MyAssistant.Chat` in the handler, in the handler's build, or in a tool that its\n * turns run. Code that doesn't know the assistant uses `CurrentChat` instead.\n *\n * @see {@link CurrentChat} for the same chat without the assistant's event types\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Chat<Events = never> {\n readonly chatId: ChatId\n /**\n * The chat's entries so far, in order. They include the library's events and the assistant's\n * own events, typed.\n */\n readonly entries: Effect.Effect<ReadonlyArray<Entry<Events>>>\n /**\n * Appends events after the chat's last entry and sends them to the chat's subscribers. The\n * events can be the library's or the assistant's own, such as a summary. None of them wakes a\n * turn: only what comes in through the assistant's `submit` does.\n */\n append(...events: ReadonlyArray<AssistantEvent.AssistantEvent | Events>): Effect.Effect<void>\n}\n\n/**\n * Represents the service that `yield* MyAssistant` returns. It gives code outside a chat, such as\n * a server or a workflow, access to the assistant's chats. Code that runs inside a chat uses\n * `CurrentChat` instead.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Service<Events = never> {\n /**\n * Stores an input or one of the assistant's own events, then returns. Examples are a user's\n * message or block answer, a workflow's progress, or the order the user placed. Each one is an\n * input: storing it wakes a turn, which the assistant runs in the background. The handler decides\n * what the turn does with it, and an app event the model should read needs a history view that\n * maps it (see {@link HistoryView}). To store an app event without waking a turn, append it from\n * within the chat instead (`yield* MyAssistant.Chat`).\n *\n * Fails with `GetChatError` when the app's `Chats` service reports that the chat can't be used,\n * because the app doesn't know the chat or has deleted it.\n */\n // Method syntax: a service for these events is one for any (`Service<any>`), for helpers over assistants.\n submit(chatId: ChatId, input: AssistantEvent.Input | Events): Effect.Effect<void, Chats.GetChatError>\n /**\n * Streams the chat's stored entries, then live ones, with the assistant's own events decoded.\n * A reader that already has the earlier entries passes `after` and receives only the entries\n * after that `seq`.\n *\n * For a chat client, pipe the whole log into `Timeline.changes(MyAssistant, { after })`, which\n * streams the chat's timeline, as its user sees it. Its `after` goes there, not here: a message\n * on the timeline depends on earlier entries. The timeline shows only the app events named in its\n * `show`, none by default (see `Timeline.changes`).\n */\n readonly subscribe: (\n chatId: ChatId,\n options?: { readonly after?: number | undefined }\n ) => Stream.Stream<Entry<Events>>\n /**\n * Deletes a chat by storing a `ChatDeleted` event and stopping everything that works in it.\n *\n * **Details**\n *\n * A turn or specialist run working in the chat stops, and subscribers' streams end with the\n * `ChatDeleted` event. After that the chat stores nothing more: a later input, a run's report,\n * or a workflow's event for it is dropped without an error. The log is kept, and removing it is\n * up to the app. Deleting a chat a second time does nothing.\n *\n * When the app's `Chats` service reports a chat as deleted, the assistant deletes it in the same\n * way the next time it checks. It checks before an input is stored and before each model call.\n */\n readonly delete: (chatId: ChatId) => Effect.Effect<void>\n}\n\n/**\n * Represents an assistant's definition.\n *\n * The definition holds what callers and the UI need to know about the assistant, builds its\n * handler's layer, and is the key of its service (`yield* MyAssistant`). `Events` is the type of\n * the app's own events that the assistant registered.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Assistant<\n Name extends string = string,\n Specs extends Specialist.Any = never,\n Events = never\n> extends Context.Service<Identifier<Name>, Service<Events>> {\n readonly [TypeId]: typeof TypeId\n readonly name: Name\n readonly blocks: BlockKit.BlockKit | undefined\n /** The specialists the assistant can hand work to. */\n readonly specialists: ReadonlyArray<Specs>\n /** The schemas of the app's own events the assistant stores. */\n readonly events: ReadonlyArray<AssistantEvent.AppEventSchema>\n /**\n * Creates a layer that registers the assistant's handler with the engine and provides the\n * assistant's service.\n *\n * **Details**\n *\n * `build` is the handler, or an Effect that returns it. The handler may use the turn services,\n * `LanguageModel`, its tools' handlers (which the layer then requires), and services that its\n * build Effect required (see `Specialist.CheckServices`). The layer requires the\n * `AssistantEngine`, the `LanguageModel`, and each specialist's handler\n * (`Research.toLayer(...)`).\n *\n * **Example** (Providing an assistant's handler)\n *\n * ```ts\n * import { Assistant, AssistantEngine, ChatLog } from \"effect-assistant\"\n * import type * as LanguageModel from \"effect/ai/LanguageModel\"\n * import * as Layer from \"effect/Layer\"\n *\n * declare const ModelLive: Layer.Layer<LanguageModel.LanguageModel>\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({ instructions: \"You help a small team. Be brief.\" })\n * )\n *\n * const AppLive = MyAssistantLive.pipe(\n * Layer.provide(ModelLive),\n * Layer.provideMerge(AssistantEngine.layerMemory),\n * Layer.provideMerge(ChatLog.layerMemory)\n * )\n * ```\n */\n readonly toLayer: <R = never, RE = never, E = never, RX = never>(\n build: (Handler<R, RE, Events> | Effect.Effect<Handler<R, RE, Events>, E, RX>) &\n Specialist.CheckServices<Exclude<HandlerServices<R | RE>, RX | ChatIdentifier<Name>>>\n ) => Layer.Layer<\n Identifier<Name>,\n never,\n | AssistantEngine\n | LanguageModel.LanguageModel\n | Specialist.HandlerOf<Specs>\n | Exclude<RX, Scope.Scope | CurrentChat | ChatIdentifier<Name>>\n | Specialist.ToolHandlers<R | RE>\n >\n /**\n * A layer that provides the assistant's service without its handler.\n *\n * **When to use**\n *\n * Use it in a process that submits to chats that another process runs, such as a web server in\n * front of a cluster.\n *\n * **Example** (Serving clients in front of a cluster)\n *\n * ```ts\n * import { Assistant, AssistantEngine } from \"effect-assistant\"\n * import * as Layer from \"effect/Layer\"\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * // Requires `Sharding`. The cluster's runners run the chats, with `AssistantEngine.layerCluster`.\n * const MyAssistantClient = MyAssistant.layerClient.pipe(\n * Layer.provide(AssistantEngine.layerClusterClient)\n * )\n * ```\n */\n readonly layerClient: Layer.Layer<Identifier<Name>, never, AssistantEngine>\n /**\n * The key of the chat that the assistant's turns run in, typed with its events. See\n * {@link Chat}.\n */\n readonly Chat: Context.Service<ChatIdentifier<Name>, Chat<Events>>\n /** A schema that encodes the chat's entries to JSON, including the assistant's own events. */\n readonly Entry: Schema.Codec<Entry<Events>, Schema.Json>\n}\n\n/**\n * Represents any assistant, for use in generic constraints.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type Any = Assistant<any, any, any>\n\n/**\n * Returns `true` when the value is an assistant's definition, created with {@link make}.\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isAssistant = (u: unknown): u is Any => Predicate.hasProperty(u, TypeId)\n\nfunction entrySchema<E>(events: ReadonlyArray<AssistantEvent.AppEventSchema>): Schema.Codec<Entry<E>, Schema.Json>\n// The overload states the decoded type: the library's events, or one of these schemas' types.\nfunction entrySchema(events: ReadonlyArray<AssistantEvent.AppEventSchema>): Schema.Top {\n return Schema.toCodecJson(\n Schema.Struct({\n chatId: ChatId,\n seq: Schema.Int,\n at: Schema.Finite,\n event: Schema.Union([AssistantEvent.AssistantEvent, ...events])\n })\n )\n}\n\n/**\n * Creates an assistant definition from its name, its UI blocks, its specialists, and the schemas of\n * the app's own events it stores.\n *\n * **Details**\n *\n * The definition holds no code that runs turns. Provide a handler with its `toLayer`, then yield\n * the definition to get the assistant's {@link Service}.\n *\n * The definition only says which of the app's events a chat stores. What happens with one is up\n * to the places that use it. One that comes in through the service's `submit`, from outside a\n * turn, is an input and wakes a turn, like a user's message; one a turn appends to its chat never\n * does. The handler decides what a turn does, a history view says how the model reads an event\n * ({@link HistoryView}), and the chat's timeline says which its user sees\n * (`Timeline.changes`).\n *\n * **Example** (Defining an assistant and submitting a message)\n *\n * ```ts\n * import { Assistant, AssistantEvent, ChatId } from \"effect-assistant\"\n * import * as Effect from \"effect/Effect\"\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * const program = Effect.gen(function* () {\n * const assistant = yield* MyAssistant\n * const chatId = yield* ChatId.make()\n *\n * yield* assistant.submit(chatId, AssistantEvent.UserMessage.make({ text: \"Weather in Oslo?\" }))\n * })\n * ```\n *\n * @see {@link Assistant} for the definition's members\n * @see {@link Service} for what `yield* MyAssistant` returns\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <\n const Name extends string,\n const Specs extends ReadonlyArray<Specialist.Any> = readonly [],\n const Events extends ReadonlyArray<AssistantEvent.AppEventSchema> = readonly []\n>(\n name: Name,\n options?: {\n /** UI blocks the assistant can add to its messages. */\n readonly blocks?: BlockKit.BlockKit | undefined\n /**\n * The specialists the assistant can hand work to. Each specialist's `toLayer` must be\n * provided to the assistant's layer.\n */\n readonly specialists?: Specs | undefined\n /**\n * The schemas of the app's own events, each a tagged struct or class. `submit` and the chat's\n * `append` store them, in their JSON form, and the chat's `entries` and `subscribe` read them\n * back, decoded. Each needs a tag of its own that isn't one of the library's: `make` throws\n * otherwise.\n */\n readonly events?: Events | undefined\n }\n): Assistant<Name, Specs[number], Events[number][\"Type\"]> => {\n const events = options?.events ?? []\n\n const definition: Turns.Definition = {\n name,\n blocks: options?.blocks,\n specialists: options?.specialists ?? [],\n app: AppEvents.make(events)\n }\n\n type OwnEvents = Events[number][\"Type\"]\n\n const Key = Context.Service<Identifier<Name>, Service<OwnEvents>>(`effect-assistant/Assistant/${name}`)\n\n // The app's own events go to the engine encoded, as they're stored; the library's go unchanged.\n const stored = (\n input: AssistantEvent.Input | OwnEvents\n ): Effect.Effect<AssistantEvent.Input | AssistantEvent.StoredAppEvent> =>\n AssistantEvent.isInput(input) ? Effect.succeed(input) : AppEvents.encode(definition.app, input)\n\n const ChatKey = Context.Service<ChatIdentifier<Name>, Chat<OwnEvents>>(`effect-assistant/Assistant/${name}/Chat`)\n\n // On the engine and the app's `Chats` the layer was given, so every caller sees the same ones.\n const makeService = Effect.gen(function* () {\n const engine = yield* AssistantEngine\n const chats = yield* Chats.Chats\n\n return Key.of({\n submit: Effect.fn(\"Assistant.submit\")(function* (chatId: ChatId, input: AssistantEvent.Input | OwnEvents) {\n // Checked here, where the caller can handle it: the chat checks again when it stores the input.\n yield* chats.get(chatId)\n yield* engine.submit(name, chatId, yield* stored(input))\n }),\n subscribe: (chatId, options) =>\n engine\n .subscribe(name, chatId, options?.after ?? 0)\n .pipe(\n Stream.filterMap(\n Filter.fromPredicateOption((entry: AssistantEvent.Entry) => AppEvents.decodeEntry(definition.app, entry))\n )\n ),\n delete: (chatId) => engine.delete(name, chatId)\n })\n })\n\n // The signature checks what the handler uses (`CheckServices`); the layer's services, which the build\n // required, are provided to it and to every turn's stream, so what's left is the turn services.\n function toLayer<R = never, RE = never, E = never, RX = never>(\n build: (Handler<R, RE, OwnEvents> | Effect.Effect<Handler<R, RE, OwnEvents>, E, RX>) &\n Specialist.CheckServices<Exclude<HandlerServices<R | RE>, RX | ChatIdentifier<Name>>>\n ): Layer.Layer<\n Identifier<Name>,\n never,\n | AssistantEngine\n | LanguageModel.LanguageModel\n | Specialist.HandlerOf<Specs[number]>\n | Exclude<RX, Scope.Scope | CurrentChat | ChatIdentifier<Name>>\n | Specialist.ToolHandlers<R | RE>\n >\n function toLayer(\n build: Handler<any, any, any> | Effect.Effect<Handler<any, any, any>, unknown, any>\n ): Layer.Layer<Identifier<Name>, never, any> {\n return Layer.effect(\n Key,\n Effect.gen(function* () {\n const context = yield* Effect.context()\n\n const registration = yield* Turns.register(definition, {\n // The build runs per chat activation, in the chat; here it only keeps the layer's services for it.\n open: (typed) =>\n Effect.gen(function* () {\n // The chat's entries are already decoded with this assistant's events.\n const chat = ChatKey.of({ chatId: typed.chatId, entries: typed.entries, append: typed.append })\n const handler = Effect.isEffect(build) ? yield* Effect.provideService(build, ChatKey, chat) : build\n\n return (turn: Turn<any>) =>\n Stream.provideContext(toStream(handler(turn)), context).pipe(Stream.provideService(ChatKey, chat))\n }).pipe(Effect.provideContext(context), Effect.orDie)\n })\n\n yield* (yield* AssistantEngine).register(registration)\n\n return yield* makeService\n })\n )\n }\n\n // The key is a function, whose own `name` is read-only: the assistant's name replaces it.\n const named = Object.defineProperty(Key, \"name\", { value: name, writable: true })\n\n return Object.assign(named, {\n [TypeId]: TypeId,\n name,\n blocks: options?.blocks,\n specialists: options?.specialists ?? [],\n events,\n toLayer,\n layerClient: Layer.effect(Key, makeService),\n Chat: ChatKey,\n Entry: entrySchema<OwnEvents>(events)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAuCA,MAAM,SAAS;AAwMf,MAAM,YACJ,WAGyD,OAAO,SAAS,MAAM,IAAI,OAAO,OAAO,MAAM,IAAI;;;;;;;AAuN7G,MAAa,eAAe,MAAyB,UAAU,YAAY,GAAG,MAAM;AAIpF,SAAS,YAAY,QAAkE;CACrF,OAAO,OAAO,YACZ,OAAO,OAAO;EACZ,QAAQ;EACR,KAAK,OAAO;EACZ,IAAI,OAAO;EACX,OAAO,OAAO,MAAM,CAACA,gBAA+B,GAAG,MAAM,CAAC;CAChE,CAAC,CACH;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAa,QAKX,MACA,YAgB2D;CAC3D,MAAM,SAAS,SAAS,UAAU,CAAC;CAEnC,MAAM,aAA+B;EACnC;EACA,QAAQ,SAAS;EACjB,aAAa,SAAS,eAAe,CAAC;EACtC,KAAKC,OAAe,MAAM;CAC5B;CAIA,MAAM,MAAM,QAAQ,QAA8C,8BAA8B,MAAM;CAGtG,MAAM,UACJ,UAEAC,QAAuB,KAAK,IAAI,OAAO,QAAQ,KAAK,IAAIC,OAAiB,WAAW,KAAK,KAAK;CAEhG,MAAM,UAAU,QAAQ,QAA+C,8BAA8B,KAAK,MAAM;CAGhH,MAAM,cAAc,OAAO,IAAI,aAAa;EAC1C,MAAM,SAAS,OAAO;EACtB,MAAM,QAAQ,OAAOC;EAErB,OAAO,IAAI,GAAG;GACZ,QAAQ,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAAW,QAAgB,OAAyC;IAExG,OAAO,MAAM,IAAI,MAAM;IACvB,OAAO,OAAO,OAAO,MAAM,QAAQ,OAAO,OAAO,KAAK,CAAC;GACzD,CAAC;GACD,YAAY,QAAQ,YAClB,OACG,UAAU,MAAM,QAAQ,SAAS,SAAS,CAAC,CAAC,CAC5C,KACC,OAAO,UACL,OAAO,qBAAqB,UAAgCC,YAAsB,WAAW,KAAK,KAAK,CAAC,CAC1G,CACF;GACJ,SAAS,WAAW,OAAO,OAAO,MAAM,MAAM;EAChD,CAAC;CACH,CAAC;CAgBD,SAAS,QACP,OAC2C;EAC3C,OAAO,MAAM,OACX,KACA,OAAO,IAAI,aAAa;GACtB,MAAM,UAAU,OAAO,OAAO,QAAQ;GAEtC,MAAM,eAAe,OAAOC,SAAe,YAAY,EAErD,OAAO,UACL,OAAO,IAAI,aAAa;IAEtB,MAAM,OAAO,QAAQ,GAAG;KAAE,QAAQ,MAAM;KAAQ,SAAS,MAAM;KAAS,QAAQ,MAAM;IAAO,CAAC;IAC9F,MAAM,UAAU,OAAO,SAAS,KAAK,IAAI,OAAO,OAAO,eAAe,OAAO,SAAS,IAAI,IAAI;IAE9F,QAAQ,SACN,OAAO,eAAe,SAAS,QAAQ,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK,OAAO,eAAe,SAAS,IAAI,CAAC;GACrG,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,OAAO,GAAG,OAAO,KAAK,EACxD,CAAC;GAED,QAAQ,OAAO,gBAAA,CAAiB,SAAS,YAAY;GAErD,OAAO,OAAO;EAChB,CAAC,CACH;CACF;CAGA,MAAM,QAAQ,OAAO,eAAe,KAAK,QAAQ;EAAE,OAAO;EAAM,UAAU;CAAK,CAAC;CAEhF,OAAO,OAAO,OAAO,OAAO;GACzB,SAAS;EACV;EACA,QAAQ,SAAS;EACjB,aAAa,SAAS,eAAe,CAAC;EACtC;EACA;EACA,aAAa,MAAM,OAAO,KAAK,WAAW;EAC1C,MAAM;EACN,OAAO,YAAuB,MAAM;CACtC,CAAC;AACH"}
|
|
1
|
+
{"version":3,"file":"Assistant.js","names":["AssistantEvent.AssistantEvent","AppEvents.make","AssistantEvent.isInput","AppEvents.encode","Chats.Chats","AppEvents.decodeEntry","Turns.register"],"sources":["../src/Assistant.ts"],"sourcesContent":["/**\n * This module provides `Assistant.make`, which defines an assistant that works in a chat the way a\n * colleague does: the user messages it, it works in the background with the app's tools, and it\n * messages the user back.\n *\n * A definition is what the rest of an app imports. Yielding it (`yield* MyAssistant`) returns the\n * assistant's {@link Service}, which submits inputs to chats and streams them back. Its `toLayer`\n * registers the handler that runs each {@link Turn} with the `AssistantEngine`, and its\n * `layerClient` provides the service without a handler. Code that runs inside a chat reads and\n * extends that chat through the definition's {@link Chat} key.\n *\n * @since 0.1.0\n */\nimport type * as AiError from \"effect/ai/AiError\"\nimport type * as LanguageModel from \"effect/ai/LanguageModel\"\nimport type * as Prompt from \"effect/ai/Prompt\"\nimport type * as Tool from \"effect/ai/Tool\"\nimport type * as Toolkit from \"effect/ai/Toolkit\"\nimport * as Context from \"effect/Context\"\nimport * as Effect from \"effect/Effect\"\nimport * as Filter from \"effect/Filter\"\nimport * as Layer from \"effect/Layer\"\nimport * as Predicate from \"effect/Predicate\"\nimport * as Schema from \"effect/Schema\"\nimport type * as Scope from \"effect/Scope\"\nimport * as Stream from \"effect/Stream\"\nimport { AssistantEngine } from \"./AssistantEngine.ts\"\nimport * as AssistantEvent from \"./AssistantEvent.ts\"\nimport type * as AssistantLoop from \"./AssistantLoop.ts\"\nimport type * as BlockKit from \"./BlockKit.ts\"\nimport { ChatId } from \"./ChatId.ts\"\nimport * as Chats from \"./Chats.ts\"\nimport type { CurrentChat } from \"./CurrentChat.ts\"\nimport type * as Instructions from \"./Instructions.ts\"\nimport * as AppEvents from \"./internal/events.ts\"\nimport * as Turns from \"./internal/turns.ts\"\nimport type * as Specialist from \"./Specialist.ts\"\n\nconst TypeId = \"~effect-assistant/Assistant\" as const\n\n/**\n * Represents the services that a turn provides to its tools, its loop, and its specialists. These\n * are the turn's chat (`CurrentChat`) and the chat's specialist runner (`Specialist.Runner`).\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type TurnServices = CurrentChat | Specialist.Runner\n\n/**\n * Represents the options accepted by `turn.loop`.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface LoopOptions<T extends Record<string, Tool.Any> = Record<never, never>, Events = never> {\n /** The assistant's role and rules. The loop places `Instructions.protocol` before them. */\n readonly instructions: string | Instructions.Resolved\n /**\n * Tools the model can use in addition to the assistant's own. This is an `effect/ai` toolkit,\n * and its handlers come from the layer. Combine several toolkits with `Toolkit.merge`, for\n * example `Memory.Tools`, a `Skill.toolkit(...)`, or a `ToolDiscovery.make(...)` toolkit together\n * with your own.\n */\n readonly toolkit?: Toolkit.Toolkit<T> | undefined\n /** The maximum number of model calls per turn. Defaults to 16. */\n readonly maxSteps?: number | undefined\n /** The message the reply pass gives the model when the turn would end without a reply. */\n readonly replyNudge?: string | undefined\n /**\n * Selects which of the chat's entries the model reads, for example only those since the last\n * summary, and maps the app's own events it should read into prompt messages. Defaults to all\n * entries, without the app's events.\n */\n readonly history?: HistoryView<Events> | undefined\n}\n\n/**\n * Represents a function that selects which of a chat's entries the model reads, and what else it\n * reads with them.\n *\n * **Details**\n *\n * The function receives the chat's entries, the app's own events among them, and returns, in\n * order, a mix of entries and `Prompt.Message`s. The model reads the returned entries the same way\n * it reads the full history, and reads each prompt message unchanged, where the view put it. The\n * model reads none of the app's events by itself: map those it should read to a message, and an\n * app event's entry left in the result is dropped.\n *\n * A message stands right after the entry before it: one that came after the model's last read, or\n * between a tool call and its result, moves after them, as an input does.\n *\n * **Example** (Telling the model about an order the user placed)\n *\n * ```ts\n * import { Assistant, InputId } from \"effect-assistant\"\n * import * as Prompt from \"effect/ai/Prompt\"\n * import * as Schema from \"effect/Schema\"\n *\n * class OrderPlaced extends Schema.TaggedClass<OrderPlaced>()(\"OrderPlaced\", {\n * id: InputId.InputId,\n * reference: Schema.String\n * }) {}\n *\n * const MyAssistant = Assistant.make(\"my-assistant\", { events: [OrderPlaced] })\n *\n * const withOrders: Assistant.HistoryView<OrderPlaced> = (entries) =>\n * entries.map((entry) =>\n * entry.event instanceof OrderPlaced\n * ? Prompt.userMessage({\n * content: [Prompt.textPart({ text: `The user placed order ${entry.event.reference}.` })]\n * })\n * : entry\n * )\n *\n * // An `OrderPlaced` that the API submits wakes a turn, which reads it as this note.\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({ instructions: \"Be brief.\", history: withOrders })\n * )\n * ```\n *\n * @category models\n * @since 0.1.0\n */\nexport type HistoryView<Events = never> = (\n entries: ReadonlyArray<Entry<Events>>\n) => ReadonlyArray<Entry<Events> | Prompt.Message>\n\n/**\n * Represents an entry in a chat's log, with the assistant's own events decoded to their types.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Entry<Events = never> {\n readonly chatId: ChatId\n readonly seq: number\n readonly at: number\n readonly event: AssistantEvent.AssistantEvent | Events\n}\n\n/**\n * Represents the options accepted by `turn.replyIfOwed`.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface ReplyOptions {\n /** The assistant's instructions, as passed to `turn.loop`. `Instructions.protocol` is added. */\n readonly instructions: string | Instructions.Resolved\n /**\n * The message given to the model after the history. Defaults to a message saying that it\n * hasn't replied yet and should reply now.\n */\n readonly nudge?: string | undefined\n}\n\n/**\n * Represents one turn, as the assistant's handler receives it.\n *\n * `Events` is the type of the app's own events that the assistant registered with its `events`\n * option.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Turn<Events = never> {\n readonly chatId: ChatId\n /**\n * Returns the model's history, built from the chat's entries (all of them, or those a view\n * keeps), together with how far into the chat it reaches.\n *\n * Read it before every model call, as the loop does. Each step records how far its model call\n * read, and the turn ends once it has handled what the model saw. An input that arrived after\n * that is handled by the next turn.\n */\n readonly history: (view?: HistoryView<Events>) => Effect.Effect<AssistantLoop.ChatHistory>\n /**\n * Returns the full system prompt for the given instructions. It contains\n * `Instructions.protocol`, the instructions, and the specialist runs that are working now.\n */\n readonly instructions: (instructions: string | Instructions.Resolved) => Instructions.Resolved\n /**\n * Runs the agent loop over the chat. The loop uses `Instructions.protocol`, the assistant's own\n * tools, and the instructions and tools in `options`. Every step is a tool call, and\n * the loop ends with `replyIfOwed`.\n */\n readonly loop: <T extends Record<string, Tool.Any> = Record<never, never>>(\n options: LoopOptions<T, Events>\n ) => Stream.Stream<\n AssistantLoop.Event,\n AiError.AiError,\n LanguageModel.LanguageModel | TurnServices | AssistantLoop.ToolkitServices<T>\n >\n /**\n * Runs one more pass when the turn would otherwise end without a reply to the user's latest\n * message. In this pass the model can only reply.\n *\n * The stream is empty when no reply is owed, or when an input arrived that the next turn will\n * read. `loop` runs this pass with its own prompt and tools, so the pass reuses the cached\n * prompt.\n */\n readonly replyIfOwed: (\n options: ReplyOptions\n ) => Stream.Stream<AssistantLoop.Event, AiError.AiError, LanguageModel.LanguageModel | TurnServices>\n}\n\n/**\n * Represents an assistant's handler, which runs a turn and returns it as a stream of the loop's\n * events.\n *\n * The handler may return the stream directly or from an Effect. `R` is the services the stream\n * requires, and `RE` is the services the Effect requires.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Handler<R = never, RE = R, Events = never> = (\n turn: Turn<Events>\n) =>\n | Stream.Stream<AssistantLoop.Event, unknown, R>\n | Effect.Effect<Stream.Stream<AssistantLoop.Event, unknown, R>, unknown, RE>\n\n/**\n * Computes the services an assistant's handler needs beyond those its turns provide (the turn\n * services and `LanguageModel`) and its tools' handlers (which its layer requires). These are the\n * services that its build Effect must require.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type HandlerServices<R> = Exclude<R, TurnServices | LanguageModel.LanguageModel | Tool.Handler<string>>\n\nconst toStream = <R, RE>(\n result:\n | Stream.Stream<AssistantLoop.Event, unknown, R>\n | Effect.Effect<Stream.Stream<AssistantLoop.Event, unknown, R>, unknown, RE>\n): Stream.Stream<AssistantLoop.Event, unknown, R | RE> => (Effect.isEffect(result) ? Stream.unwrap(result) : result)\n\n/**\n * Identifies an assistant's service in a context. Each assistant has its own identifier, keyed by\n * its name.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Identifier<Name extends string> {\n readonly \"~effect-assistant/Assistant\": Name\n}\n\n/**\n * Identifies, in a context, the chat that an assistant's turns run in.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface ChatIdentifier<Name extends string> {\n readonly \"~effect-assistant/Assistant/Chat\": Name\n}\n\n/**\n * Represents the chat that a turn of this assistant runs in, typed with the assistant's events.\n *\n * Use `yield* MyAssistant.Chat` in the handler, in the handler's build, or in a tool that its\n * turns run. Code that doesn't know the assistant uses `CurrentChat` instead.\n *\n * @see {@link CurrentChat} for the same chat without the assistant's event types\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Chat<Events = never> {\n readonly chatId: ChatId\n /**\n * The chat's entries so far, in order. They include the library's events and the assistant's\n * own events, typed.\n */\n readonly entries: Effect.Effect<ReadonlyArray<Entry<Events>>>\n /**\n * Appends events after the chat's last entry and sends them to the chat's subscribers. The\n * events can be the library's or the assistant's own, such as a summary. None of them wakes a\n * turn: only what comes in through the assistant's `submit` does.\n */\n append(...events: ReadonlyArray<AssistantEvent.AssistantEvent | Events>): Effect.Effect<void>\n}\n\n/**\n * Represents the service that `yield* MyAssistant` returns. It gives code outside a chat, such as\n * a server or a workflow, access to the assistant's chats. Code that runs inside a chat uses\n * `CurrentChat` instead.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Service<Events = never> {\n /**\n * Stores an input or one of the assistant's own events, then returns. Examples are a user's\n * message or block answer, a workflow's progress, or the order the user placed. Each one is an\n * input: storing it wakes a turn, which the assistant runs in the background. The handler decides\n * what the turn does with it, and an app event the model should read needs a history view that\n * maps it (see {@link HistoryView}). To store an app event without waking a turn, append it from\n * within the chat instead (`yield* MyAssistant.Chat`).\n *\n * Fails with `GetChatError` when the app's `Chats` service reports that the chat can't be used,\n * because the app doesn't know the chat or has deleted it.\n */\n // Method syntax: a service for these events is one for any (`Service<any>`), for helpers over assistants.\n submit(chatId: ChatId, input: AssistantEvent.Input | Events): Effect.Effect<void, Chats.GetChatError>\n /**\n * Streams the chat's stored entries, then live ones, with the assistant's own events decoded.\n * A reader that already has the earlier entries passes `after` and receives only the entries\n * after that `seq`.\n *\n * For a chat client, pipe the whole log into `Timeline.changes(MyAssistant, { after })`, which\n * streams the chat's timeline, as its user sees it. Its `after` goes there, not here: a message\n * on the timeline depends on earlier entries. The timeline shows only the app events named in its\n * `show`, none by default (see `Timeline.changes`).\n */\n readonly subscribe: (\n chatId: ChatId,\n options?: { readonly after?: number | undefined }\n ) => Stream.Stream<Entry<Events>>\n /**\n * Deletes a chat by storing a `ChatDeleted` event and stopping everything that works in it.\n *\n * **Details**\n *\n * A turn or specialist run working in the chat stops, and subscribers' streams end with the\n * `ChatDeleted` event. After that the chat stores nothing more: a later input, a run's report,\n * or a workflow's event for it is dropped without an error. The log is kept, and removing it is\n * up to the app. Deleting a chat a second time does nothing.\n *\n * When the app's `Chats` service reports a chat as deleted, the assistant deletes it in the same\n * way the next time it checks. It checks before an input is stored and before each model call.\n */\n readonly delete: (chatId: ChatId) => Effect.Effect<void>\n}\n\n/**\n * Represents an assistant's definition.\n *\n * The definition holds what callers and the UI need to know about the assistant, builds its\n * handler's layer, and is the key of its service (`yield* MyAssistant`). `Events` is the type of\n * the app's own events that the assistant registered.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Assistant<\n Name extends string = string,\n Specs extends Specialist.Any = never,\n Events = never\n> extends Context.Service<Identifier<Name>, Service<Events>> {\n readonly [TypeId]: typeof TypeId\n readonly name: Name\n readonly blocks: BlockKit.BlockKit | undefined\n /** The specialists the assistant can hand work to. */\n readonly specialists: ReadonlyArray<Specs>\n /** The schemas of the app's own events the assistant stores. */\n readonly events: ReadonlyArray<AssistantEvent.AppEventSchema>\n /**\n * Creates a layer that registers the assistant's handler with the engine and provides the\n * assistant's service.\n *\n * **Details**\n *\n * `build` is the handler, or an Effect that returns it. The handler may use the turn services,\n * `LanguageModel`, its tools' handlers (which the layer then requires), and services that its\n * build Effect required (see `Specialist.CheckServices`). The layer requires the\n * `AssistantEngine`, the `LanguageModel`, and each specialist's handler\n * (`Research.toLayer(...)`).\n *\n * **Example** (Providing an assistant's handler)\n *\n * ```ts\n * import { Assistant, AssistantEngine, ChatLog } from \"effect-assistant\"\n * import type * as LanguageModel from \"effect/ai/LanguageModel\"\n * import * as Layer from \"effect/Layer\"\n *\n * declare const ModelLive: Layer.Layer<LanguageModel.LanguageModel>\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({ instructions: \"You help a small team. Be brief.\" })\n * )\n *\n * const AppLive = MyAssistantLive.pipe(\n * Layer.provide(ModelLive),\n * Layer.provideMerge(AssistantEngine.layerMemory),\n * Layer.provideMerge(ChatLog.layerMemory)\n * )\n * ```\n */\n readonly toLayer: <R = never, RE = never, E = never, RX = never>(\n build: (Handler<R, RE, Events> | Effect.Effect<Handler<R, RE, Events>, E, RX>) &\n Specialist.CheckServices<Exclude<HandlerServices<R | RE>, RX | ChatIdentifier<Name>>>\n ) => Layer.Layer<\n Identifier<Name>,\n never,\n | AssistantEngine\n | LanguageModel.LanguageModel\n | Specialist.HandlerOf<Specs>\n | Exclude<RX, Scope.Scope | CurrentChat | ChatIdentifier<Name>>\n | Specialist.ToolHandlers<R | RE>\n >\n /**\n * A layer that provides the assistant's service without its handler.\n *\n * **When to use**\n *\n * Use it in a process that submits to chats that another process runs, such as a web server in\n * front of a cluster.\n *\n * **Example** (Serving clients in front of a cluster)\n *\n * ```ts\n * import { Assistant, AssistantEngine } from \"effect-assistant\"\n * import * as Layer from \"effect/Layer\"\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * // Requires `Sharding`. The cluster's runners run the chats, with `AssistantEngine.layerCluster`.\n * const MyAssistantClient = MyAssistant.layerClient.pipe(\n * Layer.provide(AssistantEngine.layerClusterClient)\n * )\n * ```\n */\n readonly layerClient: Layer.Layer<Identifier<Name>, never, AssistantEngine>\n /**\n * The key of the chat that the assistant's turns run in, typed with its events. See\n * {@link Chat}.\n */\n readonly Chat: Context.Service<ChatIdentifier<Name>, Chat<Events>>\n /** A schema that encodes the chat's entries to JSON, including the assistant's own events. */\n readonly Entry: Schema.Codec<Entry<Events>, Schema.Json>\n}\n\n/**\n * Represents any assistant, for use in generic constraints.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type Any = Assistant<any, any, any>\n\n/**\n * Returns `true` when the value is an assistant's definition, created with {@link make}.\n *\n * @category guards\n * @since 0.1.0\n */\nexport const isAssistant = (u: unknown): u is Any => Predicate.hasProperty(u, TypeId)\n\nfunction entrySchema<E>(events: ReadonlyArray<AssistantEvent.AppEventSchema>): Schema.Codec<Entry<E>, Schema.Json>\n// The overload states the decoded type: the library's events, or one of these schemas' types.\nfunction entrySchema(events: ReadonlyArray<AssistantEvent.AppEventSchema>): Schema.Top {\n return Schema.toCodecJson(\n Schema.Struct({\n chatId: ChatId,\n seq: Schema.Int,\n at: Schema.Finite,\n event: Schema.Union([AssistantEvent.AssistantEvent, ...events])\n })\n )\n}\n\n/**\n * Creates an assistant definition from its name, its UI blocks, its specialists, and the schemas of\n * the app's own events it stores.\n *\n * **Details**\n *\n * The definition holds no code that runs turns. Provide a handler with its `toLayer`, then yield\n * the definition to get the assistant's {@link Service}.\n *\n * The definition only says which of the app's events a chat stores. What happens with one is up\n * to the places that use it. One that comes in through the service's `submit`, from outside a\n * turn, is an input and wakes a turn, like a user's message; one a turn appends to its chat never\n * does. The handler decides what a turn does, a history view says how the model reads an event\n * ({@link HistoryView}), and the chat's timeline says which its user sees\n * (`Timeline.changes`).\n *\n * **Example** (Defining an assistant and submitting a message)\n *\n * ```ts\n * import { Assistant, AssistantEvent, ChatId } from \"effect-assistant\"\n * import * as Effect from \"effect/Effect\"\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\")\n *\n * const program = Effect.gen(function* () {\n * const assistant = yield* MyAssistant\n * const chatId = yield* ChatId.make()\n *\n * yield* assistant.submit(chatId, AssistantEvent.UserMessage.make({ text: \"Weather in Oslo?\" }))\n * })\n * ```\n *\n * @see {@link Assistant} for the definition's members\n * @see {@link Service} for what `yield* MyAssistant` returns\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <\n const Name extends string,\n const Specs extends ReadonlyArray<Specialist.Any> = readonly [],\n const Events extends ReadonlyArray<AssistantEvent.AppEventSchema> = readonly []\n>(\n name: Name,\n options?: {\n /** UI blocks the assistant can add to its messages. */\n readonly blocks?: BlockKit.BlockKit | undefined\n /**\n * The specialists the assistant can hand work to. Each specialist's `toLayer` must be\n * provided to the assistant's layer.\n */\n readonly specialists?: Specs | undefined\n /**\n * The schemas of the app's own events, each a tagged struct or class. `submit` and the chat's\n * `append` store them, in their JSON form, and the chat's `entries` and `subscribe` read them\n * back, decoded. Each needs a tag of its own that isn't one of the library's: `make` throws\n * otherwise.\n */\n readonly events?: Events | undefined\n }\n): Assistant<Name, Specs[number], Events[number][\"Type\"]> => {\n const events = options?.events ?? []\n\n const definition: Turns.Definition = {\n name,\n blocks: options?.blocks,\n specialists: options?.specialists ?? [],\n app: AppEvents.make(events)\n }\n\n type OwnEvents = Events[number][\"Type\"]\n\n const Key = Context.Service<Identifier<Name>, Service<OwnEvents>>(`effect-assistant/Assistant/${name}`)\n\n // The app's own events go to the engine encoded, as they're stored; the library's go unchanged.\n const stored = (\n input: AssistantEvent.Input | OwnEvents\n ): Effect.Effect<AssistantEvent.Input | AssistantEvent.StoredAppEvent> =>\n AssistantEvent.isInput(input) ? Effect.succeed(input) : AppEvents.encode(definition.app, input)\n\n const ChatKey = Context.Service<ChatIdentifier<Name>, Chat<OwnEvents>>(`effect-assistant/Assistant/${name}/Chat`)\n\n // On the engine and the app's `Chats` the layer was given, so every caller sees the same ones.\n const makeService = Effect.gen(function* () {\n const engine = yield* AssistantEngine\n const chats = yield* Chats.Chats\n\n return Key.of({\n submit: Effect.fn(\"Assistant.submit\")(function* (chatId: ChatId, input: AssistantEvent.Input | OwnEvents) {\n // Checked here, where the caller can handle it: the chat checks again when it stores the input.\n yield* chats.get(chatId)\n yield* engine.submit(name, chatId, yield* stored(input))\n }),\n subscribe: (chatId, options) =>\n engine\n .subscribe(name, chatId, options?.after ?? 0)\n .pipe(\n Stream.filterMap(\n Filter.fromPredicateOption((entry: AssistantEvent.Entry) => AppEvents.decodeEntry(definition.app, entry))\n )\n ),\n delete: (chatId) => engine.delete(name, chatId)\n })\n })\n\n // The signature checks what the handler uses (`CheckServices`); the layer's services, which the build\n // required, are provided to it and to every turn's stream, so what's left is the turn services.\n function toLayer<R = never, RE = never, E = never, RX = never>(\n build: (Handler<R, RE, OwnEvents> | Effect.Effect<Handler<R, RE, OwnEvents>, E, RX>) &\n Specialist.CheckServices<Exclude<HandlerServices<R | RE>, RX | ChatIdentifier<Name>>>\n ): Layer.Layer<\n Identifier<Name>,\n never,\n | AssistantEngine\n | LanguageModel.LanguageModel\n | Specialist.HandlerOf<Specs[number]>\n | Exclude<RX, Scope.Scope | CurrentChat | ChatIdentifier<Name>>\n | Specialist.ToolHandlers<R | RE>\n >\n function toLayer(\n build: Handler<any, any, any> | Effect.Effect<Handler<any, any, any>, unknown, any>\n ): Layer.Layer<Identifier<Name>, never, any> {\n return Layer.effect(\n Key,\n Effect.gen(function* () {\n const context = yield* Effect.context()\n\n const registration = yield* Turns.register(definition, {\n // The build runs per chat activation, in the chat; here it only keeps the layer's services for it.\n open: (typed) =>\n Effect.gen(function* () {\n // The chat's entries are already decoded with this assistant's events.\n const chat = ChatKey.of({ chatId: typed.chatId, entries: typed.entries, append: typed.append })\n const handler = Effect.isEffect(build) ? yield* Effect.provideService(build, ChatKey, chat) : build\n\n return (turn: Turn<any>) =>\n Stream.provideContext(toStream(handler(turn)), context).pipe(Stream.provideService(ChatKey, chat))\n }).pipe(Effect.provideContext(context), Effect.orDie)\n })\n\n yield* (yield* AssistantEngine).register(registration)\n\n return yield* makeService\n })\n )\n }\n\n // The key is a function, whose own `name` is read-only: the assistant's name replaces it.\n const named = Object.defineProperty(Key, \"name\", { value: name, writable: true })\n\n return Object.assign(named, {\n [TypeId]: TypeId,\n name,\n blocks: options?.blocks,\n specialists: options?.specialists ?? [],\n events,\n toLayer,\n layerClient: Layer.effect(Key, makeService),\n Chat: ChatKey,\n Entry: entrySchema<OwnEvents>(events)\n })\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AAsCA,MAAM,SAAS;AAmMf,MAAM,YACJ,WAGyD,OAAO,SAAS,MAAM,IAAI,OAAO,OAAO,MAAM,IAAI;;;;;;;AAuN7G,MAAa,eAAe,MAAyB,UAAU,YAAY,GAAG,MAAM;AAIpF,SAAS,YAAY,QAAkE;CACrF,OAAO,OAAO,YACZ,OAAO,OAAO;EACZ,QAAQ;EACR,KAAK,OAAO;EACZ,IAAI,OAAO;EACX,OAAO,OAAO,MAAM,CAACA,gBAA+B,GAAG,MAAM,CAAC;CAChE,CAAC,CACH;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,MAAa,QAKX,MACA,YAgB2D;CAC3D,MAAM,SAAS,SAAS,UAAU,CAAC;CAEnC,MAAM,aAA+B;EACnC;EACA,QAAQ,SAAS;EACjB,aAAa,SAAS,eAAe,CAAC;EACtC,KAAKC,OAAe,MAAM;CAC5B;CAIA,MAAM,MAAM,QAAQ,QAA8C,8BAA8B,MAAM;CAGtG,MAAM,UACJ,UAEAC,QAAuB,KAAK,IAAI,OAAO,QAAQ,KAAK,IAAIC,OAAiB,WAAW,KAAK,KAAK;CAEhG,MAAM,UAAU,QAAQ,QAA+C,8BAA8B,KAAK,MAAM;CAGhH,MAAM,cAAc,OAAO,IAAI,aAAa;EAC1C,MAAM,SAAS,OAAO;EACtB,MAAM,QAAQ,OAAOC;EAErB,OAAO,IAAI,GAAG;GACZ,QAAQ,OAAO,GAAG,kBAAkB,CAAC,CAAC,WAAW,QAAgB,OAAyC;IAExG,OAAO,MAAM,IAAI,MAAM;IACvB,OAAO,OAAO,OAAO,MAAM,QAAQ,OAAO,OAAO,KAAK,CAAC;GACzD,CAAC;GACD,YAAY,QAAQ,YAClB,OACG,UAAU,MAAM,QAAQ,SAAS,SAAS,CAAC,CAAC,CAC5C,KACC,OAAO,UACL,OAAO,qBAAqB,UAAgCC,YAAsB,WAAW,KAAK,KAAK,CAAC,CAC1G,CACF;GACJ,SAAS,WAAW,OAAO,OAAO,MAAM,MAAM;EAChD,CAAC;CACH,CAAC;CAgBD,SAAS,QACP,OAC2C;EAC3C,OAAO,MAAM,OACX,KACA,OAAO,IAAI,aAAa;GACtB,MAAM,UAAU,OAAO,OAAO,QAAQ;GAEtC,MAAM,eAAe,OAAOC,SAAe,YAAY,EAErD,OAAO,UACL,OAAO,IAAI,aAAa;IAEtB,MAAM,OAAO,QAAQ,GAAG;KAAE,QAAQ,MAAM;KAAQ,SAAS,MAAM;KAAS,QAAQ,MAAM;IAAO,CAAC;IAC9F,MAAM,UAAU,OAAO,SAAS,KAAK,IAAI,OAAO,OAAO,eAAe,OAAO,SAAS,IAAI,IAAI;IAE9F,QAAQ,SACN,OAAO,eAAe,SAAS,QAAQ,IAAI,CAAC,GAAG,OAAO,CAAC,CAAC,KAAK,OAAO,eAAe,SAAS,IAAI,CAAC;GACrG,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,OAAO,GAAG,OAAO,KAAK,EACxD,CAAC;GAED,QAAQ,OAAO,gBAAA,CAAiB,SAAS,YAAY;GAErD,OAAO,OAAO;EAChB,CAAC,CACH;CACF;CAGA,MAAM,QAAQ,OAAO,eAAe,KAAK,QAAQ;EAAE,OAAO;EAAM,UAAU;CAAK,CAAC;CAEhF,OAAO,OAAO,OAAO,OAAO;GACzB,SAAS;EACV;EACA,QAAQ,SAAS;EACjB,aAAa,SAAS,eAAe,CAAC;EACtC;EACA;EACA,aAAa,MAAM,OAAO,KAAK,WAAW;EAC1C,MAAM;EACN,OAAO,YAAuB,MAAM;CACtC,CAAC;AACH"}
|
package/dist/AssistantEvent.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import * as Schema from "effect/Schema";
|
|
|
3
3
|
import * as Response from "effect/ai/Response";
|
|
4
4
|
import * as SchemaAST from "effect/SchemaAST";
|
|
5
5
|
declare namespace AssistantEvent_d_exports {
|
|
6
|
-
export { AnyEntry, AppEventSchema, AppTag, AssistantEvent, AssistantMessage, Attachment, BlockAnswer, BlocksClosed, ChatDeleted, Entry, Input, MessageBlock, ModelOutput, ModelPart, SpecialistFinished, SpecialistStarted, StoredAppEvent, ToolCallPart, ToolOutcome, ToolResult, ToolStarted, TurnCompleted, TurnFailed, TurnStarted, UserInput, UserMessage, assistantTexts, attachmentLine, formatSize, isAppInput, isInput, isLibraryEvent, isTurnEnd, isUserInput, isWaking, maxAttachments, textWithAttachments };
|
|
6
|
+
export { AnyEntry, AppEventSchema, AppTag, ApprovalDecision, ApprovalRequested, ApprovalsExpired, AssistantEvent, AssistantMessage, Attachment, BlockAnswer, BlocksClosed, ChatDeleted, Entry, Input, MessageBlock, ModelOutput, ModelPart, SpecialistFinished, SpecialistStarted, StoredAppEvent, ToolCallPart, ToolOutcome, ToolResult, ToolStarted, TurnCompleted, TurnFailed, TurnStarted, UserInput, UserMessage, assistantTexts, attachmentLine, formatSize, isAppInput, isInput, isLibraryEvent, isTurnEnd, isUserInput, isWaking, maxAttachments, textWithAttachments };
|
|
7
7
|
}
|
|
8
8
|
/**
|
|
9
9
|
* Schema for a file the user attached to a message, kept by reference.
|
|
@@ -117,13 +117,30 @@ declare const SpecialistFinished_base: Schema.Class<SpecialistFinished, Schema.T
|
|
|
117
117
|
* @since 0.1.0
|
|
118
118
|
*/
|
|
119
119
|
export declare class SpecialistFinished extends SpecialistFinished_base {}
|
|
120
|
+
declare const ApprovalDecision_base: Schema.Class<ApprovalDecision, Schema.TaggedStruct<"ApprovalDecision", {
|
|
121
|
+
readonly id: Schema.brand<Schema.String, "~effect-assistant/InputId">;
|
|
122
|
+
readonly callId: Schema.String;
|
|
123
|
+
readonly decision: Schema.Literals<readonly ["approved", "rejected"]>;
|
|
124
|
+
readonly reason: Schema.optional<Schema.String>;
|
|
125
|
+
}>, {}>;
|
|
126
|
+
/**
|
|
127
|
+
* Represents the user's decision on a tool call that waits for their approval: `"approved"`, so
|
|
128
|
+
* the call runs, or `"rejected"`, with an optional short reason the model reads.
|
|
129
|
+
*
|
|
130
|
+
* Its id is fixed per call (see `ToolApproval.approve`), so a decision is stored once. A decision on
|
|
131
|
+
* a call that isn't waiting any more (decided, or expired) isn't stored.
|
|
132
|
+
*
|
|
133
|
+
* @category schemas
|
|
134
|
+
* @since 0.4.0
|
|
135
|
+
*/
|
|
136
|
+
export declare class ApprovalDecision extends ApprovalDecision_base {}
|
|
120
137
|
/**
|
|
121
138
|
* Schema for every input `Assistant.submit` accepts.
|
|
122
139
|
*
|
|
123
140
|
* @category schemas
|
|
124
141
|
* @since 0.1.0
|
|
125
142
|
*/
|
|
126
|
-
export declare const Input: Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof SpecialistFinished]>;
|
|
143
|
+
export declare const Input: Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof SpecialistFinished, typeof ApprovalDecision]>;
|
|
127
144
|
/**
|
|
128
145
|
* Represents an input to an assistant.
|
|
129
146
|
*
|
|
@@ -132,7 +149,8 @@ export declare const Input: Schema.Union<readonly [typeof UserMessage, typeof Bl
|
|
|
132
149
|
*/
|
|
133
150
|
export type Input = typeof Input.Type;
|
|
134
151
|
/**
|
|
135
|
-
* Schema for the inputs from the chat's user, which are messages and
|
|
152
|
+
* Schema for the inputs from the chat's user, which are messages, block answers, and decisions on
|
|
153
|
+
* tool calls that wait for their approval.
|
|
136
154
|
*
|
|
137
155
|
* A turn owes each one a reply. It is also what a chat client usually may submit, since the app's
|
|
138
156
|
* events come from the server.
|
|
@@ -140,7 +158,7 @@ export type Input = typeof Input.Type;
|
|
|
140
158
|
* @category schemas
|
|
141
159
|
* @since 0.1.0
|
|
142
160
|
*/
|
|
143
|
-
export declare const UserInput: Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer]>;
|
|
161
|
+
export declare const UserInput: Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof ApprovalDecision]>;
|
|
144
162
|
/**
|
|
145
163
|
* Represents an input from the chat's user.
|
|
146
164
|
*
|
|
@@ -151,11 +169,15 @@ export type UserInput = typeof UserInput.Type;
|
|
|
151
169
|
declare const MessageBlock_base: Schema.Class<MessageBlock, Schema.Struct<{
|
|
152
170
|
readonly kind: Schema.String;
|
|
153
171
|
readonly props: Schema.Unknown;
|
|
172
|
+
readonly resultId: Schema.optional<Schema.String>;
|
|
154
173
|
}>, {}>;
|
|
155
174
|
/**
|
|
156
175
|
* Represents the UI shown with a message, as a block kind from the assistant's `BlockKit` and its
|
|
157
176
|
* props.
|
|
158
177
|
*
|
|
178
|
+
* A block that shows a tool's result (`Block.fromToolResult`) has the tool's name as its kind and
|
|
179
|
+
* the result's `resultId`.
|
|
180
|
+
*
|
|
159
181
|
* @category schemas
|
|
160
182
|
* @since 0.1.0
|
|
161
183
|
*/
|
|
@@ -314,6 +336,9 @@ declare const ToolResult_base: Schema.Class<ToolResult, Schema.TaggedStruct<"Too
|
|
|
314
336
|
readonly outcome: Schema.Literals<readonly ["success", "failure"]>;
|
|
315
337
|
readonly result: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
316
338
|
readonly reason: Schema.optional<Schema.String>;
|
|
339
|
+
readonly full: Schema.optional<Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
340
|
+
/** The id the model passes in a `tool_result` block to show this result. */
|
|
341
|
+
readonly resultId: Schema.optional<Schema.String>;
|
|
317
342
|
}>, {}>;
|
|
318
343
|
/**
|
|
319
344
|
* Represents the result of one tool call, as the model reads it.
|
|
@@ -322,6 +347,10 @@ declare const ToolResult_base: Schema.Class<ToolResult, Schema.TaggedStruct<"Too
|
|
|
322
347
|
* failure includes its reason when it has one, which is a `ToolFailure`'s `reason` or the
|
|
323
348
|
* failure's tag.
|
|
324
349
|
*
|
|
350
|
+
* When the model reads less than the whole success (a `ToolResult.modelView`, or the `resultId`
|
|
351
|
+
* added for a tool the assistant's blocks show), `full` holds the whole success, encoded by the
|
|
352
|
+
* tool's success schema.
|
|
353
|
+
*
|
|
325
354
|
* @category schemas
|
|
326
355
|
* @since 0.1.0
|
|
327
356
|
*/
|
|
@@ -408,13 +437,43 @@ declare const BlocksClosed_base: Schema.Class<BlocksClosed, Schema.TaggedStruct<
|
|
|
408
437
|
* @since 0.1.0
|
|
409
438
|
*/
|
|
410
439
|
export declare class BlocksClosed extends BlocksClosed_base {}
|
|
440
|
+
declare const ApprovalRequested_base: Schema.Class<ApprovalRequested, Schema.TaggedStruct<"ApprovalRequested", {
|
|
441
|
+
readonly callId: Schema.String;
|
|
442
|
+
readonly tool: Schema.String;
|
|
443
|
+
readonly params: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
444
|
+
}>, {}>;
|
|
445
|
+
/**
|
|
446
|
+
* Represents a tool call that waits for the user's approval instead of running: its tool needs
|
|
447
|
+
* approval (Effect's `needsApproval`).
|
|
448
|
+
*
|
|
449
|
+
* **Details**
|
|
450
|
+
*
|
|
451
|
+
* It holds the call's id, the tool, and its params, in JSON, as the model wrote them. The model
|
|
452
|
+
* reads it as the call's result, saying it waits for the user; the user's
|
|
453
|
+
* {@link ApprovalDecision} decides it, and an approved call runs then, with the same id.
|
|
454
|
+
*
|
|
455
|
+
* @category schemas
|
|
456
|
+
* @since 0.4.0
|
|
457
|
+
*/
|
|
458
|
+
export declare class ApprovalRequested extends ApprovalRequested_base {}
|
|
459
|
+
declare const ApprovalsExpired_base: Schema.Class<ApprovalsExpired, Schema.TaggedStruct<"ApprovalsExpired", {
|
|
460
|
+
readonly callIds: Schema.$Array<Schema.String>;
|
|
461
|
+
}>, {}>;
|
|
462
|
+
/**
|
|
463
|
+
* Represents tool calls that waited for the user's approval and won't run: the user moved on, like
|
|
464
|
+
* the ones `ToolApproval.closeStale` expires. The model reads that they weren't approved.
|
|
465
|
+
*
|
|
466
|
+
* @category schemas
|
|
467
|
+
* @since 0.4.0
|
|
468
|
+
*/
|
|
469
|
+
export declare class ApprovalsExpired extends ApprovalsExpired_base {}
|
|
411
470
|
/**
|
|
412
471
|
* Schema for every event the library defines.
|
|
413
472
|
*
|
|
414
473
|
* @category schemas
|
|
415
474
|
* @since 0.1.0
|
|
416
475
|
*/
|
|
417
|
-
export declare const AssistantEvent: Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof AssistantMessage, typeof ModelOutput, typeof ToolStarted, typeof ToolResult, typeof TurnStarted, typeof TurnCompleted, typeof TurnFailed, typeof SpecialistStarted, typeof SpecialistFinished, typeof BlocksClosed, typeof ChatDeleted]>;
|
|
476
|
+
export declare const AssistantEvent: Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof AssistantMessage, typeof ModelOutput, typeof ToolStarted, typeof ToolResult, typeof TurnStarted, typeof TurnCompleted, typeof TurnFailed, typeof SpecialistStarted, typeof SpecialistFinished, typeof BlocksClosed, typeof ApprovalRequested, typeof ApprovalDecision, typeof ApprovalsExpired, typeof ChatDeleted]>;
|
|
418
477
|
/**
|
|
419
478
|
* Represents an event the library defines.
|
|
420
479
|
*
|
|
@@ -535,7 +594,7 @@ export declare const Entry: Schema.Struct<{
|
|
|
535
594
|
readonly chatId: Schema.brand<Schema.TemplateLiteral<readonly ["chat:", Schema.String]>, "~effect-assistant/ChatId">;
|
|
536
595
|
readonly seq: Schema.Int;
|
|
537
596
|
readonly at: Schema.Finite;
|
|
538
|
-
readonly event: Schema.Union<readonly [Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof AssistantMessage, typeof ModelOutput, typeof ToolStarted, typeof ToolResult, typeof TurnStarted, typeof TurnCompleted, typeof TurnFailed, typeof SpecialistStarted, typeof SpecialistFinished, typeof BlocksClosed, typeof ChatDeleted]>, Schema.StructWithRest<Schema.Struct<{
|
|
597
|
+
readonly event: Schema.Union<readonly [Schema.Union<readonly [typeof UserMessage, typeof BlockAnswer, typeof AssistantMessage, typeof ModelOutput, typeof ToolStarted, typeof ToolResult, typeof TurnStarted, typeof TurnCompleted, typeof TurnFailed, typeof SpecialistStarted, typeof SpecialistFinished, typeof BlocksClosed, typeof ApprovalRequested, typeof ApprovalDecision, typeof ApprovalsExpired, typeof ChatDeleted]>, Schema.StructWithRest<Schema.Struct<{
|
|
539
598
|
readonly _tag: Schema.brand<Schema.String, "~effect-assistant/AppTag">;
|
|
540
599
|
readonly "~effect-assistant/input": Schema.optionalKey<Schema.Literal<true>>;
|
|
541
600
|
}>, readonly [Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>]>]>;
|
|
@@ -549,7 +608,7 @@ export declare const Entry: Schema.Struct<{
|
|
|
549
608
|
export type Entry = typeof Entry.Type;
|
|
550
609
|
/**
|
|
551
610
|
* Returns whether an event is one of the library's inputs, which are a user message, a block
|
|
552
|
-
* answer,
|
|
611
|
+
* answer, a finished specialist run, or a decision on a tool call waiting for approval.
|
|
553
612
|
*
|
|
554
613
|
* The application's events that came in through the assistant's `submit` are inputs too (see
|
|
555
614
|
* {@link isAppInput}).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AssistantEvent.d.ts","names":[],"sources":["../src/AssistantEvent.ts"],"mappings":";;;;;;;;;;;;;;;qBA2Ba,YAAU,OAAA;;;;;;;;;;;;;;;qBAgBV;;;;;;;YAQD,oBAAoB,WAAW;;;;;;;qBAQ9B,aAAU;;;;;;;;;qBAiBV,iBAAc,YAAgB;;;;;;;qBAS9B,sBAAmB,cAAgB,aAAe,cAAc;;;;;;;;;;;;;;;;;;;;;qBAchE,oBAAoB;;;;;;;;;;;;;;;;qBAepB,oBAAoB;;;;;;;;;;;;;;;;;;;;;qBAgBpB,2BAA2B;;;;;;;
|
|
1
|
+
{"version":3,"file":"AssistantEvent.d.ts","names":[],"sources":["../src/AssistantEvent.ts"],"mappings":";;;;;;;;;;;;;;;qBA2Ba,YAAU,OAAA;;;;;;;;;;;;;;;qBAgBV;;;;;;;YAQD,oBAAoB,WAAW;;;;;;;qBAQ9B,aAAU;;;;;;;;;qBAiBV,iBAAc,YAAgB;;;;;;;qBAS9B,sBAAmB,cAAgB,aAAe,cAAc;;;;;;;;;;;;;;;;;;;;;qBAchE,oBAAoB;;;;;;;;;;;;;;;;qBAepB,oBAAoB;;;;;;;;;;;;;;;;;;;;;qBAgBpB,2BAA2B;;;;;;;;;;;;;;;;;qBAsB3B,yBAAyB;;;;;;;qBAazB,OAAK,OAAA,uBAAA,oBAAA,oBAAA,2BAAA;;;;;;;YAQN,eAAe,MAAM;;;;;;;;;;;qBAYpB,WAAS,OAAA,uBAAA,oBAAA,oBAAA;;;;;;;YAQV,mBAAmB,UAAU;;;;;;;;;;;;;;;;qBAY5B,qBAAqB;;;;;;;;;;;;;;;qBAarB,yBAAyB;;;;;;;;;;qBAiBzB,cAAY,OAAA;;;;;;;;;;;;;;;YAWb,sBAAsB,aAAa;;;;;;;;;;qBAWlC,WAAS,OAAA,gBAAA,OAAA;;;;;;;;;;;;;;;;;;;;;;;;;YAQV,mBAAmB,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAU5B,oBAAoB;;;;;;;;;;;;;;qBA2BpB,oBAAoB;;;;;;;;qBAYpB,aAAW,OAAA;;;;;;;YAQZ,qBAAqB,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;qBAgBhC,mBAAmB;;;;;;;;;;;;;;;qBAiBnB,oBAAoB;;;;;;;;;;;;qBAiBpB,sBAAsB;;;;;;;;;;;;;;qBAatB,mBAAmB;;;;;;;;;;;;;;;;;qBAenB,0BAA0B;;;;;;;;;;;qBAgB1B,oBAAoB;;;;;;;;;;;;;qBAWpB,qBAAqB;;;;;;;;;;;;;;;;;;;qBAiBrB,0BAA0B;;;;;;;;;;;qBAa1B,yBAAyB;;;;;;;qBAUzB,gBAAc,OAAA,uBAAA,oBAAA,oBAAA,yBAAA,oBAAA,oBAAA,mBAAA,oBAAA,sBAAA,mBAAA,0BAAA,2BAAA,qBAAA,0BAAA,yBAAA,yBAAA;;;;;;;YAyBf,wBAAwB,eAAe;;;;;;;;;;;qBAgBtC,QAAM,OAAA,MAAA,OAAA;;;;;;;;;;;;;;YAeP,iBAAiB,OAAO;WAAiB;;WAA2B;;WACrE;aAAmB;eAAiB,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;qBAmBjD,gBAAc,OAAA,eAAA,OAAA;;;cAG0F,OAAA,QAAA,OAAA,QAAA,OAAA,MAAA,OAAA,MAAA,OAAA;;;;;;;YAQzG,wBAAwB,eAAe;;;;;;;qBAQtC,iBAAc;WAAsB;MAAiB,SAAS;;;;;;;;;;qBAW9D,aAAU;WAAsB;;;;;;;;;;;iBAY5B;WACN,QAAQ;WACR;WACA;WACA;aAAkB;;;;;;;;;;;;qBAYhB,OAAK,OAAA;;;;;;;;;;;;;;;YAaN,eAAe,MAAM;;;;;;;;;;;qBAYpB,UAAO;WAAsB;MAAiB,SAAS;;;;;;;;qBAavD,WAAQ,OAAW;;;;;;;qBASnB,cAAW,OAAW,UAAQ,SAAS;;;;;;;qBAWvC,YAAS;WAAsB;MAAiB,SAAS,gBAAgB;;;;;;;qBASzE,iBAAc,SAAa,cAAc,cAAY"}
|
package/dist/AssistantEvent.js
CHANGED
|
@@ -19,6 +19,9 @@ import * as Response from "effect/ai/Response";
|
|
|
19
19
|
*/
|
|
20
20
|
var AssistantEvent_exports = /* @__PURE__ */ __exportAll({
|
|
21
21
|
AppTag: () => AppTag,
|
|
22
|
+
ApprovalDecision: () => ApprovalDecision,
|
|
23
|
+
ApprovalRequested: () => ApprovalRequested,
|
|
24
|
+
ApprovalsExpired: () => ApprovalsExpired,
|
|
22
25
|
AssistantEvent: () => AssistantEvent,
|
|
23
26
|
AssistantMessage: () => AssistantMessage,
|
|
24
27
|
Attachment: () => Attachment,
|
|
@@ -156,6 +159,22 @@ var SpecialistFinished = class extends Schema.TaggedClass()("SpecialistFinished"
|
|
|
156
159
|
error: Schema.optional(Schema.String)
|
|
157
160
|
}) {};
|
|
158
161
|
/**
|
|
162
|
+
* Represents the user's decision on a tool call that waits for their approval: `"approved"`, so
|
|
163
|
+
* the call runs, or `"rejected"`, with an optional short reason the model reads.
|
|
164
|
+
*
|
|
165
|
+
* Its id is fixed per call (see `ToolApproval.approve`), so a decision is stored once. A decision on
|
|
166
|
+
* a call that isn't waiting any more (decided, or expired) isn't stored.
|
|
167
|
+
*
|
|
168
|
+
* @category schemas
|
|
169
|
+
* @since 0.4.0
|
|
170
|
+
*/
|
|
171
|
+
var ApprovalDecision = class extends Schema.TaggedClass()("ApprovalDecision", {
|
|
172
|
+
id: InputId,
|
|
173
|
+
callId: Schema.String,
|
|
174
|
+
decision: Schema.Literals(["approved", "rejected"]),
|
|
175
|
+
reason: Schema.optional(Schema.String.check(Schema.isMaxLength(500)))
|
|
176
|
+
}) {};
|
|
177
|
+
/**
|
|
159
178
|
* Schema for every input `Assistant.submit` accepts.
|
|
160
179
|
*
|
|
161
180
|
* @category schemas
|
|
@@ -164,10 +183,12 @@ var SpecialistFinished = class extends Schema.TaggedClass()("SpecialistFinished"
|
|
|
164
183
|
const Input = Schema.Union([
|
|
165
184
|
UserMessage,
|
|
166
185
|
BlockAnswer,
|
|
167
|
-
SpecialistFinished
|
|
186
|
+
SpecialistFinished,
|
|
187
|
+
ApprovalDecision
|
|
168
188
|
]);
|
|
169
189
|
/**
|
|
170
|
-
* Schema for the inputs from the chat's user, which are messages and
|
|
190
|
+
* Schema for the inputs from the chat's user, which are messages, block answers, and decisions on
|
|
191
|
+
* tool calls that wait for their approval.
|
|
171
192
|
*
|
|
172
193
|
* A turn owes each one a reply. It is also what a chat client usually may submit, since the app's
|
|
173
194
|
* events come from the server.
|
|
@@ -175,17 +196,25 @@ const Input = Schema.Union([
|
|
|
175
196
|
* @category schemas
|
|
176
197
|
* @since 0.1.0
|
|
177
198
|
*/
|
|
178
|
-
const UserInput = Schema.Union([
|
|
199
|
+
const UserInput = Schema.Union([
|
|
200
|
+
UserMessage,
|
|
201
|
+
BlockAnswer,
|
|
202
|
+
ApprovalDecision
|
|
203
|
+
]);
|
|
179
204
|
/**
|
|
180
205
|
* Represents the UI shown with a message, as a block kind from the assistant's `BlockKit` and its
|
|
181
206
|
* props.
|
|
182
207
|
*
|
|
208
|
+
* A block that shows a tool's result (`Block.fromToolResult`) has the tool's name as its kind and
|
|
209
|
+
* the result's `resultId`.
|
|
210
|
+
*
|
|
183
211
|
* @category schemas
|
|
184
212
|
* @since 0.1.0
|
|
185
213
|
*/
|
|
186
214
|
var MessageBlock = class extends Schema.Class("effect-assistant/MessageBlock")({
|
|
187
215
|
kind: Schema.String,
|
|
188
|
-
props: Schema.Unknown
|
|
216
|
+
props: Schema.Unknown,
|
|
217
|
+
resultId: Schema.optional(Schema.String)
|
|
189
218
|
}) {};
|
|
190
219
|
/**
|
|
191
220
|
* Represents a message the assistant sent the user with `send_user_message`, optionally with a
|
|
@@ -281,6 +310,10 @@ const ToolOutcome = Schema.Literals(["success", "failure"]);
|
|
|
281
310
|
* failure includes its reason when it has one, which is a `ToolFailure`'s `reason` or the
|
|
282
311
|
* failure's tag.
|
|
283
312
|
*
|
|
313
|
+
* When the model reads less than the whole success (a `ToolResult.modelView`, or the `resultId`
|
|
314
|
+
* added for a tool the assistant's blocks show), `full` holds the whole success, encoded by the
|
|
315
|
+
* tool's success schema.
|
|
316
|
+
*
|
|
284
317
|
* @category schemas
|
|
285
318
|
* @since 0.1.0
|
|
286
319
|
*/
|
|
@@ -289,7 +322,10 @@ var ToolResult = class extends Schema.TaggedClass()("ToolResult", {
|
|
|
289
322
|
tool: Schema.String,
|
|
290
323
|
outcome: ToolOutcome,
|
|
291
324
|
result: Schema.Json,
|
|
292
|
-
reason: Schema.optional(Schema.String)
|
|
325
|
+
reason: Schema.optional(Schema.String),
|
|
326
|
+
full: Schema.optional(Schema.Json),
|
|
327
|
+
/** The id the model passes in a `tool_result` block to show this result. */
|
|
328
|
+
resultId: Schema.optional(Schema.String)
|
|
293
329
|
}) {};
|
|
294
330
|
/**
|
|
295
331
|
* Represents the start of a turn.
|
|
@@ -364,6 +400,32 @@ var ChatDeleted = class extends Schema.TaggedClass()("ChatDeleted", {}) {};
|
|
|
364
400
|
*/
|
|
365
401
|
var BlocksClosed = class extends Schema.TaggedClass()("BlocksClosed", { messageIds: Schema.Array(Schema.String) }) {};
|
|
366
402
|
/**
|
|
403
|
+
* Represents a tool call that waits for the user's approval instead of running: its tool needs
|
|
404
|
+
* approval (Effect's `needsApproval`).
|
|
405
|
+
*
|
|
406
|
+
* **Details**
|
|
407
|
+
*
|
|
408
|
+
* It holds the call's id, the tool, and its params, in JSON, as the model wrote them. The model
|
|
409
|
+
* reads it as the call's result, saying it waits for the user; the user's
|
|
410
|
+
* {@link ApprovalDecision} decides it, and an approved call runs then, with the same id.
|
|
411
|
+
*
|
|
412
|
+
* @category schemas
|
|
413
|
+
* @since 0.4.0
|
|
414
|
+
*/
|
|
415
|
+
var ApprovalRequested = class extends Schema.TaggedClass()("ApprovalRequested", {
|
|
416
|
+
callId: Schema.String,
|
|
417
|
+
tool: Schema.String,
|
|
418
|
+
params: Schema.Json
|
|
419
|
+
}) {};
|
|
420
|
+
/**
|
|
421
|
+
* Represents tool calls that waited for the user's approval and won't run: the user moved on, like
|
|
422
|
+
* the ones `ToolApproval.closeStale` expires. The model reads that they weren't approved.
|
|
423
|
+
*
|
|
424
|
+
* @category schemas
|
|
425
|
+
* @since 0.4.0
|
|
426
|
+
*/
|
|
427
|
+
var ApprovalsExpired = class extends Schema.TaggedClass()("ApprovalsExpired", { callIds: Schema.Array(Schema.String) }) {};
|
|
428
|
+
/**
|
|
367
429
|
* Schema for every event the library defines.
|
|
368
430
|
*
|
|
369
431
|
* @category schemas
|
|
@@ -382,6 +444,9 @@ const AssistantEvent = Schema.Union([
|
|
|
382
444
|
SpecialistStarted,
|
|
383
445
|
SpecialistFinished,
|
|
384
446
|
BlocksClosed,
|
|
447
|
+
ApprovalRequested,
|
|
448
|
+
ApprovalDecision,
|
|
449
|
+
ApprovalsExpired,
|
|
385
450
|
ChatDeleted
|
|
386
451
|
]);
|
|
387
452
|
const libraryTags = new Set(AssistantEvent.members.map((member) => member.fields._tag.schema.literal));
|
|
@@ -450,7 +515,7 @@ const Entry = Schema.Struct({
|
|
|
450
515
|
});
|
|
451
516
|
/**
|
|
452
517
|
* Returns whether an event is one of the library's inputs, which are a user message, a block
|
|
453
|
-
* answer,
|
|
518
|
+
* answer, a finished specialist run, or a decision on a tool call waiting for approval.
|
|
454
519
|
*
|
|
455
520
|
* The application's events that came in through the assistant's `submit` are inputs too (see
|
|
456
521
|
* {@link isAppInput}).
|
|
@@ -458,7 +523,7 @@ const Entry = Schema.Struct({
|
|
|
458
523
|
* @category guards
|
|
459
524
|
* @since 0.1.0
|
|
460
525
|
*/
|
|
461
|
-
const isInput = (event) => Predicate.isTagged(event, "UserMessage") || Predicate.isTagged(event, "BlockAnswer") || Predicate.isTagged(event, "SpecialistFinished");
|
|
526
|
+
const isInput = (event) => Predicate.isTagged(event, "UserMessage") || Predicate.isTagged(event, "BlockAnswer") || Predicate.isTagged(event, "SpecialistFinished") || Predicate.isTagged(event, "ApprovalDecision");
|
|
462
527
|
/**
|
|
463
528
|
* Returns whether an input starts a turn, which every input does except a run the assistant
|
|
464
529
|
* stopped itself.
|
|
@@ -473,7 +538,7 @@ const isWaking = (input) => !(Predicate.isTagged(input, "SpecialistFinished") &&
|
|
|
473
538
|
* @category guards
|
|
474
539
|
* @since 0.1.0
|
|
475
540
|
*/
|
|
476
|
-
const isUserInput = (input) => Predicate.isTagged(input, "UserMessage") || Predicate.isTagged(input, "BlockAnswer");
|
|
541
|
+
const isUserInput = (input) => Predicate.isTagged(input, "UserMessage") || Predicate.isTagged(input, "BlockAnswer") || Predicate.isTagged(input, "ApprovalDecision");
|
|
477
542
|
/**
|
|
478
543
|
* Returns whether an event ends a turn, and so says how far the assistant has read.
|
|
479
544
|
*
|
|
@@ -489,6 +554,6 @@ const isTurnEnd = (event) => Predicate.isTagged(event, "TurnCompleted") || Predi
|
|
|
489
554
|
*/
|
|
490
555
|
const assistantTexts = (entries) => entries.flatMap(({ event }) => isLibraryEvent(event) && Predicate.isTagged(event, "AssistantMessage") ? [event.text] : []);
|
|
491
556
|
//#endregion
|
|
492
|
-
export { AppTag, AssistantEvent, AssistantEvent_exports, AssistantMessage, Attachment, BlockAnswer, BlocksClosed, ChatDeleted, Entry, Input, MessageBlock, ModelOutput, ModelPart, SpecialistFinished, SpecialistStarted, StoredAppEvent, ToolCallPart, ToolOutcome, ToolResult, ToolStarted, TurnCompleted, TurnFailed, TurnStarted, UserInput, UserMessage, assistantTexts, attachmentLine, formatSize, isAppInput, isInput, isLibraryEvent, isTurnEnd, isUserInput, isWaking, maxAttachments, textWithAttachments };
|
|
557
|
+
export { AppTag, ApprovalDecision, ApprovalRequested, ApprovalsExpired, AssistantEvent, AssistantEvent_exports, AssistantMessage, Attachment, BlockAnswer, BlocksClosed, ChatDeleted, Entry, Input, MessageBlock, ModelOutput, ModelPart, SpecialistFinished, SpecialistStarted, StoredAppEvent, ToolCallPart, ToolOutcome, ToolResult, ToolStarted, TurnCompleted, TurnFailed, TurnStarted, UserInput, UserMessage, assistantTexts, attachmentLine, formatSize, isAppInput, isInput, isLibraryEvent, isTurnEnd, isUserInput, isWaking, maxAttachments, textWithAttachments };
|
|
493
558
|
|
|
494
559
|
//# sourceMappingURL=AssistantEvent.js.map
|