@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.
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/lib/ai.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/lib/ai.ts"],"names":[],"mappings":"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"}
package/build/lib/ai.js CHANGED
@@ -3,315 +3,328 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AIEngine = void 0;
6
+ exports.createAIEngine = createAIEngine;
7
+ exports.createConversation = createConversation;
8
+ exports.getStepBuilder = getStepBuilder;
7
9
  // cspell:words lstripBlocks
8
- const fs_1 = __importDefault(require("fs"));
9
10
  const openai_1 = __importDefault(require("openai"));
10
- const path_1 = require("path");
11
11
  const nunjucks_1 = __importDefault(require("nunjucks"));
12
- const zod_to_json_schema_1 = require("zod-to-json-schema");
12
+ const zod_1 = require("zod");
13
13
  const action_1 = require("./bosun/action");
14
14
  const core_1 = require("openai/core");
15
- var AIEngine;
16
- (function (AIEngine) {
17
- /**
18
- * Creates an AI Engine with the given configuration.
19
- *
20
- * The AI Engine provides utilities for creating and running conversational workflows
21
- * with large language models, specifically OpenAI GPT models.
22
- *
23
- * @returns An AIEngine instance.
24
- *
25
- * @example
26
- * ```ts
27
- * const engine = createAIEngine({
28
- * logger: customLogger,
29
- * basePath: '/path/to/prompts'
30
- * });
31
- *
32
- * const workflow = await engine.createWorkflow(
33
- * engine.createStep({
34
- * name: 'generate-response',
35
- * prompt: engine.loadFile('prompts/response.txt'),
36
- * execute: (response) => conversation.setProposedReply(response)
37
- * })
38
- * );
39
- *
40
- * const reply = await workflow.run(conversation);
41
- * ```
42
- */
43
- function createAIEngine(cfg = {}) {
44
- const logger = cfg.logger || globalThis.console;
45
- const basePath = cfg.basePath || process.cwd();
46
- const tokenStorage = cfg.tokenStorage || {
47
- async getToken() {
48
- if (process.env.OPENAI_API_KEY) {
49
- return process.env.OPENAI_API_KEY;
50
- }
51
- throw new Error('OpenAI API key is not set');
15
+ const tracer_1 = require("./bosun/tracer");
16
+ const zod_to_json_schema_1 = require("zod-to-json-schema");
17
+ /**
18
+ * Creates an AI Engine with the given configuration.
19
+ *
20
+ * The AI Engine provides utilities for creating and running conversational workflows
21
+ * with large language models, specifically OpenAI GPT models.
22
+ *
23
+ * @returns An AIEngine instance.
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * const engine = createAIEngine({
28
+ * logger: customLogger,
29
+ * basePath: '/path/to/prompts'
30
+ * });
31
+ *
32
+ * const workflow = await engine.createWorkflow(
33
+ * engine.createStep({
34
+ * name: 'generate-response',
35
+ * prompt: engine.loadFile('prompts/response.txt'),
36
+ * execute: (response) => conversation.setProposedReply(response)
37
+ * })
38
+ * );
39
+ *
40
+ * const reply = await workflow.run(conversation);
41
+ * ```
42
+ */
43
+ function createAIEngine(cfg = {}) {
44
+ const stepTracer = cfg.stepTracer || undefined;
45
+ const logger = cfg.logger || globalThis.console;
46
+ const tracer = cfg.tracer || (0, tracer_1.createConsoleTracer)(logger);
47
+ let apiKey = null;
48
+ const tokenStorage = cfg.tokenStorage || {
49
+ async getToken() {
50
+ if (process.env.OPENAI_API_KEY) {
51
+ return process.env.OPENAI_API_KEY;
52
+ }
53
+ throw new Error('OpenAI API key is not set');
54
+ },
55
+ };
56
+ function createWorkflow({ onError }) {
57
+ let shouldRun = true;
58
+ let currentStep = 0;
59
+ let beforeEachCallback = async () => Promise.resolve(null);
60
+ const attempts = new Map();
61
+ const steps = [];
62
+ return {
63
+ terminate: () => {
64
+ logger.debug('AI Engine: Terminating conversation...');
65
+ shouldRun = false;
52
66
  },
53
- };
54
- function createStep(step) {
55
- return step;
56
- }
57
- async function createWorkflow(...steps) {
58
- const apiKey = await tokenStorage.getToken();
59
- let shouldRun = true;
60
- let currentStep = 0;
61
- let beforeEachCallback = async () => Promise.resolve(null);
62
- const attempts = new Map();
63
- const trace = {
64
- steps: steps.reduce((acc, step) => {
65
- acc[step.name] = {};
66
- return acc;
67
- }, {})
68
- };
69
- return {
70
- terminate: () => {
71
- logger.debug('AI Engine: Terminating conversation...');
72
- shouldRun = false;
73
- },
74
- run: async (messages) => {
75
- for (; currentStep < steps.length; currentStep++) {
76
- await beforeEachCallback();
77
- const step = steps[currentStep];
78
- if (!shouldRun) {
79
- break;
80
- }
81
- if (!step.runIf || (await step.runIf(messages))) {
82
- const action = (0, action_1.makeAction)(cfg.sendAction, 'AI', step.name);
83
- await action('started');
84
- logger.debug(`AI Engine: Step: ${step.name}`);
85
- if ('prompt' in step) {
86
- const stepTrace = await runStep(step, messages);
87
- trace.steps[step.name] = stepTrace;
88
- }
89
- else {
90
- await runDumbStep(step, messages);
91
- }
92
- await action('completed');
93
- }
94
- }
95
- return {
96
- reply: shouldRun ? messages.getProposedReply() : null,
97
- trace
98
- };
99
- },
100
- rewindTo: (step) => {
101
- const index = steps.indexOf(step);
102
- if (index === -1) {
103
- throw new Error(`Step ${step.name} not found`);
104
- }
105
- if (index > currentStep) {
106
- throw new Error(`Cannot rewind to a step ahead of the current step`);
107
- }
108
- currentStep = index - 1; // -1 because it will be incremented in the loop definition
109
- },
110
- beforeEach(callback) {
111
- beforeEachCallback = callback;
112
- },
113
- };
114
- async function runStep(step, messages) {
115
- if (!apiKey) {
116
- throw new Error('OpenAI API key is not set');
117
- }
118
- const stepTrace = {};
119
- try {
120
- stepTrace.receivedContext = step.context;
121
- let response = null;
122
- let prompt = typeof step.prompt === 'string' ? step.prompt : await step.prompt.content();
123
- stepTrace.receivedPrompt = prompt;
124
- logger.debug('AI Engine: context', step.context);
125
- logger.debug('AI Engine: messages', messages.toString({ ignoreAddedMessages: step.ignoreAddedMessages }));
126
- prompt = renderPrompt(prompt, step.context);
127
- stepTrace.renderedPrompt = prompt;
128
- const stringifiedMessages = messages.toString({ ignoreAddedMessages: step.ignoreAddedMessages });
129
- stepTrace.stringifiedConversation = stringifiedMessages;
130
- response = await runLLM(apiKey, prompt, stringifiedMessages, step.json, step.model);
131
- if (!response) {
132
- throw new Error('No response from OpenAI');
67
+ run: async (messages, ctx) => {
68
+ for (; currentStep < steps.length; currentStep++) {
69
+ await beforeEachCallback();
70
+ const step = steps[currentStep];
71
+ if (!shouldRun) {
72
+ logger.debug('AI Engine: run terminated');
73
+ break;
133
74
  }
134
- logger.debug(`AI Engine: response: ${response}`);
135
- if (typeof step.shouldExecute === 'function') {
136
- if (await step.shouldExecute(response)) {
137
- logger.debug(`AI Engine: executing`);
138
- checkAttempts(step);
139
- await step.execute(response);
75
+ if (!step.runIf || (await step.runIf(messages, ctx))) {
76
+ const action = (0, action_1.makeAction)(cfg.sendAction, 'AI', step.name);
77
+ await action('started');
78
+ logger.debug(`AI Engine: Step: ${step.name}`);
79
+ if ('prompt' in step) {
80
+ await runStep(step, messages, ctx, onError);
140
81
  }
141
82
  else {
142
- resetAttempts(step);
143
- logger.debug(`AI Engine: skipping`);
83
+ await runProgrammaticStep(step, messages, ctx);
144
84
  }
85
+ await action('completed');
145
86
  }
146
- else {
147
- logger.debug(`AI Engine: replying`);
148
- await step.execute(response);
149
- }
150
- return stepTrace;
151
87
  }
152
- catch (error) {
153
- // FIXME: this doesn't terminate the workflow
154
- await step.onError(error.message);
155
- shouldRun = false;
156
- return stepTrace;
88
+ currentStep = 0;
89
+ return shouldRun ? messages.getProposedReply() : null;
90
+ },
91
+ rewindTo: (step) => {
92
+ const index = steps.indexOf(step);
93
+ if (index === -1) {
94
+ throw new Error(`Step ${step.name} not found`);
157
95
  }
158
- }
159
- async function runDumbStep(step, messages) {
160
- try {
161
- if (!step.runIf || (await step.runIf(messages))) {
162
- await step.execute();
163
- }
96
+ if (index > currentStep) {
97
+ throw new Error(`Cannot rewind to a step ahead of the current step`);
164
98
  }
165
- catch (error) {
166
- console.error(`AI Engine: error in dumb step ${step.name}: ${error.message}`);
167
- await step.onError(error.message);
168
- shouldRun = false;
99
+ currentStep = index - 1; // -1 because it will be incremented in the loop definition
100
+ },
101
+ beforeEach(callback) {
102
+ beforeEachCallback = callback;
103
+ },
104
+ addStep(step) {
105
+ if ('prompt' in step) {
106
+ tracer.addStep({
107
+ name: step.name,
108
+ prompt: (0, tracer_1.stdPrompt)(step.prompt),
109
+ type: 'text',
110
+ schema: 'schema' in step ? step.schema : undefined,
111
+ });
169
112
  }
113
+ steps.push(step);
114
+ },
115
+ };
116
+ async function runStep(step, conversation, ctx, onError) {
117
+ if (!apiKey) {
118
+ apiKey = await tokenStorage.getToken();
170
119
  }
171
- function checkAttempts(step) {
172
- if (step.maxAttempts) {
173
- if (!attempts.has(step)) {
174
- attempts.set(step, 0);
120
+ if (!apiKey) {
121
+ throw new Error('LLM API key is not provided');
122
+ }
123
+ const stepTrace = {
124
+ name: step.name,
125
+ model: step.model,
126
+ schema: 'schema' in step
127
+ ? step.schema instanceof zod_1.ZodSchema
128
+ ? step.schema
129
+ : undefined
130
+ : undefined,
131
+ };
132
+ try {
133
+ stepTrace.receivedContext = ctx;
134
+ let response = null;
135
+ let prompt = typeof step.prompt === 'string' ? step.prompt : await step.prompt.content();
136
+ stepTrace.receivedPrompt = prompt;
137
+ logger.debug('AI Engine: context', ctx);
138
+ logger.debug('AI Engine: messages', conversation.toString({ ignoreAddedMessages: step.ignoreAddedMessages }));
139
+ prompt = renderPrompt(prompt, ctx);
140
+ stepTrace.renderedPrompt = prompt;
141
+ const stringifiedMessages = conversation.toString({
142
+ ignoreAddedMessages: step.ignoreAddedMessages,
143
+ });
144
+ stepTrace.stringifiedConversation = stringifiedMessages;
145
+ stepTracer?.addStepTrace(stepTrace);
146
+ if ('schema' in step) {
147
+ response = await runLLM(apiKey, prompt, stringifiedMessages, step.schema, step.model);
148
+ response = step.schema.parse(JSON.parse(response));
149
+ }
150
+ else {
151
+ response = await runLLM(apiKey, prompt, stringifiedMessages, undefined, step.model);
152
+ }
153
+ if (!response) {
154
+ throw new Error('No response from OpenAI');
155
+ }
156
+ logger.debug(`AI Engine: response:`, response);
157
+ if (typeof step.shouldExecute === 'function') {
158
+ if (await step.shouldExecute(response, ctx)) {
159
+ logger.debug(`AI Engine: executing`);
160
+ checkAttempts(step);
161
+ await step.execute(response, conversation, ctx);
175
162
  }
176
- attempts.set(step, attempts.get(step) + 1);
177
- if (attempts.get(step) > step.maxAttempts) {
178
- throw new Error(`Max attempts reached for step ${step.name}`);
163
+ else {
164
+ resetAttempts(step);
165
+ logger.debug(`AI Engine: skipping`);
179
166
  }
180
167
  }
168
+ else {
169
+ logger.debug(`AI Engine: replying`);
170
+ await step.execute(response, conversation, ctx);
171
+ }
181
172
  }
182
- function resetAttempts(step) {
183
- attempts.set(step, 0);
173
+ catch (error) {
174
+ await (step.onError
175
+ ? step.onError(error.message, ctx)
176
+ : onError(error.message, ctx));
177
+ // FIXME: this doesn't terminate the workflow
178
+ stepTracer?.addStepTrace(stepTrace);
179
+ shouldRun = false;
184
180
  }
185
181
  }
186
- async function runLLM(apiKey, systemPrompt, messages, json, model = 'gpt-4o-2024-08-06') {
187
- logger.debug('AI Engine: model:', model);
188
- logger.debug('----------- RENDERED PROMPT ---------------');
189
- logger.debug(systemPrompt);
190
- logger.debug('-------------------------------------------');
191
- if (apiKey === '__TESTING__') {
192
- await (0, core_1.sleep)(100);
193
- if (typeof json === 'boolean') {
194
- return json ? JSON.stringify({ message: 'canned response', reasons: [] }) : 'canned response';
182
+ async function runProgrammaticStep(step, messages, ctx) {
183
+ try {
184
+ if (!step.runIf || (await step.runIf(messages, ctx))) {
185
+ await step.execute(messages, ctx);
195
186
  }
196
- return JSON.stringify({ message: 'canned response', reasons: [] });
197
187
  }
198
- const client = new openai_1.default({ apiKey });
199
- const response = await client.chat.completions.create({
200
- messages: [
201
- { role: 'system', content: systemPrompt },
202
- { role: 'user', content: messages },
203
- ],
204
- ...getOpenAiOptions(model, json),
205
- });
206
- if (!response.choices[0].message.content) {
207
- throw new Error('No response from OpenAI');
188
+ catch (error) {
189
+ console.error(`AI Engine: error in dumb step ${step.name}: ${error.message}`);
190
+ await (step.onError
191
+ ? step.onError(error.message, ctx)
192
+ : onError(error.message, ctx));
193
+ shouldRun = false;
208
194
  }
209
- return response.choices[0].message.content;
210
195
  }
211
- function loadFile(path) {
212
- // NOTE: there probably will be S3 loading stuff here
213
- return {
214
- content: async () => {
215
- logger.debug('AI Engine: loading prompt:', path);
216
- return fs_1.default.promises.readFile((0, path_1.join)(basePath, path), 'utf-8');
217
- },
218
- };
219
- }
220
- return {
221
- createWorkflow: createWorkflow,
222
- createStep,
223
- loadFile,
224
- createConversation,
225
- renderPrompt
226
- };
227
- }
228
- AIEngine.createAIEngine = createAIEngine;
229
- function getOpenAiOptions(model, json) {
230
- const options = {
231
- model,
232
- };
233
- const isReasoningModel = ['o3-', 'o1-', 'o1-preview-'].some((m) => model.startsWith(m));
234
- if (isReasoningModel) {
235
- if (!model.startsWith('o1-preview-')) {
236
- options.reasoning_effort = 'high';
196
+ function checkAttempts(step) {
197
+ if (step.maxAttempts) {
198
+ if (!attempts.has(step)) {
199
+ attempts.set(step, 0);
200
+ }
201
+ attempts.set(step, attempts.get(step) + 1);
202
+ if (attempts.get(step) > step.maxAttempts) {
203
+ throw new Error(`Max attempts reached for step ${step.name}`);
204
+ }
237
205
  }
238
206
  }
239
- else {
240
- options.temperature = 0.1;
207
+ function resetAttempts(step) {
208
+ attempts.set(step, 0);
241
209
  }
242
- if (typeof json !== 'boolean') {
243
- options.response_format = {
244
- type: 'json_schema',
245
- json_schema: {
246
- name: 'detector_response',
247
- schema: (0, zod_to_json_schema_1.zodToJsonSchema)(json),
248
- },
249
- };
210
+ }
211
+ async function runLLM(apiKey, systemPrompt, messages, schema, model = 'gpt-4o-2024-08-06') {
212
+ logger.debug('AI Engine: model:', model);
213
+ logger.debug('----------- RENDERED PROMPT ---------------');
214
+ logger.debug(systemPrompt);
215
+ logger.debug('-------------------------------------------');
216
+ if (apiKey === '__TESTING__') {
217
+ await (0, core_1.sleep)(100);
218
+ if (!schema) {
219
+ return 'canned response';
220
+ }
221
+ return JSON.stringify({ message: 'canned response', reasons: [] });
250
222
  }
251
- else if (json) {
252
- options.response_format = { type: 'json_object' };
223
+ const client = new openai_1.default({ apiKey });
224
+ const response = await client.chat.completions.create({
225
+ messages: [
226
+ { role: 'system', content: systemPrompt },
227
+ { role: 'user', content: messages },
228
+ ],
229
+ ...getOpenAiOptions(model, schema),
230
+ });
231
+ if (!response.choices[0].message.content) {
232
+ throw new Error('No response from OpenAI');
253
233
  }
254
- else {
255
- options.response_format = { type: 'text' };
234
+ return response.choices[0].message.content;
235
+ }
236
+ return {
237
+ createWorkflow,
238
+ createConversation,
239
+ renderPrompt,
240
+ getStepBuilder() {
241
+ return (step) => step;
242
+ },
243
+ };
244
+ }
245
+ function getOpenAiOptions(model, schema) {
246
+ const options = {
247
+ model,
248
+ };
249
+ const isReasoningModel = ['o3-', 'o1-', 'o1-preview-'].some((m) => model.startsWith(m));
250
+ if (isReasoningModel) {
251
+ if (!model.startsWith('o1-preview-')) {
252
+ options.reasoning_effort = 'high';
256
253
  }
257
- return options;
258
254
  }
259
- function renderPrompt(prompt, context) {
260
- nunjucks_1.default.configure({
261
- autoescape: false,
262
- trimBlocks: true,
263
- lstripBlocks: true,
264
- });
265
- return nunjucks_1.default.renderString(prompt, context || {});
255
+ else {
256
+ options.temperature = 0.1;
266
257
  }
267
- function createConversation(initialMessages = []) {
268
- const messages = initialMessages.map((msg) => ({
269
- ...msg,
270
- isAddedMessage: false,
271
- formatter: undefined
272
- }));
273
- const names = {
274
- agent: 'Agent',
275
- user: 'User',
276
- system: 'System',
277
- };
278
- let defaultFormatter = (message) => `${names[message.sender]}: ${message.text}`;
279
- let proposedFormatter = (message) => `Proposed reply: ${message}`;
280
- let proposedReply = null;
281
- return {
282
- toString: (options) => {
283
- return messages
284
- .filter((msg) => !options?.ignoreAddedMessages || !msg.isAddedMessage)
285
- .map((msg) => {
286
- return msg.formatter ? msg.formatter(msg) : defaultFormatter(msg);
287
- })
288
- .filter((msg) => msg !== null)
289
- .join('\n') +
290
- (proposedReply ? `\n${proposedFormatter(proposedReply)}` : '');
291
- },
292
- addMessage: (message, opts) => {
293
- messages.push({
294
- ...message,
295
- isAddedMessage: true,
296
- formatter: opts?.formatter ?? defaultFormatter,
297
- });
298
- },
299
- setDefaultFormatter: (formatter) => {
300
- defaultFormatter = formatter;
301
- },
302
- setProposedMessageFormatter: (formatter) => {
303
- proposedFormatter = formatter;
304
- },
305
- setProposedReply: (message) => (proposedReply = message),
306
- getProposedReply: () => proposedReply,
307
- getHistory: () => messages,
308
- setUserName: (name) => {
309
- names.user = name;
258
+ if (schema) {
259
+ options.response_format = {
260
+ type: 'json_schema',
261
+ json_schema: {
262
+ name: 'detector_response',
263
+ schema: (0, zod_to_json_schema_1.zodToJsonSchema)(schema),
310
264
  },
311
- setAgentName: (name) => {
312
- names.agent = name;
313
- }
314
265
  };
315
266
  }
316
- AIEngine.createConversation = createConversation;
317
- })(AIEngine || (exports.AIEngine = AIEngine = {}));
267
+ else {
268
+ options.response_format = { type: 'text' };
269
+ }
270
+ return options;
271
+ }
272
+ function renderPrompt(prompt, context) {
273
+ nunjucks_1.default.configure({
274
+ autoescape: false,
275
+ trimBlocks: true,
276
+ lstripBlocks: true,
277
+ });
278
+ return nunjucks_1.default.renderString(prompt, context || {});
279
+ }
280
+ function createConversation(initialMessages = []) {
281
+ const messages = initialMessages.map((msg) => ({
282
+ ...msg,
283
+ isAddedMessage: false,
284
+ formatter: undefined,
285
+ }));
286
+ const names = {
287
+ agent: 'Agent',
288
+ user: 'User',
289
+ system: 'System',
290
+ };
291
+ let defaultFormatter = (message) => `${names[message.sender]}: ${message.text}`;
292
+ let proposedFormatter = (message) => `Proposed reply: ${message}`;
293
+ let proposedReply = null;
294
+ return {
295
+ toString: (options) => {
296
+ return (messages
297
+ .filter((msg) => !options?.ignoreAddedMessages || !msg.isAddedMessage)
298
+ .map((msg) => {
299
+ return msg.formatter ? msg.formatter(msg) : defaultFormatter(msg);
300
+ })
301
+ .filter((msg) => msg !== null)
302
+ .join('\n') + (proposedReply ? `\n${proposedFormatter(proposedReply)}` : ''));
303
+ },
304
+ addMessage: (message, opts) => {
305
+ messages.push({
306
+ ...message,
307
+ isAddedMessage: true,
308
+ formatter: opts?.formatter ?? defaultFormatter,
309
+ });
310
+ },
311
+ setDefaultFormatter: (formatter) => {
312
+ defaultFormatter = formatter;
313
+ },
314
+ setProposedMessageFormatter: (formatter) => {
315
+ proposedFormatter = formatter;
316
+ },
317
+ setProposedReply: (message) => (proposedReply = message),
318
+ getProposedReply: () => proposedReply,
319
+ getHistory: () => messages,
320
+ setUserName: (name) => {
321
+ names.user = name;
322
+ },
323
+ setAgentName: (name) => {
324
+ names.agent = name;
325
+ },
326
+ };
327
+ }
328
+ function getStepBuilder() {
329
+ return (step) => step;
330
+ }