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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Skill.js","names":[],"sources":["../src/Skill.ts"],"sourcesContent":["/**\n * Defines skills, which are playbooks with step-by-step instructions for a kind of task.\n *\n * A loop lists its skills as a catalog in the prompt, with each skill's name and description\n * ({@link withCatalog}). The model loads a skill's instructions with the `load_skill` tool when a\n * task matches.\n *\n * @since 0.1.0\n */\nimport type * as Instructions from \"./Instructions.ts\"\n\n/**\n * Represents a skill.\n *\n * `R` is the services its instructions need when they're loaded.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Skill<R = never> {\n readonly name: string\n /** When to use it, in one line. This is all the model sees until it loads the skill. */\n readonly description: string\n /** Text, or an Effect resolved each time the skill is loaded. */\n readonly instructions: Instructions.Instructions<R>\n}\n\n/**\n * Creates a skill from its name, a description of when to use it, and its instructions.\n *\n * **Details**\n *\n * Write the description as a trigger (\"Use when…\"), since it's all the model sees until it loads\n * the skill. The instructions are text, or an Effect that is resolved each time the skill is\n * loaded.\n *\n * **Example** (Defining a playbook for ordering campaigns)\n *\n * ```ts\n * import { Skill } from \"effect-assistant\"\n *\n * const orderingCampaigns = Skill.make(\"Ordering a campaign\", {\n * description: \"Use when the user wants to order or start a campaign.\",\n * instructions: `1. Pick the product with list_campaign_products.\n * 2. You need who it should reach and a budget. Ask for what's missing, one question at a time.\n * 3. When you have both, call start_campaign.`\n * })\n *\n * const MyAssistantLive = MyAssistant.toLayer((turn) =>\n * turn.loop({ instructions, skills: [orderingCampaigns] })\n * )\n * ```\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <R = never>(\n name: string,\n options: {\n /** When to use it, in one line. This is all the model sees until it loads the skill. */\n readonly description: string\n /** Text, or an Effect resolved each time the skill is loaded. */\n readonly instructions: Instructions.Instructions<R>\n }\n): Skill<R> => ({ name, description: options.description, instructions: options.instructions })\n\n/**\n * Extracts the services that skills need when they're loaded.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type Services<S> = S extends Skill<infer R> ? R : never\n\n/**\n * Returns the prompt with the skills' catalog appended, or the prompt unchanged when there are no\n * skills.\n *\n * @category utils\n * @since 0.1.0\n */\nexport const withCatalog = <R>(prompt: string, skills: ReadonlyArray<Skill<R>>): string =>\n skills.length === 0\n ? prompt\n : [\n prompt,\n \"\",\n \"## Skills\",\n \"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.\",\n ...skills.map((skill) => `- ${skill.name}: ${skill.description}`)\n ].join(\"\\n\")\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwDA,MAAa,QACX,MACA,aAMc;CAAE;CAAM,aAAa,QAAQ;CAAa,cAAc,QAAQ;AAAa;;;;;;;;AAiB7F,MAAa,eAAkB,QAAgB,WAC7C,OAAO,WAAW,IACd,SACA;CACE;CACA;CACA;CACA;CACA,GAAG,OAAO,KAAK,UAAU,KAAK,MAAM,KAAK,IAAI,MAAM,aAAa;AAClE,CAAC,CAAC,KAAK,IAAI"}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { ChatId } from "./ChatId.js";
|
|
2
|
+
import { Instructions_d_exports, Resolved } from "./Instructions.js";
|
|
3
|
+
import { AssistantLoop_d_exports, Event, ToolkitServices } from "./AssistantLoop.js";
|
|
4
|
+
import { CurrentChat } from "./CurrentChat.js";
|
|
5
|
+
import { RunId } from "./RunId.js";
|
|
6
|
+
import { Skill } from "./Skill.js";
|
|
7
|
+
import * as Context from "effect/Context";
|
|
8
|
+
import * as Effect from "effect/Effect";
|
|
9
|
+
import * as Layer from "effect/Layer";
|
|
10
|
+
import * as Schema from "effect/Schema";
|
|
11
|
+
import * as Stream from "effect/Stream";
|
|
12
|
+
import * as Scope from "effect/Scope";
|
|
13
|
+
import * as Prompt from "effect/ai/Prompt";
|
|
14
|
+
import * as Tool from "effect/ai/Tool";
|
|
15
|
+
import * as Toolkit from "effect/ai/Toolkit";
|
|
16
|
+
import * as LanguageModel from "effect/ai/LanguageModel";
|
|
17
|
+
import * as AiError from "effect/ai/AiError";
|
|
18
|
+
declare namespace Specialist_d_exports {
|
|
19
|
+
export { Any, Brief, Built, CheckServices, Handler, HandlerOf, LoopOptions, Run, RunServices, Runner, SpawnRequest, Specialist, SpecialistError, SpecialistHandler, ToolHandlers, make };
|
|
20
|
+
}
|
|
21
|
+
declare const TypeId = "~effect-assistant/Specialist";
|
|
22
|
+
/**
|
|
23
|
+
* Represents a specialist's definition.
|
|
24
|
+
*
|
|
25
|
+
* @category models
|
|
26
|
+
* @since 0.1.0
|
|
27
|
+
*/
|
|
28
|
+
export interface Specialist<Name extends string = string> {
|
|
29
|
+
readonly [TypeId]: typeof TypeId;
|
|
30
|
+
readonly name: Name;
|
|
31
|
+
/** When to use the specialist. The assistant sees this. */
|
|
32
|
+
readonly description: string;
|
|
33
|
+
/** The key of the specialist's handler, as `toLayer` provides it. */
|
|
34
|
+
readonly Handler: Context.Key<SpecialistHandler<Name>, Built>;
|
|
35
|
+
/**
|
|
36
|
+
* Provides the specialist's handler. The handler may use the {@link RunServices} and the
|
|
37
|
+
* services its build Effect required (see {@link CheckServices}).
|
|
38
|
+
*/
|
|
39
|
+
readonly toLayer: <R = never, RE = never, E = never, RX = never>(build: (Handler<R, RE> | Effect.Effect<Handler<R, RE>, E, RX>) & CheckServices<Exclude<R | RE, RunServices | RX | Tool.Handler<string>>>) => Layer.Layer<SpecialistHandler<Name>, never, Exclude<RX, Scope.Scope | CurrentChat> | ToolHandlers<R | RE>>;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Represents the check `toLayer` applies to the services a handler uses.
|
|
43
|
+
*
|
|
44
|
+
* **Details**
|
|
45
|
+
*
|
|
46
|
+
* Every service a handler uses must be one the run (or turn) provides, or one its build Effect
|
|
47
|
+
* required, which the layer provides. A handler that uses any other service gets this type
|
|
48
|
+
* error, which names those services.
|
|
49
|
+
*
|
|
50
|
+
* @category utility types
|
|
51
|
+
* @since 0.1.0
|
|
52
|
+
*/
|
|
53
|
+
export type CheckServices<Undeclared> = [Undeclared] extends [never] ? unknown : {
|
|
54
|
+
readonly "~undeclaredServices": {
|
|
55
|
+
readonly error: "The handler uses services that neither the turn provides nor its build Effect requires";
|
|
56
|
+
readonly services: Undeclared;
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Extracts the tool handlers (`Toolkit.toLayer`) that a handler's loop uses.
|
|
61
|
+
*
|
|
62
|
+
* They are requirements of the layer, so `Layer.provide(MyToolsLive)` provides them, and a
|
|
63
|
+
* missing one is a type error.
|
|
64
|
+
*
|
|
65
|
+
* @category utility types
|
|
66
|
+
* @since 0.1.0
|
|
67
|
+
*/
|
|
68
|
+
export type ToolHandlers<R> = Extract<R, Tool.Handler<string>>;
|
|
69
|
+
/**
|
|
70
|
+
* Represents any specialist.
|
|
71
|
+
*
|
|
72
|
+
* @category utility types
|
|
73
|
+
* @since 0.1.0
|
|
74
|
+
*/
|
|
75
|
+
export type Any = Specialist<any>;
|
|
76
|
+
/**
|
|
77
|
+
* Identifies a specialist's handler in a context.
|
|
78
|
+
*
|
|
79
|
+
* @category models
|
|
80
|
+
* @since 0.1.0
|
|
81
|
+
*/
|
|
82
|
+
export interface SpecialistHandler<Name extends string> {
|
|
83
|
+
readonly _SpecialistHandler: Name;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Extracts the handlers that these specialists need.
|
|
87
|
+
*
|
|
88
|
+
* @category utility types
|
|
89
|
+
* @since 0.1.0
|
|
90
|
+
*/
|
|
91
|
+
export type HandlerOf<S> = S extends Specialist<infer Name> ? SpecialistHandler<Name> : never;
|
|
92
|
+
/**
|
|
93
|
+
* The services a run provides to its handler, which are its chat, the chat's runner, and the
|
|
94
|
+
* model.
|
|
95
|
+
*
|
|
96
|
+
* @category utility types
|
|
97
|
+
* @since 0.1.0
|
|
98
|
+
*/
|
|
99
|
+
export type RunServices = CurrentChat | Runner | LanguageModel.LanguageModel;
|
|
100
|
+
/**
|
|
101
|
+
* Represents the options for `run.loop`.
|
|
102
|
+
*
|
|
103
|
+
* @category models
|
|
104
|
+
* @since 0.1.0
|
|
105
|
+
*/
|
|
106
|
+
export interface LoopOptions<T extends Record<string, Tool.Any> = Record<never, never>, RS = never> {
|
|
107
|
+
readonly instructions: string | Resolved;
|
|
108
|
+
/** The loop's tools, as a native toolkit whose handlers come from the layer. */
|
|
109
|
+
readonly toolkit?: Toolkit.Toolkit<T> | undefined;
|
|
110
|
+
/** Playbooks, listed as a catalog in the prompt and loaded with `load_skill` when one matches. */
|
|
111
|
+
readonly skills?: ReadonlyArray<Skill<RS>> | undefined;
|
|
112
|
+
/** The model calls allowed per brief. Defaults to 8. */
|
|
113
|
+
readonly maxSteps?: number | undefined;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Represents one run of a specialist on a brief, as its handler sees it.
|
|
117
|
+
*
|
|
118
|
+
* @category models
|
|
119
|
+
* @since 0.1.0
|
|
120
|
+
*/
|
|
121
|
+
export interface Run {
|
|
122
|
+
readonly runId: RunId;
|
|
123
|
+
/** The chat the run belongs to, which is the chat of the turn that spawned it. */
|
|
124
|
+
readonly chatId: ChatId;
|
|
125
|
+
readonly brief: Brief;
|
|
126
|
+
/**
|
|
127
|
+
* The run's history, with the brief, what the run did so far, and the messages sent to it since
|
|
128
|
+
* (follow-ups and steering). Read it before every model call, as the loop does.
|
|
129
|
+
*/
|
|
130
|
+
readonly history: Effect.Effect<ReadonlyArray<Prompt.Message>>;
|
|
131
|
+
/** Runs the agent loop over the run's history, with the given instructions, tools, and skills. */
|
|
132
|
+
readonly loop: <T extends Record<string, Tool.Any> = Record<never, never>, RS = never>(options: LoopOptions<T, RS>) => Stream.Stream<Event, AiError.AiError, LanguageModel.LanguageModel | ToolkitServices<T> | RS>;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Represents a specialist's handler, which works on a brief and returns a stream of what the loop
|
|
136
|
+
* did.
|
|
137
|
+
*
|
|
138
|
+
* It may return the stream from an Effect. `R` is the services the stream needs, and `RE` the
|
|
139
|
+
* services the Effect needs.
|
|
140
|
+
*
|
|
141
|
+
* @category models
|
|
142
|
+
* @since 0.1.0
|
|
143
|
+
*/
|
|
144
|
+
export type Handler<R = never, RE = R> = (run: Run) => Stream.Stream<Event, unknown, R> | Effect.Effect<Stream.Stream<Event, unknown, R>, unknown, RE>;
|
|
145
|
+
/**
|
|
146
|
+
* Represents a specialist's handler as its layer provides it.
|
|
147
|
+
*
|
|
148
|
+
* `open` runs the build for a chat (once per chat activation, see `CurrentChat`) and returns
|
|
149
|
+
* the handler with the layer's services already provided.
|
|
150
|
+
*
|
|
151
|
+
* @category models
|
|
152
|
+
* @since 0.1.0
|
|
153
|
+
*/
|
|
154
|
+
export interface Built {
|
|
155
|
+
readonly open: Effect.Effect<(run: Run) => Stream.Stream<Event, unknown, RunServices>, never, Scope.Scope | CurrentChat>;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Creates a specialist from its name and a description of when to use it.
|
|
159
|
+
*
|
|
160
|
+
* **Details**
|
|
161
|
+
*
|
|
162
|
+
* The specialist's `toLayer` provides its handler, which is usually `run.loop` with the
|
|
163
|
+
* specialist's own instructions and tools. List the specialist in `Assistant.make`'s
|
|
164
|
+
* `specialists`, and provide its layer to the assistant's.
|
|
165
|
+
*
|
|
166
|
+
* **Example** (Defining a research specialist)
|
|
167
|
+
*
|
|
168
|
+
* ```ts
|
|
169
|
+
* import { Assistant, Specialist } from "effect-assistant"
|
|
170
|
+
* import * as Layer from "effect/Layer"
|
|
171
|
+
*
|
|
172
|
+
* const Research = Specialist.make("research", {
|
|
173
|
+
* description: "Researches past campaigns and orders. Give it the question and any context."
|
|
174
|
+
* })
|
|
175
|
+
*
|
|
176
|
+
* const ResearchLive = Research.toLayer((run) =>
|
|
177
|
+
* run.loop({
|
|
178
|
+
* instructions: "Answer with the findings and numbers the colleague needs, in a few lines.",
|
|
179
|
+
* toolkit: ResearchTools
|
|
180
|
+
* })
|
|
181
|
+
* ).pipe(Layer.provide(ResearchToolsLive))
|
|
182
|
+
*
|
|
183
|
+
* export const MyAssistant = Assistant.make("my-assistant", { specialists: [Research] })
|
|
184
|
+
*
|
|
185
|
+
* const MyAssistantLive = MyAssistant.toLayer((turn) => turn.loop({ instructions })).pipe(
|
|
186
|
+
* Layer.provide(ResearchLive)
|
|
187
|
+
* )
|
|
188
|
+
* ```
|
|
189
|
+
*
|
|
190
|
+
* @category constructors
|
|
191
|
+
* @since 0.1.0
|
|
192
|
+
*/
|
|
193
|
+
export declare const make: <const Name extends string>(name: Name, options: {
|
|
194
|
+
/** When to use it. The assistant sees this. */
|
|
195
|
+
readonly description: string;
|
|
196
|
+
}) => Specialist<Name>;
|
|
197
|
+
/**
|
|
198
|
+
* Schema for the brief the assistant gives a specialist.
|
|
199
|
+
*
|
|
200
|
+
* Only `goal` is required.
|
|
201
|
+
*
|
|
202
|
+
* @category schemas
|
|
203
|
+
* @since 0.1.0
|
|
204
|
+
*/
|
|
205
|
+
export declare const Brief: Schema.Struct<{
|
|
206
|
+
readonly goal: Schema.String;
|
|
207
|
+
readonly context: Schema.optional<Schema.String>;
|
|
208
|
+
readonly successCriteria: Schema.optional<Schema.String>;
|
|
209
|
+
readonly report: Schema.optional<Schema.String>;
|
|
210
|
+
readonly limits: Schema.optional<Schema.String>;
|
|
211
|
+
}>;
|
|
212
|
+
/**
|
|
213
|
+
* Represents the brief the assistant gives a specialist.
|
|
214
|
+
*
|
|
215
|
+
* @category models
|
|
216
|
+
* @since 0.1.0
|
|
217
|
+
*/
|
|
218
|
+
export type Brief = typeof Brief.Type;
|
|
219
|
+
/**
|
|
220
|
+
* Represents a request to start a specialist run in the runner's chat.
|
|
221
|
+
*
|
|
222
|
+
* @category models
|
|
223
|
+
* @since 0.1.0
|
|
224
|
+
*/
|
|
225
|
+
export interface SpawnRequest {
|
|
226
|
+
/** The specialist's name. */
|
|
227
|
+
readonly specialist: string;
|
|
228
|
+
readonly brief: Brief;
|
|
229
|
+
}
|
|
230
|
+
declare const SpecialistError_base: Schema.Class<SpecialistError, Schema.Struct<{
|
|
231
|
+
readonly _tag: Schema.tag<"SpecialistError">;
|
|
232
|
+
readonly reason: Schema.Literals<readonly ["UnknownSpecialist", "RunNotFound", "NotRunning"]>;
|
|
233
|
+
readonly message: Schema.String;
|
|
234
|
+
}>, import("effect/Cause").YieldableError>;
|
|
235
|
+
/**
|
|
236
|
+
* Represents why a run request can't be carried out.
|
|
237
|
+
*
|
|
238
|
+
* **Details**
|
|
239
|
+
*
|
|
240
|
+
* The `reason` says which request failed: `"UnknownSpecialist"` when `spawn` names no specialist
|
|
241
|
+
* of the assistant, `"RunNotFound"` when `message` names a run that is gone, and `"NotRunning"`
|
|
242
|
+
* when `stop` names a run that isn't running. The `message` is written for the model.
|
|
243
|
+
*
|
|
244
|
+
* @category errors
|
|
245
|
+
* @since 0.1.0
|
|
246
|
+
*/
|
|
247
|
+
export declare class SpecialistError extends SpecialistError_base {}
|
|
248
|
+
declare const Runner_base: Context.ServiceClass<Runner, "effect-assistant/Specialist/Runner", {
|
|
249
|
+
/** Starts a run and returns its id. */
|
|
250
|
+
readonly spawn: (request: SpawnRequest) => Effect.Effect<RunId, SpecialistError>;
|
|
251
|
+
/** Steers a running run, or continues a finished one. */
|
|
252
|
+
readonly message: (runId: RunId, text: string) => Effect.Effect<"steered" | "continued", SpecialistError>;
|
|
253
|
+
/** Interrupts a running run. */
|
|
254
|
+
readonly stop: (runId: RunId) => Effect.Effect<void, SpecialistError>;
|
|
255
|
+
}>;
|
|
256
|
+
/**
|
|
257
|
+
* Service that runs a chat's specialists and keeps finished runs warm for follow-ups.
|
|
258
|
+
*
|
|
259
|
+
* The engine provides it to every turn. The specialist tools use it, and a handler can too.
|
|
260
|
+
*
|
|
261
|
+
* @category services
|
|
262
|
+
* @since 0.1.0
|
|
263
|
+
*/
|
|
264
|
+
export declare class Runner extends Runner_base {}
|
|
265
|
+
//#endregion
|
|
266
|
+
export { Specialist_d_exports };
|
|
267
|
+
//# sourceMappingURL=Specialist.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Specialist.d.ts","names":[],"sources":["../src/Specialist.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;cA2BM;;;;;;;iBAQW,WAAW;YAChB,gBAAgB;WACjB,MAAM;;WAEN;;WAEA,SAAS,QAAQ,IAAI,kBAAkB,OAAO;;;;;WAK9C,UAAU,WAAW,YAAY,WAAW,YACnD,QAAQ,QAAQ,GAAG,MAAM,OAAO,OAAO,QAAQ,GAAG,KAAK,GAAG,OACxD,cAAc,QAAQ,IAAI,IAAI,cAAc,KAAK,KAAK,sBACrD,MAAM,MAAM,kBAAkB,cAAc,QAAQ,IAAI,MAAM,QAAQ,eAAe,aAAa,IAAI;;;;;;;;;;;;;;YAejG,cAAc,eAAe;WAG1B;aACE;aACA,UAAU;;;;;;;;;;;;YAaf,aAAa,KAAK,QAAQ,GAAG,KAAK;;;;;;;YAQlC,MAAM;;;;;;;iBAQD,kBAAkB;WACxB,oBAAoB;;;;;;;;YASnB,UAAU,KAAK,UAAU,iBAAiB,QAAQ,kBAAkB;;;;;;;;YASpE,cAAc,cAAc,SAAS,cAAc;;;;;;;iBAQ9C,YAAY,UAAU,eAAe,KAAK,OAAO,sBAAsB;WAC7E,uBAAuB;;WAEvB,UAAU,QAAQ,QAAQ;;WAE1B,SAAS,cAAc,MAAM;;WAE7B;;;;;;;;iBASM;WACN,OAAO;;WAEP,QAAQ;WACR,OAAO;;;;;WAKP,SAAS,OAAO,OAAO,cAAc,OAAO;;WAE5C,OAAO,UAAU,eAAe,KAAK,OAAO,sBAAsB,YACzE,SAAS,YAAY,GAAG,QACrB,OAAO,OACV,OACA,QAAQ,SACR,cAAc,gBAAgB,gBAA8B,KAAK;;;;;;;;;;;;YAczD,QAAQ,WAAW,KAAK,MAClC,KAAK,QAEH,OAAO,OAAO,gBAA8B,KAC5C,OAAO,OAAO,OAAO,OAAO,gBAA8B,aAAa;;;;;;;;;;iBAW1D;WACN,MAAM,OAAO,QACnB,KAAK,QAAQ,OAAO,OAAO,gBAA8B,qBAE1D,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA8CL,aAAc,qBAAmB,MACtC,MAAI;;WAGC;MAEV,WAAW;;;;;;;;;qBA0CD,OAAK,OAAA;;;;;;;;;;;;;YAoBN,eAAe,MAAM;;;;;;;iBAQhB;;WAEN;WACA,OAAO;;;;;;;;;;;;;;;;;;;qBAeL,wBAAwB;;;WAkBjB,QAAC,SAAS,iBAAiB,OAAO,OAAO,OAAO;;WAE9C,UAAC,OAAO,OAAO,iBAAiB,OAAO,gCAAgC;;WAE1E,OAAC,OAAO,UAAU,OAAO,aAAa;;;;;;;;;;qBAR5C,eAAe"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { __exportAll } from "./_virtual/_rolldown/runtime.js";
|
|
2
|
+
import * as Context from "effect/Context";
|
|
3
|
+
import * as Effect from "effect/Effect";
|
|
4
|
+
import * as Layer from "effect/Layer";
|
|
5
|
+
import * as Schema from "effect/Schema";
|
|
6
|
+
import * as Stream from "effect/Stream";
|
|
7
|
+
//#region src/Specialist.ts
|
|
8
|
+
var Specialist_exports = /* @__PURE__ */ __exportAll({
|
|
9
|
+
Brief: () => Brief,
|
|
10
|
+
Runner: () => Runner,
|
|
11
|
+
SpecialistError: () => SpecialistError,
|
|
12
|
+
make: () => make
|
|
13
|
+
});
|
|
14
|
+
const TypeId = "~effect-assistant/Specialist";
|
|
15
|
+
const toStream = (result) => Effect.isEffect(result) ? Stream.unwrap(result) : result;
|
|
16
|
+
/**
|
|
17
|
+
* Creates a specialist from its name and a description of when to use it.
|
|
18
|
+
*
|
|
19
|
+
* **Details**
|
|
20
|
+
*
|
|
21
|
+
* The specialist's `toLayer` provides its handler, which is usually `run.loop` with the
|
|
22
|
+
* specialist's own instructions and tools. List the specialist in `Assistant.make`'s
|
|
23
|
+
* `specialists`, and provide its layer to the assistant's.
|
|
24
|
+
*
|
|
25
|
+
* **Example** (Defining a research specialist)
|
|
26
|
+
*
|
|
27
|
+
* ```ts
|
|
28
|
+
* import { Assistant, Specialist } from "effect-assistant"
|
|
29
|
+
* import * as Layer from "effect/Layer"
|
|
30
|
+
*
|
|
31
|
+
* const Research = Specialist.make("research", {
|
|
32
|
+
* description: "Researches past campaigns and orders. Give it the question and any context."
|
|
33
|
+
* })
|
|
34
|
+
*
|
|
35
|
+
* const ResearchLive = Research.toLayer((run) =>
|
|
36
|
+
* run.loop({
|
|
37
|
+
* instructions: "Answer with the findings and numbers the colleague needs, in a few lines.",
|
|
38
|
+
* toolkit: ResearchTools
|
|
39
|
+
* })
|
|
40
|
+
* ).pipe(Layer.provide(ResearchToolsLive))
|
|
41
|
+
*
|
|
42
|
+
* export const MyAssistant = Assistant.make("my-assistant", { specialists: [Research] })
|
|
43
|
+
*
|
|
44
|
+
* const MyAssistantLive = MyAssistant.toLayer((turn) => turn.loop({ instructions })).pipe(
|
|
45
|
+
* Layer.provide(ResearchLive)
|
|
46
|
+
* )
|
|
47
|
+
* ```
|
|
48
|
+
*
|
|
49
|
+
* @category constructors
|
|
50
|
+
* @since 0.1.0
|
|
51
|
+
*/
|
|
52
|
+
const make = (name, options) => {
|
|
53
|
+
const Handler = Context.Service(`effect-assistant/Specialist/${name}`);
|
|
54
|
+
function toLayer(build) {
|
|
55
|
+
return Layer.effect(Handler, Effect.gen(function* () {
|
|
56
|
+
const context = yield* Effect.context();
|
|
57
|
+
return { open: Effect.gen(function* () {
|
|
58
|
+
const handler = Effect.isEffect(build) ? yield* build : build;
|
|
59
|
+
return (run) => Stream.provideContext(toStream(handler(run)), context);
|
|
60
|
+
}).pipe(Effect.provideContext(context), Effect.orDie) };
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
return {
|
|
64
|
+
[TypeId]: TypeId,
|
|
65
|
+
name,
|
|
66
|
+
description: options.description,
|
|
67
|
+
Handler,
|
|
68
|
+
toLayer
|
|
69
|
+
};
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Schema for the brief the assistant gives a specialist.
|
|
73
|
+
*
|
|
74
|
+
* Only `goal` is required.
|
|
75
|
+
*
|
|
76
|
+
* @category schemas
|
|
77
|
+
* @since 0.1.0
|
|
78
|
+
*/
|
|
79
|
+
const Brief = Schema.Struct({
|
|
80
|
+
goal: Schema.String.annotate({ description: "What to find out or do." }),
|
|
81
|
+
context: Schema.optional(Schema.String).annotate({ description: "What it needs to know. It can't see this chat." }),
|
|
82
|
+
successCriteria: Schema.optional(Schema.String).annotate({ description: "When it is done." }),
|
|
83
|
+
report: Schema.optional(Schema.String).annotate({ description: "What to put in the answer, and how." }),
|
|
84
|
+
limits: Schema.optional(Schema.String).annotate({ description: "Hard limits for this job, like read-only or a deadline." })
|
|
85
|
+
});
|
|
86
|
+
/**
|
|
87
|
+
* Represents why a run request can't be carried out.
|
|
88
|
+
*
|
|
89
|
+
* **Details**
|
|
90
|
+
*
|
|
91
|
+
* The `reason` says which request failed: `"UnknownSpecialist"` when `spawn` names no specialist
|
|
92
|
+
* of the assistant, `"RunNotFound"` when `message` names a run that is gone, and `"NotRunning"`
|
|
93
|
+
* when `stop` names a run that isn't running. The `message` is written for the model.
|
|
94
|
+
*
|
|
95
|
+
* @category errors
|
|
96
|
+
* @since 0.1.0
|
|
97
|
+
*/
|
|
98
|
+
var SpecialistError = class extends Schema.Error("effect-assistant/Specialist/SpecialistError")({
|
|
99
|
+
_tag: Schema.tag("SpecialistError"),
|
|
100
|
+
reason: Schema.Literals([
|
|
101
|
+
"UnknownSpecialist",
|
|
102
|
+
"RunNotFound",
|
|
103
|
+
"NotRunning"
|
|
104
|
+
]),
|
|
105
|
+
message: Schema.String
|
|
106
|
+
}) {};
|
|
107
|
+
/**
|
|
108
|
+
* Service that runs a chat's specialists and keeps finished runs warm for follow-ups.
|
|
109
|
+
*
|
|
110
|
+
* The engine provides it to every turn. The specialist tools use it, and a handler can too.
|
|
111
|
+
*
|
|
112
|
+
* @category services
|
|
113
|
+
* @since 0.1.0
|
|
114
|
+
*/
|
|
115
|
+
var Runner = class extends Context.Service()("effect-assistant/Specialist/Runner") {};
|
|
116
|
+
//#endregion
|
|
117
|
+
export { Brief, Runner, SpecialistError, Specialist_exports, make };
|
|
118
|
+
|
|
119
|
+
//# sourceMappingURL=Specialist.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Specialist.js","names":[],"sources":["../src/Specialist.ts"],"sourcesContent":["/**\n * Defines specialists, which are focused agents an assistant hands work to in the background.\n *\n * A specialist has a definition, created with {@link make}, that gives its name and when to use\n * it, and a handler, provided with its `toLayer`, that works on a {@link Brief} as a loop. The\n * {@link Runner} service starts, steers, and stops a chat's specialist runs.\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 Layer from \"effect/Layer\"\nimport * as Schema from \"effect/Schema\"\nimport type * as Scope from \"effect/Scope\"\nimport * as Stream from \"effect/Stream\"\nimport type * as AssistantLoop from \"./AssistantLoop.ts\"\nimport type { ChatId } from \"./ChatId.ts\"\nimport type { CurrentChat } from \"./CurrentChat.ts\"\nimport type * as Instructions from \"./Instructions.ts\"\nimport type { RunId } from \"./RunId.ts\"\nimport type { Skill } from \"./Skill.ts\"\n\nconst TypeId = \"~effect-assistant/Specialist\"\n\n/**\n * Represents a specialist's definition.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Specialist<Name extends string = string> {\n readonly [TypeId]: typeof TypeId\n readonly name: Name\n /** When to use the specialist. The assistant sees this. */\n readonly description: string\n /** The key of the specialist's handler, as `toLayer` provides it. */\n readonly Handler: Context.Key<SpecialistHandler<Name>, Built>\n /**\n * Provides the specialist's handler. The handler may use the {@link RunServices} and the\n * services its build Effect required (see {@link CheckServices}).\n */\n readonly toLayer: <R = never, RE = never, E = never, RX = never>(\n build: (Handler<R, RE> | Effect.Effect<Handler<R, RE>, E, RX>) &\n CheckServices<Exclude<R | RE, RunServices | RX | Tool.Handler<string>>>\n ) => Layer.Layer<SpecialistHandler<Name>, never, Exclude<RX, Scope.Scope | CurrentChat> | ToolHandlers<R | RE>>\n}\n\n/**\n * Represents the check `toLayer` applies to the services a handler uses.\n *\n * **Details**\n *\n * Every service a handler uses must be one the run (or turn) provides, or one its build Effect\n * required, which the layer provides. A handler that uses any other service gets this type\n * error, which names those services.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type CheckServices<Undeclared> = [Undeclared] extends [never]\n ? unknown\n : {\n readonly \"~undeclaredServices\": {\n readonly error: \"The handler uses services that neither the turn provides nor its build Effect requires\"\n readonly services: Undeclared\n }\n }\n\n/**\n * Extracts the tool handlers (`Toolkit.toLayer`) that a handler's loop uses.\n *\n * They are requirements of the layer, so `Layer.provide(MyToolsLive)` provides them, and a\n * missing one is a type error.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type ToolHandlers<R> = Extract<R, Tool.Handler<string>>\n\n/**\n * Represents any specialist.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type Any = Specialist<any>\n\n/**\n * Identifies a specialist's handler in a context.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface SpecialistHandler<Name extends string> {\n readonly _SpecialistHandler: Name\n}\n\n/**\n * Extracts the handlers that these specialists need.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type HandlerOf<S> = S extends Specialist<infer Name> ? SpecialistHandler<Name> : never\n\n/**\n * The services a run provides to its handler, which are its chat, the chat's runner, and the\n * model.\n *\n * @category utility types\n * @since 0.1.0\n */\nexport type RunServices = CurrentChat | Runner | LanguageModel.LanguageModel\n\n/**\n * Represents the options for `run.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> {\n readonly instructions: string | Instructions.Resolved\n /** The loop's tools, as a native toolkit whose handlers come from the layer. */\n readonly toolkit?: Toolkit.Toolkit<T> | undefined\n /** Playbooks, listed as a catalog in the prompt and loaded with `load_skill` when one matches. */\n readonly skills?: ReadonlyArray<Skill<RS>> | undefined\n /** The model calls allowed per brief. Defaults to 8. */\n readonly maxSteps?: number | undefined\n}\n\n/**\n * Represents one run of a specialist on a brief, as its handler sees it.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Run {\n readonly runId: RunId\n /** The chat the run belongs to, which is the chat of the turn that spawned it. */\n readonly chatId: ChatId\n readonly brief: Brief\n /**\n * The run's history, with the brief, what the run did so far, and the messages sent to it since\n * (follow-ups and steering). Read it before every model call, as the loop does.\n */\n readonly history: Effect.Effect<ReadonlyArray<Prompt.Message>>\n /** Runs the agent loop over the run's history, with the given instructions, tools, and skills. */\n readonly loop: <T extends Record<string, Tool.Any> = Record<never, never>, RS = never>(\n options: LoopOptions<T, RS>\n ) => Stream.Stream<\n AssistantLoop.Event,\n AiError.AiError,\n LanguageModel.LanguageModel | AssistantLoop.ToolkitServices<T> | RS\n >\n}\n\n/**\n * Represents a specialist's handler, which works on a brief and returns a stream of what the loop\n * did.\n *\n * It may return the stream from an Effect. `R` is the services the stream needs, and `RE` the\n * services the Effect needs.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Handler<R = never, RE = R> = (\n run: Run\n) =>\n | Stream.Stream<AssistantLoop.Event, unknown, R>\n | Effect.Effect<Stream.Stream<AssistantLoop.Event, unknown, R>, unknown, RE>\n\n/**\n * Represents a specialist's handler as its layer provides it.\n *\n * `open` runs the build for a chat (once per chat activation, see `CurrentChat`) and returns\n * the handler with the layer's services already provided.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface Built {\n readonly open: Effect.Effect<\n (run: Run) => Stream.Stream<AssistantLoop.Event, unknown, RunServices>,\n never,\n Scope.Scope | CurrentChat\n >\n}\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 * Creates a specialist from its name and a description of when to use it.\n *\n * **Details**\n *\n * The specialist's `toLayer` provides its handler, which is usually `run.loop` with the\n * specialist's own instructions and tools. List the specialist in `Assistant.make`'s\n * `specialists`, and provide its layer to the assistant's.\n *\n * **Example** (Defining a research specialist)\n *\n * ```ts\n * import { Assistant, Specialist } from \"effect-assistant\"\n * import * as Layer from \"effect/Layer\"\n *\n * const Research = Specialist.make(\"research\", {\n * description: \"Researches past campaigns and orders. Give it the question and any context.\"\n * })\n *\n * const ResearchLive = Research.toLayer((run) =>\n * run.loop({\n * instructions: \"Answer with the findings and numbers the colleague needs, in a few lines.\",\n * toolkit: ResearchTools\n * })\n * ).pipe(Layer.provide(ResearchToolsLive))\n *\n * export const MyAssistant = Assistant.make(\"my-assistant\", { specialists: [Research] })\n *\n * const MyAssistantLive = MyAssistant.toLayer((turn) => turn.loop({ instructions })).pipe(\n * Layer.provide(ResearchLive)\n * )\n * ```\n *\n * @category constructors\n * @since 0.1.0\n */\nexport const make = <const Name extends string>(\n name: Name,\n options: {\n /** When to use it. The assistant sees this. */\n readonly description: string\n }\n): Specialist<Name> => {\n const Handler = Context.Service<SpecialistHandler<Name>, Built>(`effect-assistant/Specialist/${name}`)\n\n // The signature checks what the handler uses (`CheckServices`); the layer's services, which the\n // build required, are provided to it and to every run's stream, so what's left is the run\n // services.\n function toLayer<R = never, RE = never, E = never, RX = never>(\n build: (Handler<R, RE> | Effect.Effect<Handler<R, RE>, E, RX>) &\n CheckServices<Exclude<R | RE, RunServices | RX | Tool.Handler<string>>>\n ): Layer.Layer<SpecialistHandler<Name>, never, Exclude<RX, Scope.Scope | CurrentChat> | ToolHandlers<R | RE>>\n function toLayer(\n build: Handler<any, any> | Effect.Effect<Handler<any, any>, unknown, any>\n ): Layer.Layer<SpecialistHandler<Name>, never, any> {\n return Layer.effect(\n Handler,\n Effect.gen(function* () {\n const context = yield* Effect.context()\n\n return {\n // The build runs per chat activation, in the chat; here it only keeps the layer's\n // services for it.\n open: Effect.gen(function* () {\n const handler = Effect.isEffect(build) ? yield* build : build\n\n return (run: Run) => Stream.provideContext(toStream(handler(run)), context)\n }).pipe(Effect.provideContext(context), Effect.orDie)\n }\n })\n )\n }\n\n return { [TypeId]: TypeId, name, description: options.description, Handler, toLayer }\n}\n\n/**\n * Schema for the brief the assistant gives a specialist.\n *\n * Only `goal` is required.\n *\n * @category schemas\n * @since 0.1.0\n */\nexport const Brief = Schema.Struct({\n goal: Schema.String.annotate({ description: \"What to find out or do.\" }),\n context: Schema.optional(Schema.String).annotate({\n description: \"What it needs to know. It can't see this chat.\"\n }),\n successCriteria: Schema.optional(Schema.String).annotate({ description: \"When it is done.\" }),\n report: Schema.optional(Schema.String).annotate({\n description: \"What to put in the answer, and how.\"\n }),\n limits: Schema.optional(Schema.String).annotate({\n description: \"Hard limits for this job, like read-only or a deadline.\"\n })\n})\n\n/**\n * Represents the brief the assistant gives a specialist.\n *\n * @category models\n * @since 0.1.0\n */\nexport type Brief = typeof Brief.Type\n\n/**\n * Represents a request to start a specialist run in the runner's chat.\n *\n * @category models\n * @since 0.1.0\n */\nexport interface SpawnRequest {\n /** The specialist's name. */\n readonly specialist: string\n readonly brief: Brief\n}\n\n/**\n * Represents why a run request can't be carried out.\n *\n * **Details**\n *\n * The `reason` says which request failed: `\"UnknownSpecialist\"` when `spawn` names no specialist\n * of the assistant, `\"RunNotFound\"` when `message` names a run that is gone, and `\"NotRunning\"`\n * when `stop` names a run that isn't running. The `message` is written for the model.\n *\n * @category errors\n * @since 0.1.0\n */\nexport class SpecialistError extends Schema.Error<SpecialistError>(\"effect-assistant/Specialist/SpecialistError\")({\n _tag: Schema.tag(\"SpecialistError\"),\n reason: Schema.Literals([\"UnknownSpecialist\", \"RunNotFound\", \"NotRunning\"]),\n message: Schema.String\n}) {}\n\n/**\n * Service that runs a chat's specialists and keeps finished runs warm for follow-ups.\n *\n * The engine provides it to every turn. The specialist tools use it, and a handler can too.\n *\n * @category services\n * @since 0.1.0\n */\nexport class Runner extends Context.Service<\n Runner,\n {\n /** Starts a run and returns its id. */\n readonly spawn: (request: SpawnRequest) => Effect.Effect<RunId, SpecialistError>\n /** Steers a running run, or continues a finished one. */\n readonly message: (runId: RunId, text: string) => Effect.Effect<\"steered\" | \"continued\", SpecialistError>\n /** Interrupts a running run. */\n readonly stop: (runId: RunId) => Effect.Effect<void, SpecialistError>\n }\n>()(\"effect-assistant/Specialist/Runner\") {}\n"],"mappings":";;;;;;;;;;;;;AA2BA,MAAM,SAAS;AAuKf,MAAM,YACJ,WAGyD,OAAO,SAAS,MAAM,IAAI,OAAO,OAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsC7G,MAAa,QACX,MACA,YAIqB;CACrB,MAAM,UAAU,QAAQ,QAAwC,+BAA+B,MAAM;CASrG,SAAS,QACP,OACkD;EAClD,OAAO,MAAM,OACX,SACA,OAAO,IAAI,aAAa;GACtB,MAAM,UAAU,OAAO,OAAO,QAAQ;GAEtC,OAAO,EAGL,MAAM,OAAO,IAAI,aAAa;IAC5B,MAAM,UAAU,OAAO,SAAS,KAAK,IAAI,OAAO,QAAQ;IAExD,QAAQ,QAAa,OAAO,eAAe,SAAS,QAAQ,GAAG,CAAC,GAAG,OAAO;GAC5E,CAAC,CAAC,CAAC,KAAK,OAAO,eAAe,OAAO,GAAG,OAAO,KAAK,EACtD;EACF,CAAC,CACH;CACF;CAEA,OAAO;GAAG,SAAS;EAAQ;EAAM,aAAa,QAAQ;EAAa;EAAS;CAAQ;AACtF;;;;;;;;;AAUA,MAAa,QAAQ,OAAO,OAAO;CACjC,MAAM,OAAO,OAAO,SAAS,EAAE,aAAa,0BAA0B,CAAC;CACvE,SAAS,OAAO,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,EAC/C,aAAa,iDACf,CAAC;CACD,iBAAiB,OAAO,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,EAAE,aAAa,mBAAmB,CAAC;CAC5F,QAAQ,OAAO,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,EAC9C,aAAa,sCACf,CAAC;CACD,QAAQ,OAAO,SAAS,OAAO,MAAM,CAAC,CAAC,SAAS,EAC9C,aAAa,0DACf,CAAC;AACH,CAAC;;;;;;;;;;;;;AAkCD,IAAa,kBAAb,cAAqC,OAAO,MAAuB,6CAA6C,CAAC,CAAC;CAChH,MAAM,OAAO,IAAI,iBAAiB;CAClC,QAAQ,OAAO,SAAS;EAAC;EAAqB;EAAe;CAAY,CAAC;CAC1E,SAAS,OAAO;AAClB,CAAC,CAAC,CAAC,CAAC;;;;;;;;;AAUJ,IAAa,SAAb,cAA4B,QAAQ,QAUlC,CAAC,CAAC,oCAAoC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { AssistantToolCall } from "./AssistantToolCall.js";
|
|
2
|
+
import { ToolServices, toolkit_d_exports } from "./internal/toolkit.js";
|
|
3
|
+
import * as Schema from "effect/Schema";
|
|
4
|
+
import * as Tool from "effect/ai/Tool";
|
|
5
|
+
import * as Toolkit from "effect/ai/Toolkit";
|
|
6
|
+
declare namespace ToolDiscovery_d_exports {
|
|
7
|
+
export { layer, make };
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Creates the `search_tools` and `execute_tool` tools over a catalog toolkit, as a native toolkit.
|
|
11
|
+
*
|
|
12
|
+
* **Details**
|
|
13
|
+
*
|
|
14
|
+
* Merge the toolkit into the loop's, and provide {@link layer} for the same catalog, which has
|
|
15
|
+
* the tools' handlers. A catalog tool's services are `execute_tool`'s, so the turn provides them
|
|
16
|
+
* as it does for any tool.
|
|
17
|
+
*
|
|
18
|
+
* `execute_tool` doesn't run a tool that needs the user's decision; keep such tools in the loop's
|
|
19
|
+
* toolkit directly.
|
|
20
|
+
*
|
|
21
|
+
* **Example** (Finding rarely used tools when needed)
|
|
22
|
+
*
|
|
23
|
+
* ```ts
|
|
24
|
+
* import { ToolDiscovery } from "effect-assistant"
|
|
25
|
+
* import * as Toolkit from "effect/ai/Toolkit"
|
|
26
|
+
* import * as Layer from "effect/Layer"
|
|
27
|
+
*
|
|
28
|
+
* // OfficeTools is a big toolkit, found when needed. CommonTools stays in the prompt.
|
|
29
|
+
* const OfficeDiscovery = ToolDiscovery.make(OfficeTools)
|
|
30
|
+
* const OfficeDiscoveryLive = ToolDiscovery.layer(OfficeTools).pipe(Layer.provide(OfficeToolsLive))
|
|
31
|
+
*
|
|
32
|
+
* const MyAssistantLive = MyAssistant.toLayer((turn) =>
|
|
33
|
+
* turn.loop({
|
|
34
|
+
* instructions,
|
|
35
|
+
* toolkit: Toolkit.merge(CommonTools, OfficeDiscovery)
|
|
36
|
+
* })
|
|
37
|
+
* ).pipe(Layer.provide([CommonToolsLive, OfficeDiscoveryLive]))
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @see {@link layer} for the tools' handlers
|
|
41
|
+
*
|
|
42
|
+
* @category constructors
|
|
43
|
+
* @since 0.1.0
|
|
44
|
+
*/
|
|
45
|
+
export declare const make: <T extends Record<string, Tool.Any>>(_catalog: Toolkit.Toolkit<T>) => Toolkit.Toolkit<{
|
|
46
|
+
readonly execute_tool: Tool.Tool<"execute_tool", {
|
|
47
|
+
readonly parameters: Schema.Struct<{
|
|
48
|
+
readonly name: Schema.String;
|
|
49
|
+
readonly input: Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
50
|
+
}>;
|
|
51
|
+
readonly success: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
52
|
+
readonly failure: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
53
|
+
readonly failureMode: "error";
|
|
54
|
+
}, AssistantToolCall | ToolServices<T>>;
|
|
55
|
+
readonly search_tools: Tool.Tool<"search_tools", {
|
|
56
|
+
readonly parameters: Schema.Struct<{
|
|
57
|
+
readonly query: Schema.String;
|
|
58
|
+
}>;
|
|
59
|
+
readonly success: Schema.$Array<Schema.Struct<{
|
|
60
|
+
readonly name: Schema.String;
|
|
61
|
+
readonly description: Schema.optional<Schema.String>;
|
|
62
|
+
readonly inputSchema: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
63
|
+
}>>;
|
|
64
|
+
readonly failure: Schema.Never;
|
|
65
|
+
readonly failureMode: "error";
|
|
66
|
+
}, never>;
|
|
67
|
+
}>;
|
|
68
|
+
/**
|
|
69
|
+
* Creates the layer with the handlers of the `search_tools` and `execute_tool` tools over a
|
|
70
|
+
* catalog toolkit.
|
|
71
|
+
*
|
|
72
|
+
* **Details**
|
|
73
|
+
*
|
|
74
|
+
* The layer needs the catalog's handlers. It provides the handlers of the toolkit that
|
|
75
|
+
* {@link make} returns for the same catalog: handlers are keyed by tool name, so the two calls
|
|
76
|
+
* don't need to share a value. Give both the same catalog.
|
|
77
|
+
*
|
|
78
|
+
* @see {@link make} for the toolkit and an example
|
|
79
|
+
*
|
|
80
|
+
* @category layers
|
|
81
|
+
* @since 0.1.0
|
|
82
|
+
*/
|
|
83
|
+
export declare const layer: <T extends Record<string, Tool.Any>>(catalog: Toolkit.Toolkit<T>) => import("effect/Layer").Layer<Tool.HandlersFor<{
|
|
84
|
+
readonly execute_tool: Tool.Tool<"execute_tool", {
|
|
85
|
+
readonly parameters: Schema.Struct<{
|
|
86
|
+
readonly name: Schema.String;
|
|
87
|
+
readonly input: Schema.$Record<Schema.String, Schema.Codec<Schema.Json, Schema.Json, never, never>>;
|
|
88
|
+
}>;
|
|
89
|
+
readonly success: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
90
|
+
readonly failure: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
91
|
+
readonly failureMode: "error";
|
|
92
|
+
}, AssistantToolCall | ToolServices<T>>;
|
|
93
|
+
readonly search_tools: Tool.Tool<"search_tools", {
|
|
94
|
+
readonly parameters: Schema.Struct<{
|
|
95
|
+
readonly query: Schema.String;
|
|
96
|
+
}>;
|
|
97
|
+
readonly success: Schema.$Array<Schema.Struct<{
|
|
98
|
+
readonly name: Schema.String;
|
|
99
|
+
readonly description: Schema.optional<Schema.String>;
|
|
100
|
+
readonly inputSchema: Schema.Codec<Schema.Json, Schema.Json, never, never>;
|
|
101
|
+
}>>;
|
|
102
|
+
readonly failure: Schema.Never;
|
|
103
|
+
readonly failureMode: "error";
|
|
104
|
+
}, never>;
|
|
105
|
+
}>, never, Exclude<Tool.HandlersFor<T>, import("effect/Scope").Scope>>;
|
|
106
|
+
//#endregion
|
|
107
|
+
export { ToolDiscovery_d_exports };
|
|
108
|
+
//# sourceMappingURL=ToolDiscovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ToolDiscovery.d.ts","names":[],"sources":["../src/ToolDiscovery.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA2Ha,OAAQ,UAAU,eAAe,KAAK,MAAI,UAE3C,QAAQ,QAAQ,OAAE,QAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAkBjB,QAAS,UAAU,eAAe,KAAK,MAAI,SAAW,QAAQ,QAAQ,8BAAE,MAAA,KAAA;;;;;;;;;;;;;;;;;;;;;;WA2ClF,QAAA,KAAA,YAAA,2BAAA"}
|