@recombine-ai/engine 0.6.0 → 0.7.1
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/build/index.d.ts +4 -5
- package/build/index.d.ts.map +1 -1
- package/build/index.js +4 -8
- package/build/lib/ai.d.ts +336 -328
- package/build/lib/ai.d.ts.map +1 -1
- package/build/lib/ai.js +288 -275
- package/build/lib/bosun/agent.d.ts +34 -24
- package/build/lib/bosun/agent.d.ts.map +1 -1
- package/build/lib/bosun/agent.js +4 -27
- package/build/lib/bosun/context.d.ts.map +1 -1
- package/build/lib/bosun/context.js +1 -4
- package/build/lib/bosun/index.d.ts +2 -0
- package/build/lib/bosun/index.d.ts.map +1 -1
- package/build/lib/bosun/index.js +1 -0
- package/build/lib/bosun/stepTracer.d.ts +14 -0
- package/build/lib/bosun/stepTracer.d.ts.map +1 -0
- package/build/lib/bosun/stepTracer.js +2 -0
- package/build/lib/bosun/tracer.d.ts +19 -0
- package/build/lib/bosun/tracer.d.ts.map +1 -0
- package/build/lib/bosun/tracer.js +20 -0
- package/build/lib/interfaces.d.ts +17 -19
- package/build/lib/interfaces.d.ts.map +1 -1
- package/build/lib/prompt-fs.d.ts +17 -0
- package/build/lib/prompt-fs.d.ts.map +1 -0
- package/build/lib/prompt-fs.js +23 -0
- package/build/lib/rc-fs.d.ts +17 -0
- package/build/lib/rc-fs.d.ts.map +1 -0
- package/build/lib/rc-fs.js +22 -0
- package/changelog.md +26 -4
- package/eslint.config.mjs +52 -0
- package/package.json +9 -2
package/build/lib/ai.d.ts
CHANGED
|
@@ -1,355 +1,363 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ZodTypeAny } from 'zod';
|
|
2
2
|
import { Logger } from './interfaces';
|
|
3
3
|
import { SendAction } from './bosun/action';
|
|
4
|
-
|
|
4
|
+
import { PromptFile } from './prompt-fs';
|
|
5
|
+
import { StepTracer } from './bosun/stepTracer';
|
|
6
|
+
import { Tracer } from './bosun';
|
|
7
|
+
/**
|
|
8
|
+
* Represents a basic model name for LLMs.
|
|
9
|
+
*/
|
|
10
|
+
export type BasicModel = 'o3-mini-2025-01-31' | 'o1-preview-2024-09-12' | 'gpt-4o-2024-11-20' | 'o1-2024-12-17' | (string & {});
|
|
11
|
+
export interface ProgrammaticStep<CTX> {
|
|
12
|
+
/** Step name for debugging */
|
|
13
|
+
name: string;
|
|
14
|
+
/** Determines if the step should be run or not */
|
|
15
|
+
runIf?: (messages: Conversation, ctx: CTX) => boolean | Promise<boolean>;
|
|
16
|
+
/** Content of the step */
|
|
17
|
+
execute: (messages: Conversation, ctx: CTX) => Promise<unknown>;
|
|
18
|
+
/** Error handler called if an error occurred during in `execute` function */
|
|
19
|
+
onError?: (error: string, ctx: CTX) => Promise<unknown>;
|
|
20
|
+
}
|
|
21
|
+
export interface LLMStep<CTX> {
|
|
22
|
+
/** Step name for debugging */
|
|
23
|
+
name: string;
|
|
24
|
+
/** Determines if the step should be run or not */
|
|
25
|
+
runIf?: (messages: Conversation, ctx: CTX) => boolean | Promise<boolean>;
|
|
26
|
+
/** LLM to use. Defaults to gpt-4o */
|
|
27
|
+
model?: BasicModel;
|
|
5
28
|
/**
|
|
6
|
-
*
|
|
29
|
+
* Prompt can be a simple string or a link to a file, loaded with `loadFile` function which
|
|
30
|
+
* takes a path to the file relative to `src/use-cases` directory. Should be Nunjucks-compatible.
|
|
7
31
|
*/
|
|
8
|
-
|
|
9
|
-
export interface ProgrammaticStep {
|
|
10
|
-
/** Step name for debugging */
|
|
11
|
-
name: string;
|
|
12
|
-
/** Determines if the step should be run or not */
|
|
13
|
-
runIf?: (messages: Conversation) => boolean | Promise<boolean>;
|
|
14
|
-
/** Content of the step */
|
|
15
|
-
execute: () => Promise<unknown>;
|
|
16
|
-
/** Error handler called if an error occurred during in `execute` function */
|
|
17
|
-
onError: (error: string) => Promise<unknown>;
|
|
18
|
-
}
|
|
19
|
-
export interface LLMStep {
|
|
20
|
-
/** Step name for debugging */
|
|
21
|
-
name: string;
|
|
22
|
-
/** Determines if the step should be run or not */
|
|
23
|
-
runIf?: (messages: Conversation) => boolean | Promise<boolean>;
|
|
24
|
-
/** LLM to use. Defaults to gpt-4o */
|
|
25
|
-
model?: BasicModel;
|
|
26
|
-
/**
|
|
27
|
-
* Prompt can be a simple string or a link to a file, loaded with `loadFile` function which
|
|
28
|
-
* takes a path to the file relative to `src/use-cases` directory. Should be Nunjucks-compatible.
|
|
29
|
-
*/
|
|
30
|
-
prompt: string | File;
|
|
31
|
-
/**
|
|
32
|
-
* Defines the expected structure of the LLM's output.
|
|
33
|
-
* Accepts either a boolean (for plain text or JSON responses) or a ZodSchema, which is automatically
|
|
34
|
-
* converted to a JSON schema. When provided, the LLM's response is validated and parsed according
|
|
35
|
-
* to this schema ensuring reliable structured output.
|
|
36
|
-
*/
|
|
37
|
-
json: boolean | ZodSchema;
|
|
38
|
-
/**
|
|
39
|
-
* Do not put messages that were added via {@link Conversation.addMessage} into the prompt.
|
|
40
|
-
*/
|
|
41
|
-
ignoreAddedMessages?: boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Additional data to be inserted into the prompt. Accessible via Nunjucks variables.
|
|
44
|
-
* @example
|
|
45
|
-
* ```
|
|
46
|
-
* prompt: "Hello {{ name }}, your score is {{ score }}"
|
|
47
|
-
* context: { name: "John", score: 42 }
|
|
48
|
-
* ```
|
|
49
|
-
*/
|
|
50
|
-
context?: Record<string, unknown>;
|
|
51
|
-
/**
|
|
52
|
-
* Function to execute with the LLM's response. Use {@link setProposedReply} to use the LLM's output as the proposed reply.
|
|
53
|
-
* Or use combination of {@link getProposedReply} and {@link setProposedReply} to substitute parts of the string.
|
|
54
|
-
* @example
|
|
55
|
-
* ```
|
|
56
|
-
* // Use LLM output directly as reply
|
|
57
|
-
* execute: (reply) => messages.setProposedReply(reply)
|
|
58
|
-
*
|
|
59
|
-
* // Substitute tokens in LLM output
|
|
60
|
-
* execute: (reply) => {
|
|
61
|
-
* const withLink = reply.replace('<PAYMENT_LINK>', 'https://payment.example.com/123')
|
|
62
|
-
* messages.setProposedReply(withLink)
|
|
63
|
-
* }
|
|
64
|
-
* ```
|
|
65
|
-
*/
|
|
66
|
-
execute: (reply: string) => Promise<unknown>;
|
|
67
|
-
/**
|
|
68
|
-
* Check a condition, whether the `execute` function should run or not
|
|
69
|
-
* @deprecated use `runIf` to check if the step should be run, use if in `execute` to check
|
|
70
|
-
* if it should be executed
|
|
71
|
-
**/
|
|
72
|
-
shouldExecute?: (reply: string) => boolean | Promise<boolean>;
|
|
73
|
-
/**
|
|
74
|
-
* When provided, throws an error if the step is invoked more times than `maxAttempts`.
|
|
75
|
-
* Number of attempts taken is reset when `shouldExecute` returns `false`. Useful to limit
|
|
76
|
-
* rewinds by reviewers. NOTE that it doesn't work on steps without `shouldExecute` method.
|
|
77
|
-
*/
|
|
78
|
-
maxAttempts?: number;
|
|
79
|
-
/** Error handler called if an error occurred during LLM API call or in `execute` function */
|
|
80
|
-
onError: (error: string) => Promise<unknown>;
|
|
81
|
-
}
|
|
32
|
+
prompt: string | PromptFile;
|
|
82
33
|
/**
|
|
83
|
-
*
|
|
34
|
+
* Do not put messages that were added via {@link Conversation.addMessage} into the prompt.
|
|
84
35
|
*/
|
|
85
|
-
|
|
86
|
-
renderedPrompt?: string;
|
|
87
|
-
receivedContext?: Record<string, unknown>;
|
|
88
|
-
receivedPrompt?: string;
|
|
89
|
-
stringifiedConversation?: string;
|
|
90
|
-
};
|
|
36
|
+
ignoreAddedMessages?: boolean;
|
|
91
37
|
/**
|
|
92
|
-
*
|
|
38
|
+
* When provided, throws an error if the step is invoked more times than `maxAttempts`.
|
|
39
|
+
* Number of attempts taken is reset when `shouldExecute` returns `false`. Useful to limit
|
|
40
|
+
* rewinds by reviewers. NOTE that it doesn't work on steps without `shouldExecute` method.
|
|
93
41
|
*/
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* Runs the workflow with a given conversation context.
|
|
101
|
-
* Executes steps sequentially until completion or termination.
|
|
102
|
-
* @param messages - The conversation context for the workflow
|
|
103
|
-
* @returns The proposed reply if workflow completes, or null if terminated
|
|
104
|
-
*/
|
|
105
|
-
run: (messages: Conversation) => Promise<{
|
|
106
|
-
reply: string | null;
|
|
107
|
-
trace: {
|
|
108
|
-
steps: Record<string, StepTrace>;
|
|
109
|
-
};
|
|
110
|
-
}>;
|
|
111
|
-
/**
|
|
112
|
-
* Rewinds the workflow execution to a specific step.
|
|
113
|
-
* @param step - The step to rewind to
|
|
114
|
-
*/
|
|
115
|
-
rewindTo: (step: LLMStep | ProgrammaticStep) => void;
|
|
116
|
-
/**
|
|
117
|
-
* Registers a callback to be executed before each step.
|
|
118
|
-
* @param callback - Async function to execute before each step
|
|
119
|
-
*/
|
|
120
|
-
beforeEach: (callback: () => Promise<unknown>) => void;
|
|
121
|
-
}
|
|
42
|
+
maxAttempts?: number;
|
|
43
|
+
/** Error handler called if an error occurred during LLM API call or in `execute` function */
|
|
44
|
+
onError?: (error: string, ctx: CTX) => Promise<unknown>;
|
|
45
|
+
}
|
|
46
|
+
export interface JsonLLMStep<CTX, Schema extends ZodTypeAny> extends LLMStep<CTX> {
|
|
122
47
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
48
|
+
* Defines the expected structure of the LLM's output. Accepts ZodSchema. When provided, the
|
|
49
|
+
* LLM's response is validated and parsed according to this schema ensuring reliable structured
|
|
50
|
+
* output.
|
|
51
|
+
*/
|
|
52
|
+
schema: Schema;
|
|
53
|
+
/**
|
|
54
|
+
* Function to execute with the LLM's response. Use {@link setProposedReply} to use the LLM's output as the proposed reply.
|
|
55
|
+
* Or use combination of {@link getProposedReply} and {@link setProposedReply} to substitute parts of the string.
|
|
125
56
|
* @example
|
|
126
|
-
* ```
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
* // Create a new AI engine instance
|
|
130
|
-
* const ai = AIEngine.createAIEngine()
|
|
131
|
-
*
|
|
132
|
-
* // Create a conversation
|
|
133
|
-
* const conversation = ai.createConversation()
|
|
134
|
-
* conversation.addMessage('user', 'I need help with my order')
|
|
135
|
-
*
|
|
136
|
-
* // Define workflow steps
|
|
137
|
-
* const killswitch = ai.createStep({
|
|
138
|
-
* name: 'killswitch',
|
|
139
|
-
* prompt: ai.loadFile('prompts/killswitch.njk'),
|
|
140
|
-
* execute: async (reply) => {
|
|
141
|
-
* const result = JSON.parse(reply)
|
|
142
|
-
* if (result.terminate) {
|
|
143
|
-
* conversation.addDirective(`Terminating workflow: ${result.reason}`)
|
|
144
|
-
* return workflow.terminate()
|
|
145
|
-
* }
|
|
146
|
-
* },
|
|
147
|
-
* onError: async (error) => conversation.addDirective(`Error in killswitch: ${error}`)
|
|
148
|
-
* })
|
|
149
|
-
*
|
|
150
|
-
* const analyzeIntent = ai.createStep({
|
|
151
|
-
* name: 'analyze-intent',
|
|
152
|
-
* prompt: ai.loadFile('prompts/analyze-intent.njk'),
|
|
153
|
-
* execute: async (reply) => {
|
|
154
|
-
* const intent = JSON.parse(reply)
|
|
155
|
-
* conversation.addDirective(`User intent is: ${intent.category}`)
|
|
156
|
-
* },
|
|
157
|
-
* onError: async (error) => conversation.addDirective(`Error analyzing intent: ${error}`)
|
|
158
|
-
* })
|
|
159
|
-
*
|
|
160
|
-
* const mainReply = ai.createStep({
|
|
161
|
-
* name: 'main-reply',
|
|
162
|
-
* prompt: ai.loadFile('prompts/generate-response.njk'),
|
|
163
|
-
* execute: async (reply) => conversation.setProposedReply(reply),
|
|
164
|
-
* onError: async (error) => conversation.setProposedReply(`I'm sorry, I'm having trouble right now.`)
|
|
165
|
-
* })
|
|
57
|
+
* ```
|
|
58
|
+
* // Use LLM output directly as reply
|
|
59
|
+
* execute: (reply) => messages.setProposedReply(reply)
|
|
166
60
|
*
|
|
167
|
-
* //
|
|
168
|
-
*
|
|
169
|
-
*
|
|
170
|
-
*
|
|
61
|
+
* // Substitute tokens in LLM output
|
|
62
|
+
* execute: (reply) => {
|
|
63
|
+
* const withLink = reply.replace('<PAYMENT_LINK>', 'https://payment.example.com/123')
|
|
64
|
+
* messages.setProposedReply(withLink)
|
|
65
|
+
* }
|
|
171
66
|
* ```
|
|
172
67
|
*/
|
|
173
|
-
|
|
174
|
-
/**
|
|
175
|
-
* Creates a workflow from a sequence of steps.
|
|
176
|
-
* @param steps - An array of LLM or programmatic steps to be executed in order.
|
|
177
|
-
* @returns A Promise that resolves to the created Workflow.
|
|
178
|
-
*/
|
|
179
|
-
createWorkflow: (...steps: Array<LLMStep | ProgrammaticStep>) => Promise<Workflow>;
|
|
180
|
-
/**
|
|
181
|
-
* Creates a step that can be used in a workflow.
|
|
182
|
-
* @param step - The LLM or programmatic step to create.
|
|
183
|
-
* @returns The created step of the same type as the input.
|
|
184
|
-
*/
|
|
185
|
-
createStep: <T extends LLMStep | ProgrammaticStep>(step: T) => T;
|
|
186
|
-
/**
|
|
187
|
-
* Loads a file from the specified path.
|
|
188
|
-
* @param path - The path to the file to load.
|
|
189
|
-
* @returns The loaded File object.
|
|
190
|
-
*/
|
|
191
|
-
loadFile: (path: string) => File;
|
|
192
|
-
/**
|
|
193
|
-
* Creates a new conversation instance.
|
|
194
|
-
* @param messages - Optional initial messages for the conversation.
|
|
195
|
-
* @returns A new Conversation object.
|
|
196
|
-
*/
|
|
197
|
-
createConversation: (messages?: Message[]) => Conversation;
|
|
198
|
-
/**
|
|
199
|
-
* Renders a prompt string using Nunjucks templating engine.
|
|
200
|
-
* @param prompt - The prompt string to render.
|
|
201
|
-
* @param context - Optional context object to use for rendering the prompt.
|
|
202
|
-
* @returns The rendered prompt string.
|
|
203
|
-
*/
|
|
204
|
-
renderPrompt: typeof renderPrompt;
|
|
205
|
-
}
|
|
68
|
+
execute: (reply: Zod.infer<Schema>, conversation: Conversation, ctx: CTX) => Promise<unknown>;
|
|
206
69
|
/**
|
|
207
|
-
*
|
|
208
|
-
*
|
|
209
|
-
*
|
|
70
|
+
* Check a condition, whether the `execute` function should run or not
|
|
71
|
+
* @deprecated use `runIf` to check if the step should be run, use if in `execute` to check
|
|
72
|
+
* if it should be executed
|
|
73
|
+
**/
|
|
74
|
+
shouldExecute?: (reply: Schema, ctx: CTX) => boolean | Promise<boolean>;
|
|
75
|
+
}
|
|
76
|
+
export interface StringLLMStep<CTX> extends LLMStep<CTX> {
|
|
77
|
+
/**
|
|
78
|
+
* Function to execute with the LLM's response. Use {@link setProposedReply} to use the LLM's output as the proposed reply.
|
|
79
|
+
* Or use combination of {@link getProposedReply} and {@link setProposedReply} to substitute parts of the string.
|
|
210
80
|
* @example
|
|
211
|
-
* ```
|
|
212
|
-
* //
|
|
213
|
-
*
|
|
214
|
-
*
|
|
215
|
-
* // Set names for the participants
|
|
216
|
-
* conversation.setUserName("Client");
|
|
217
|
-
* conversation.setAgentName("Support");
|
|
218
|
-
*
|
|
219
|
-
* // Add messages to the conversation
|
|
220
|
-
* conversation.addMessage("user", "I need help with my account");
|
|
221
|
-
* conversation.addDirective("Ask for account details");
|
|
81
|
+
* ```
|
|
82
|
+
* // Use LLM output directly as reply
|
|
83
|
+
* execute: (reply) => messages.setProposedReply(reply)
|
|
222
84
|
*
|
|
223
|
-
* //
|
|
224
|
-
*
|
|
225
|
-
*
|
|
226
|
-
*
|
|
227
|
-
*
|
|
85
|
+
* // Substitute tokens in LLM output
|
|
86
|
+
* execute: (reply) => {
|
|
87
|
+
* const withLink = reply.replace('<PAYMENT_LINK>', 'https://payment.example.com/123')
|
|
88
|
+
* messages.setProposedReply(withLink)
|
|
89
|
+
* }
|
|
228
90
|
* ```
|
|
229
91
|
*/
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
* Sets the default formatter for stringifying messages when toString is called.
|
|
243
|
-
* @param formatter - A function that takes a message and returns a formatted string.
|
|
244
|
-
*/
|
|
245
|
-
setDefaultFormatter: (formatter: (message: Message) => string) => void;
|
|
246
|
-
/**
|
|
247
|
-
* Converts the conversation to a string representation to be fed to an LLM.
|
|
248
|
-
* @param filter - A function that filters messages based on certain criteria.
|
|
249
|
-
* @example
|
|
250
|
-
* @returns The string representation of the conversation.
|
|
251
|
-
*/
|
|
252
|
-
toString: (options?: {
|
|
253
|
-
ignoreAddedMessages?: boolean;
|
|
254
|
-
}) => string;
|
|
255
|
-
/**
|
|
256
|
-
* Adds a message from a specified sender to the conversation.
|
|
257
|
-
* @param message - The message to add to the conversation.
|
|
258
|
-
*/
|
|
259
|
-
addMessage: (message: Message, opts?: {
|
|
260
|
-
formatter?: (message: Message) => string;
|
|
261
|
-
}) => void;
|
|
262
|
-
/**
|
|
263
|
-
* Sets a custom formatter for proposed messages.
|
|
264
|
-
* @param formatter - A function that takes a message string and returns a formatted string.
|
|
265
|
-
*/
|
|
266
|
-
setProposedMessageFormatter: (formatter: (message: string) => string) => void;
|
|
267
|
-
/**
|
|
268
|
-
* Sets a proposed reply message.
|
|
269
|
-
* @param message - The proposed reply message.
|
|
270
|
-
*/
|
|
271
|
-
setProposedReply: (message: string) => void;
|
|
272
|
-
/**
|
|
273
|
-
* Gets the current proposed reply message.
|
|
274
|
-
* @returns The proposed reply message, or null if none exists.
|
|
275
|
-
*/
|
|
276
|
-
getProposedReply: () => string | null;
|
|
277
|
-
/**
|
|
278
|
-
* Gets the history of all messages in the conversation.
|
|
279
|
-
* Returns {@link Message} rather than {@link ConversationMessage} because none of the {@link ConversationMessage} properties should be accessed outside of the {@link Conversation} context.
|
|
280
|
-
* @returns An array of Message objects representing the conversation history.
|
|
281
|
-
*/
|
|
282
|
-
getHistory: () => Message[];
|
|
283
|
-
}
|
|
92
|
+
execute: (reply: string, conversation: Conversation, ctx: CTX) => Promise<unknown>;
|
|
93
|
+
/**
|
|
94
|
+
* Check a condition, whether the `execute` function should run or not
|
|
95
|
+
* @deprecated use `runIf` to check if the step should be run, use if in `execute` to check
|
|
96
|
+
* if it should be executed
|
|
97
|
+
**/
|
|
98
|
+
shouldExecute?: (reply: string, ctx: CTX) => boolean | Promise<boolean>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* An AI workflow composed of steps.
|
|
102
|
+
*/
|
|
103
|
+
export interface Workflow<CTX> {
|
|
284
104
|
/**
|
|
285
|
-
*
|
|
286
|
-
* Messages can contain text and optionally an image URL. To be used in the {@link Conversation} interface.
|
|
105
|
+
* Terminates the workflow, preventing further steps from being executed.
|
|
287
106
|
*/
|
|
288
|
-
|
|
289
|
-
/** The sender of the message, which can be one of the following: 'user', 'agent', or 'system' */
|
|
290
|
-
sender: 'user' | 'agent' | 'system';
|
|
291
|
-
/** The text content of the message */
|
|
292
|
-
text: string;
|
|
293
|
-
/** Optional URL of an image associated with the message */
|
|
294
|
-
imageUrl?: string;
|
|
295
|
-
}
|
|
296
|
-
export interface File {
|
|
297
|
-
content: () => Promise<string>;
|
|
298
|
-
}
|
|
107
|
+
terminate: () => void;
|
|
299
108
|
/**
|
|
300
|
-
*
|
|
109
|
+
* Runs the workflow with a given conversation context.
|
|
110
|
+
* Executes steps sequentially until completion or termination.
|
|
111
|
+
* @param messages - The conversation context for the workflow
|
|
112
|
+
* @returns The proposed reply if workflow completes, or null if terminated
|
|
301
113
|
*/
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Optional token storage object that provides access to authentication tokens.
|
|
305
|
-
* @property {object} tokenStorage - Object containing method to retrieve token.
|
|
306
|
-
* @property {() => Promise<string | null>} tokenStorage.getToken - Function that returns a promise resolving to an authentication token or null.
|
|
307
|
-
*/
|
|
308
|
-
tokenStorage?: {
|
|
309
|
-
getToken: () => Promise<string | null>;
|
|
310
|
-
};
|
|
311
|
-
/**
|
|
312
|
-
* Optional base URL path for resolving paths to prompts.
|
|
313
|
-
*/
|
|
314
|
-
basePath?: string;
|
|
315
|
-
/**
|
|
316
|
-
* Optional logger instance for handling log messages.
|
|
317
|
-
*/
|
|
318
|
-
logger?: Logger;
|
|
319
|
-
/**
|
|
320
|
-
* Optional function for sending actions.
|
|
321
|
-
*/
|
|
322
|
-
sendAction?: SendAction;
|
|
323
|
-
}
|
|
114
|
+
run: (messages: Conversation, ctx?: CTX) => Promise<string | null>;
|
|
324
115
|
/**
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
*
|
|
331
|
-
*
|
|
116
|
+
* Rewinds the workflow execution to a specific step.
|
|
117
|
+
* @param step - The step to rewind to
|
|
118
|
+
*/
|
|
119
|
+
rewindTo: (step: LLMStep<CTX> | ProgrammaticStep<CTX>) => void;
|
|
120
|
+
/**
|
|
121
|
+
* Registers a callback to be executed before each step.
|
|
122
|
+
* @param callback - Async function to execute before each step
|
|
123
|
+
*/
|
|
124
|
+
beforeEach: (callback: () => Promise<unknown>) => void;
|
|
125
|
+
/**
|
|
126
|
+
* Add a step to workflow
|
|
127
|
+
*/
|
|
128
|
+
addStep<Schema extends ZodTypeAny>(step: JsonLLMStep<CTX, Schema>): void;
|
|
129
|
+
addStep(step: StringLLMStep<CTX>): void;
|
|
130
|
+
addStep(step: ProgrammaticStep<CTX>): void;
|
|
131
|
+
}
|
|
132
|
+
export interface WorkflowConfig<CTX> {
|
|
133
|
+
onError: (error: string, ctx: CTX) => Promise<unknown>;
|
|
134
|
+
}
|
|
135
|
+
interface StepBuilder<CTX> {
|
|
136
|
+
<Schema extends ZodTypeAny>(step: JsonLLMStep<CTX, Schema>): JsonLLMStep<CTX, Schema>;
|
|
137
|
+
(step: StringLLMStep<CTX>): StringLLMStep<CTX>;
|
|
138
|
+
(step: ProgrammaticStep<CTX>): ProgrammaticStep<CTX>;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* The main interface for the AI Engine.
|
|
142
|
+
*
|
|
143
|
+
* @example
|
|
144
|
+
* ```typescript
|
|
145
|
+
* import { AIEngine } from './lib/ai'
|
|
146
|
+
*
|
|
147
|
+
* // Create a new AI engine instance
|
|
148
|
+
* const ai = AIEngine.createAIEngine()
|
|
149
|
+
*
|
|
150
|
+
* // Create a conversation
|
|
151
|
+
* const conversation = ai.createConversation()
|
|
152
|
+
* conversation.addMessage('user', 'I need help with my order')
|
|
153
|
+
*
|
|
154
|
+
* // Define workflow steps
|
|
155
|
+
* const killswitch = ai.createStep({
|
|
156
|
+
* name: 'killswitch',
|
|
157
|
+
* prompt: ai.loadFile('prompts/killswitch.njk'),
|
|
158
|
+
* execute: async (reply) => {
|
|
159
|
+
* const result = JSON.parse(reply)
|
|
160
|
+
* if (result.terminate) {
|
|
161
|
+
* conversation.addDirective(`Terminating workflow: ${result.reason}`)
|
|
162
|
+
* return workflow.terminate()
|
|
163
|
+
* }
|
|
164
|
+
* },
|
|
165
|
+
* onError: async (error) => conversation.addDirective(`Error in killswitch: ${error}`)
|
|
166
|
+
* })
|
|
167
|
+
*
|
|
168
|
+
* const analyzeIntent = ai.createStep({
|
|
169
|
+
* name: 'analyze-intent',
|
|
170
|
+
* prompt: ai.loadFile('prompts/analyze-intent.njk'),
|
|
171
|
+
* execute: async (reply) => {
|
|
172
|
+
* const intent = JSON.parse(reply)
|
|
173
|
+
* conversation.addDirective(`User intent is: ${intent.category}`)
|
|
174
|
+
* },
|
|
175
|
+
* onError: async (error) => conversation.addDirective(`Error analyzing intent: ${error}`)
|
|
176
|
+
* })
|
|
177
|
+
*
|
|
178
|
+
* const mainReply = ai.createStep({
|
|
179
|
+
* name: 'main-reply',
|
|
180
|
+
* prompt: ai.loadFile('prompts/generate-response.njk'),
|
|
181
|
+
* execute: async (reply) => conversation.setProposedReply(reply),
|
|
182
|
+
* onError: async (error) => conversation.setProposedReply(`I'm sorry, I'm having trouble right now.`)
|
|
183
|
+
* })
|
|
184
|
+
*
|
|
185
|
+
* // Create and run the workflow
|
|
186
|
+
* const workflow = await ai.createWorkflow(killswitch, analyzeIntent, mainReply)
|
|
187
|
+
* const response = await workflow.run(conversation)
|
|
188
|
+
* console.log(response)
|
|
189
|
+
* ```
|
|
190
|
+
*/
|
|
191
|
+
export interface AIEngine {
|
|
192
|
+
/**
|
|
193
|
+
* Creates a workflow from a sequence of steps.
|
|
194
|
+
* @param config - common parameters for a workflow
|
|
195
|
+
* @returns A Promise that resolves to the created Workflow.
|
|
196
|
+
*/
|
|
197
|
+
createWorkflow: <CTX>(config: WorkflowConfig<CTX>) => Workflow<CTX>;
|
|
198
|
+
/**
|
|
199
|
+
* Creates a new conversation instance.
|
|
200
|
+
* @param messages - Optional initial messages for the conversation.
|
|
201
|
+
* @returns A new Conversation object.
|
|
202
|
+
*/
|
|
203
|
+
createConversation: (messages?: Message[]) => Conversation;
|
|
204
|
+
/**
|
|
205
|
+
* Get the function to create steps to use with workflow.addStep(step)
|
|
206
|
+
* if you want to define steps outside of workflow.
|
|
207
|
+
*/
|
|
208
|
+
getStepBuilder<CTX>(): StepBuilder<CTX>;
|
|
209
|
+
/**
|
|
210
|
+
* Renders a prompt string using Nunjucks templating engine.
|
|
211
|
+
* @param prompt - The prompt string to render.
|
|
212
|
+
* @param context - Optional context object to use for rendering the prompt.
|
|
213
|
+
* @returns The rendered prompt string.
|
|
214
|
+
*/
|
|
215
|
+
renderPrompt: typeof renderPrompt;
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Represents a conversation between a user and an AI agent.
|
|
219
|
+
* Provides methods to manage the conversation flow, format messages, and convert the conversation to a string representation.
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* // Create a new conversation instance
|
|
224
|
+
* const conversation = new Conversation();
|
|
225
|
+
*
|
|
226
|
+
* // Set names for the participants
|
|
227
|
+
* conversation.setUserName("Client");
|
|
228
|
+
* conversation.setAgentName("Support");
|
|
229
|
+
*
|
|
230
|
+
* // Add messages to the conversation
|
|
231
|
+
* conversation.addMessage("user", "I need help with my account");
|
|
232
|
+
* conversation.addDirective("Ask for account details");
|
|
233
|
+
*
|
|
234
|
+
* // Get the conversation as a string to feed to an LLM
|
|
235
|
+
* const conversationText = conversation.toString();
|
|
236
|
+
* // Output:
|
|
237
|
+
* // Client: I need help with my account
|
|
238
|
+
* // System: Ask for account details
|
|
239
|
+
* ```
|
|
240
|
+
*/
|
|
241
|
+
export interface Conversation {
|
|
242
|
+
/**
|
|
243
|
+
* Sets the name of the user in the conversation to be used in {@link toString}.
|
|
244
|
+
* @param name - The name to set for the user.
|
|
245
|
+
*/
|
|
246
|
+
setUserName(name: string): void;
|
|
247
|
+
/**
|
|
248
|
+
* Sets the name of the AI agent in the conversation to be used in {@link toString}.
|
|
249
|
+
* @param name - The name to set for the agent.
|
|
250
|
+
*/
|
|
251
|
+
setAgentName(name: string): void;
|
|
252
|
+
/**
|
|
253
|
+
* Sets the default formatter for stringifying messages when toString is called.
|
|
254
|
+
* @param formatter - A function that takes a message and returns a formatted string.
|
|
255
|
+
*/
|
|
256
|
+
setDefaultFormatter: (formatter: (message: Message) => string) => void;
|
|
257
|
+
/**
|
|
258
|
+
* Converts the conversation to a string representation to be fed to an LLM.
|
|
259
|
+
* @param filter - A function that filters messages based on certain criteria.
|
|
332
260
|
* @example
|
|
333
|
-
*
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
*
|
|
340
|
-
*
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
|
|
261
|
+
* @returns The string representation of the conversation.
|
|
262
|
+
*/
|
|
263
|
+
toString: (options?: {
|
|
264
|
+
ignoreAddedMessages?: boolean;
|
|
265
|
+
}) => string;
|
|
266
|
+
/**
|
|
267
|
+
* Adds a message from a specified sender to the conversation.
|
|
268
|
+
* @param message - The message to add to the conversation.
|
|
269
|
+
*/
|
|
270
|
+
addMessage: (message: Message, opts?: {
|
|
271
|
+
formatter?: (message: Message) => string;
|
|
272
|
+
}) => void;
|
|
273
|
+
/**
|
|
274
|
+
* Sets a custom formatter for proposed messages.
|
|
275
|
+
* @param formatter - A function that takes a message string and returns a formatted string.
|
|
276
|
+
*/
|
|
277
|
+
setProposedMessageFormatter: (formatter: (message: string) => string) => void;
|
|
278
|
+
/**
|
|
279
|
+
* Sets a proposed reply message.
|
|
280
|
+
* @param message - The proposed reply message.
|
|
281
|
+
*/
|
|
282
|
+
setProposedReply: (message: string) => void;
|
|
283
|
+
/**
|
|
284
|
+
* Gets the current proposed reply message.
|
|
285
|
+
* @returns The proposed reply message, or null if none exists.
|
|
286
|
+
*/
|
|
287
|
+
getProposedReply: () => string | null;
|
|
288
|
+
/**
|
|
289
|
+
* Gets the history of all messages in the conversation.
|
|
290
|
+
* Returns {@link Message} rather than {@link ConversationMessage} because none of the {@link ConversationMessage} properties should be accessed outside of the {@link Conversation} context.
|
|
291
|
+
* @returns An array of Message objects representing the conversation history.
|
|
292
|
+
*/
|
|
293
|
+
getHistory: () => Message[];
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Represents a message in a conversation between a user and an agent, or a system message.
|
|
297
|
+
* Messages can contain text and optionally an image URL. To be used in the {@link Conversation} interface.
|
|
298
|
+
*/
|
|
299
|
+
export interface Message {
|
|
300
|
+
/** The sender of the message, which can be one of the following: 'user', 'agent', or 'system' */
|
|
301
|
+
sender: 'user' | 'agent' | 'system';
|
|
302
|
+
/** The text content of the message */
|
|
303
|
+
text: string;
|
|
304
|
+
/** Optional URL of an image associated with the message */
|
|
305
|
+
imageUrl?: string;
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* Configuration options for the Engine.
|
|
309
|
+
*/
|
|
310
|
+
export interface EngineConfig {
|
|
311
|
+
/**
|
|
312
|
+
* Optional token storage object that provides access to authentication tokens.
|
|
313
|
+
* @property {object} tokenStorage - Object containing method to retrieve token.
|
|
314
|
+
* @property {() => Promise<string | null>} tokenStorage.getToken - Function that returns a promise resolving to an authentication token or null.
|
|
315
|
+
*/
|
|
316
|
+
tokenStorage?: {
|
|
317
|
+
getToken: () => Promise<string | null>;
|
|
318
|
+
};
|
|
319
|
+
/**
|
|
320
|
+
* Optional logger instance for handling log messages.
|
|
321
|
+
*/
|
|
322
|
+
logger?: Logger;
|
|
323
|
+
/**
|
|
324
|
+
* Optional function for sending actions.
|
|
349
325
|
*/
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
326
|
+
sendAction?: SendAction;
|
|
327
|
+
/** traces received prompt, rendered prompt, context and other useful info about LLM execution */
|
|
328
|
+
stepTracer?: StepTracer;
|
|
329
|
+
/** registers steps in workflow */
|
|
330
|
+
tracer?: Tracer;
|
|
354
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* Creates an AI Engine with the given configuration.
|
|
334
|
+
*
|
|
335
|
+
* The AI Engine provides utilities for creating and running conversational workflows
|
|
336
|
+
* with large language models, specifically OpenAI GPT models.
|
|
337
|
+
*
|
|
338
|
+
* @returns An AIEngine instance.
|
|
339
|
+
*
|
|
340
|
+
* @example
|
|
341
|
+
* ```ts
|
|
342
|
+
* const engine = createAIEngine({
|
|
343
|
+
* logger: customLogger,
|
|
344
|
+
* basePath: '/path/to/prompts'
|
|
345
|
+
* });
|
|
346
|
+
*
|
|
347
|
+
* const workflow = await engine.createWorkflow(
|
|
348
|
+
* engine.createStep({
|
|
349
|
+
* name: 'generate-response',
|
|
350
|
+
* prompt: engine.loadFile('prompts/response.txt'),
|
|
351
|
+
* execute: (response) => conversation.setProposedReply(response)
|
|
352
|
+
* })
|
|
353
|
+
* );
|
|
354
|
+
*
|
|
355
|
+
* const reply = await workflow.run(conversation);
|
|
356
|
+
* ```
|
|
357
|
+
*/
|
|
358
|
+
export declare function createAIEngine(cfg?: EngineConfig): AIEngine;
|
|
359
|
+
declare function renderPrompt(prompt: string, context?: Record<string, unknown>): string;
|
|
360
|
+
export declare function createConversation(initialMessages?: Message[]): Conversation;
|
|
361
|
+
export declare function getStepBuilder<CTX = unknown>(): StepBuilder<CTX>;
|
|
362
|
+
export {};
|
|
355
363
|
//# sourceMappingURL=ai.d.ts.map
|