@recombine-ai/engine 0.5.0 → 0.7.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","sourceRoot":"","sources":["../../src/lib/ai.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,KAAK,CAAA;AAE/B,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AACrC,OAAO,EAAc,UAAU,EAAE,MAAM,gBAAgB,CAAA;AAGvD,yBAAiB,QAAQ,CAAC;IACtB;;OAEG;IACH,MAAM,MAAM,UAAU,GAChB,oBAAoB,GACpB,uBAAuB,GACvB,mBAAmB,GACnB,eAAe,GACf,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;IAEnB,MAAM,WAAW,gBAAgB;QAC7B,8BAA8B;QAC9B,IAAI,EAAE,MAAM,CAAA;QAEZ,kDAAkD;QAClD,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAE9D,0BAA0B;QAC1B,OAAO,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;QAE/B,6EAA6E;QAC7E,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KAC/C;IAED,MAAM,WAAW,OAAO;QACpB,8BAA8B;QAC9B,IAAI,EAAE,MAAM,CAAA;QAEZ,kDAAkD;QAClD,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAE9D,qCAAqC;QACrC,KAAK,CAAC,EAAE,UAAU,CAAA;QAElB;;;WAGG;QACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;QAErB;;;;;WAKG;QACH,IAAI,EAAE,OAAO,GAAG,SAAS,CAAA;QAEzB,8EAA8E;QAC9E,gBAAgB,CAAC,EAAE,OAAO,CAAA;QAE1B;;;;;;;WAOG;QACH,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;QAEjC;;;;;;;;;;;;;;WAcG;QACH,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;QAE5C;;;;YAII;QACJ,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAE7D;;;;WAIG;QACH,WAAW,CAAC,EAAE,MAAM,CAAA;QAEpB,6FAA6F;QAC7F,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;KAC/C;IAED;;OAEG;IACH,MAAM,MAAM,SAAS,GAAG;QACpB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,uBAAuB,CAAC,EAAE,MAAM,CAAA;KACnC,CAAA;IAED;;OAEG;IACH,MAAM,WAAW,QAAQ;QACrB;;WAEG;QACH,SAAS,EAAE,MAAM,IAAI,CAAA;QAErB;;;;;WAKG;QACH,GAAG,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,CAAC;YAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;YAAC,KAAK,EAAE;gBAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;aAAE,CAAA;SAAE,CAAC,CAAA;QAEhH;;;WAGG;QACH,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,GAAG,gBAAgB,KAAK,IAAI,CAAA;QAEpD;;;WAGG;QACH,UAAU,EAAE,CAAC,QAAQ,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;KACzD;IAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkDG;IACH,MAAM,WAAW,QAAQ;QACrB;;;;WAIG;QACH,cAAc,EAAE,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,OAAO,GAAG,gBAAgB,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;QAEnF;;;;WAIG;QACH,UAAU,EAAE,CAAC,CAAC,SAAS,OAAO,GAAG,gBAAgB,EAAE,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;QAEjE;;;;WAIG;QACH,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;QAEjC;;;;WAIG;QACH,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,KAAK,YAAY,CAAC;QAE3D;;;;;WAKG;QACH,YAAY,EAAE,OAAO,YAAY,CAAA;KACpC;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,MAAM,WAAW,YAAY;QACzB;;;WAGG;QACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;QAE/B;;;WAGG;QACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;QAEhC;;;;WAIG;QACH,QAAQ,EAAE,CAAC,gBAAgB,CAAC,EAAE,OAAO,KAAK,MAAM,CAAA;QAEhD;;;;;;;;;;;;WAYG;QACH,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,KAAK,IAAI,CAAA;QAEjF;;;;WAIG;QACH,UAAU,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;QAE9D;;;WAGG;QACH,4BAA4B,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,KAAK,IAAI,CAAA;QAE/E;;;WAGG;QACH,2BAA2B,EAAE,CAAC,SAAS,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,KAAK,IAAI,CAAA;QAE7E;;;WAGG;QACH,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAA;QAE3C;;;WAGG;QACH,gBAAgB,EAAE,MAAM,MAAM,GAAG,IAAI,CAAA;QAErC;;;WAGG;QACH,UAAU,EAAE,MAAM,OAAO,EAAE,CAAA;KAC9B;IAED;;;OAGG;IACH,MAAM,WAAW,OAAO;QACpB,iGAAiG;QACjG,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;QACnC,sCAAsC;QACtC,IAAI,EAAE,MAAM,CAAA;QACZ,2DAA2D;QAC3D,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB,SAAS,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,CAAA;KAC3C;IAED,MAAM,WAAW,IAAI;QACjB,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;KACjC;IAED;;OAEG;IACH,MAAM,WAAW,YAAY;QACzB;;;;WAIG;QACH,YAAY,CAAC,EAAE;YAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA;SAAE,CAAA;QACzD;;WAEG;QACH,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB;;WAEG;QACH,MAAM,CAAC,EAAE,MAAM,CAAA;QACf;;WAEG;QACH,UAAU,CAAC,EAAE,UAAU,CAAA;KAC1B;IAED;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACH,MAAM,UAAU,cAAc,CAAC,GAAG,GAAE,YAAiB,GAAG,QAAQ,CAqQ/D;IAgCD,SAAS,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAO/E;;CACJ"}
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,308 +3,326 @@ 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
- function getConversation(messages = []) {
58
- let defaultDirectivesFormatter = (message) => `${message.sender}: ${message.text}`;
59
- let proposedFormatter = (message) => `Proposed reply: ${message}`;
60
- let proposedReply = null;
61
- const names = {
62
- agent: 'Agent',
63
- user: 'User',
64
- system: 'System',
65
- };
66
- return {
67
- toString: (ignoreDirectives = false) => messages
68
- .map((msg) => {
69
- if (msg.sender === 'system') {
70
- logger.debug('formatter', msg.formatter);
71
- return ignoreDirectives ? null : (msg.formatter ? msg.formatter(msg) : defaultDirectivesFormatter(msg));
72
- }
73
- return `${names[msg.sender]}: ${msg.text}`;
74
- })
75
- .filter((msg) => msg !== null)
76
- .join('\n') +
77
- (proposedReply ? `\n${proposedFormatter(proposedReply)}` : ''),
78
- addMessage: (sender, text) => messages.push({ sender, text }),
79
- addDirective: (message, formatter) => {
80
- logger.debug(`AI Engine: add directive: ${message}`);
81
- messages.push({ sender: 'system', text: message, formatter });
82
- },
83
- setDefaultDirectiveFormatter: (formatter) => {
84
- defaultDirectivesFormatter = formatter;
85
- },
86
- setProposedMessageFormatter: (formatter) => {
87
- proposedFormatter = formatter;
88
- },
89
- setProposedReply: (message) => (proposedReply = message),
90
- getProposedReply: () => proposedReply,
91
- getHistory: () => messages,
92
- setUserName: (name) => {
93
- names.user = name;
94
- },
95
- setAgentName: (name) => {
96
- names.agent = name;
97
- },
98
- };
99
- }
100
- async function createWorkflow(...steps) {
101
- const apiKey = await tokenStorage.getToken();
102
- let shouldRun = true;
103
- let currentStep = 0;
104
- let beforeEachCallback = async () => Promise.resolve(null);
105
- const attempts = new Map();
106
- const trace = {
107
- steps: steps.reduce((acc, step) => {
108
- acc[step.name] = {};
109
- return acc;
110
- }, {})
111
- };
112
- return {
113
- terminate: () => {
114
- logger.debug('AI Engine: Terminating conversation...');
115
- shouldRun = false;
116
- },
117
- run: async (messages) => {
118
- for (; currentStep < steps.length; currentStep++) {
119
- await beforeEachCallback();
120
- const step = steps[currentStep];
121
- if (!shouldRun) {
122
- break;
123
- }
124
- if (!step.runIf || (await step.runIf(messages))) {
125
- const action = (0, action_1.makeAction)(cfg.sendAction, 'AI', step.name);
126
- await action('started');
127
- logger.debug(`AI Engine: Step: ${step.name}`);
128
- if ('prompt' in step) {
129
- const stepTrace = await runStep(step, messages);
130
- trace.steps[step.name] = stepTrace;
131
- }
132
- else {
133
- await runDumbStep(step, messages);
134
- }
135
- await action('completed');
136
- }
67
+ run: async (messages, ctx) => {
68
+ for (; currentStep < steps.length; currentStep++) {
69
+ await beforeEachCallback();
70
+ const step = steps[currentStep];
71
+ if (!shouldRun) {
72
+ break;
137
73
  }
138
- return {
139
- reply: shouldRun ? messages.getProposedReply() : null,
140
- trace
141
- };
142
- },
143
- rewindTo: (step) => {
144
- const index = steps.indexOf(step);
145
- if (index === -1) {
146
- throw new Error(`Step ${step.name} not found`);
147
- }
148
- if (index > currentStep) {
149
- throw new Error(`Cannot rewind to a step ahead of the current step`);
150
- }
151
- currentStep = index - 1; // -1 because it will be incremented in the loop definition
152
- },
153
- beforeEach(callback) {
154
- beforeEachCallback = callback;
155
- },
156
- };
157
- async function runStep(step, messages) {
158
- if (!apiKey) {
159
- throw new Error('OpenAI API key is not set');
160
- }
161
- const stepTrace = {};
162
- try {
163
- stepTrace.receivedContext = step.context;
164
- let response = null;
165
- let prompt = typeof step.prompt === 'string' ? step.prompt : await step.prompt.content();
166
- stepTrace.receivedPrompt = prompt;
167
- logger.debug('AI Engine: context', step.context);
168
- logger.debug('AI Engine: messages', messages.toString(step.ignoreDirectives || false));
169
- prompt = renderPrompt(prompt, step.context);
170
- stepTrace.renderedPrompt = prompt;
171
- const stringifiedMessages = messages.toString(step.ignoreDirectives || false);
172
- stepTrace.stringifiedConversation = stringifiedMessages;
173
- response = await runLLM(apiKey, prompt, stringifiedMessages, step.json, step.model);
174
- if (!response) {
175
- throw new Error('No response from OpenAI');
176
- }
177
- logger.debug(`AI Engine: response: ${response}`);
178
- if (typeof step.shouldExecute === 'function') {
179
- if (await step.shouldExecute(response)) {
180
- logger.debug(`AI Engine: executing`);
181
- checkAttempts(step);
182
- await step.execute(response);
74
+ if (!step.runIf || (await step.runIf(messages, ctx))) {
75
+ const action = (0, action_1.makeAction)(cfg.sendAction, 'AI', step.name);
76
+ await action('started');
77
+ logger.debug(`AI Engine: Step: ${step.name}`);
78
+ if ('prompt' in step) {
79
+ await runStep(step, messages, ctx, onError);
183
80
  }
184
81
  else {
185
- resetAttempts(step);
186
- logger.debug(`AI Engine: skipping`);
82
+ await runProgrammaticStep(step, messages, ctx);
187
83
  }
84
+ await action('completed');
188
85
  }
189
- else {
190
- logger.debug(`AI Engine: replying`);
191
- await step.execute(response);
192
- }
193
- return stepTrace;
194
86
  }
195
- catch (error) {
196
- // FIXME: this doesn't terminate the workflow
197
- await step.onError(error.message);
198
- shouldRun = false;
199
- return stepTrace;
87
+ return shouldRun ? messages.getProposedReply() : null;
88
+ },
89
+ rewindTo: (step) => {
90
+ const index = steps.indexOf(step);
91
+ if (index === -1) {
92
+ throw new Error(`Step ${step.name} not found`);
200
93
  }
201
- }
202
- async function runDumbStep(step, messages) {
203
- try {
204
- if (!step.runIf || (await step.runIf(messages))) {
205
- await step.execute();
206
- }
94
+ if (index > currentStep) {
95
+ throw new Error(`Cannot rewind to a step ahead of the current step`);
207
96
  }
208
- catch (error) {
209
- console.error(`AI Engine: error in dumb step ${step.name}: ${error.message}`);
210
- await step.onError(error.message);
211
- shouldRun = false;
97
+ currentStep = index - 1; // -1 because it will be incremented in the loop definition
98
+ },
99
+ beforeEach(callback) {
100
+ beforeEachCallback = callback;
101
+ },
102
+ addStep(step) {
103
+ if ('prompt' in step) {
104
+ tracer.addStep({
105
+ name: step.name,
106
+ prompt: (0, tracer_1.stdPrompt)(step.prompt),
107
+ type: 'text',
108
+ schema: 'schema' in step ? step.schema : undefined,
109
+ });
212
110
  }
111
+ steps.push(step);
112
+ },
113
+ };
114
+ async function runStep(step, conversation, ctx, onError) {
115
+ if (!apiKey) {
116
+ apiKey = await tokenStorage.getToken();
213
117
  }
214
- function checkAttempts(step) {
215
- if (step.maxAttempts) {
216
- if (!attempts.has(step)) {
217
- attempts.set(step, 0);
118
+ if (!apiKey) {
119
+ throw new Error('LLM API key is not provided');
120
+ }
121
+ const stepTrace = {
122
+ name: step.name,
123
+ model: step.model,
124
+ schema: 'schema' in step
125
+ ? step.schema instanceof zod_1.ZodSchema
126
+ ? step.schema
127
+ : undefined
128
+ : undefined,
129
+ };
130
+ try {
131
+ stepTrace.receivedContext = ctx;
132
+ let response = null;
133
+ let prompt = typeof step.prompt === 'string' ? step.prompt : await step.prompt.content();
134
+ stepTrace.receivedPrompt = prompt;
135
+ logger.debug('AI Engine: context', ctx);
136
+ logger.debug('AI Engine: messages', conversation.toString({ ignoreAddedMessages: step.ignoreAddedMessages }));
137
+ prompt = renderPrompt(prompt, ctx);
138
+ stepTrace.renderedPrompt = prompt;
139
+ const stringifiedMessages = conversation.toString({
140
+ ignoreAddedMessages: step.ignoreAddedMessages,
141
+ });
142
+ stepTrace.stringifiedConversation = stringifiedMessages;
143
+ stepTracer?.addStepTrace(stepTrace);
144
+ if ('schema' in step) {
145
+ response = await runLLM(apiKey, prompt, stringifiedMessages, step.schema, step.model);
146
+ response = step.schema.parse(JSON.parse(response));
147
+ }
148
+ else {
149
+ response = await runLLM(apiKey, prompt, stringifiedMessages, undefined, step.model);
150
+ }
151
+ if (!response) {
152
+ throw new Error('No response from OpenAI');
153
+ }
154
+ logger.debug(`AI Engine: response: ${response}`);
155
+ if (typeof step.shouldExecute === 'function') {
156
+ if (await step.shouldExecute(response, ctx)) {
157
+ logger.debug(`AI Engine: executing`);
158
+ checkAttempts(step);
159
+ await step.execute(response, conversation, ctx);
218
160
  }
219
- attempts.set(step, attempts.get(step) + 1);
220
- if (attempts.get(step) > step.maxAttempts) {
221
- throw new Error(`Max attempts reached for step ${step.name}`);
161
+ else {
162
+ resetAttempts(step);
163
+ logger.debug(`AI Engine: skipping`);
222
164
  }
223
165
  }
166
+ else {
167
+ logger.debug(`AI Engine: replying`);
168
+ await step.execute(response, conversation, ctx);
169
+ }
224
170
  }
225
- function resetAttempts(step) {
226
- attempts.set(step, 0);
171
+ catch (error) {
172
+ await (step.onError
173
+ ? step.onError(error.message, ctx)
174
+ : onError(error.message, ctx));
175
+ // FIXME: this doesn't terminate the workflow
176
+ stepTracer?.addStepTrace(stepTrace);
177
+ shouldRun = false;
227
178
  }
228
179
  }
229
- async function runLLM(apiKey, systemPrompt, messages, json, model = 'gpt-4o-2024-08-06') {
230
- logger.debug('AI Engine: model:', model);
231
- logger.debug('----------- RENDERED PROMPT ---------------');
232
- logger.debug(systemPrompt);
233
- logger.debug('-------------------------------------------');
234
- if (apiKey === '__TESTING__') {
235
- await (0, core_1.sleep)(100);
236
- if (typeof json === 'boolean') {
237
- return json ? JSON.stringify({ message: 'canned response', reasons: [] }) : 'canned response';
180
+ async function runProgrammaticStep(step, messages, ctx) {
181
+ try {
182
+ if (!step.runIf || (await step.runIf(messages, ctx))) {
183
+ await step.execute(messages, ctx);
238
184
  }
239
- return JSON.stringify({ message: 'canned response', reasons: [] });
240
185
  }
241
- const client = new openai_1.default({ apiKey });
242
- const response = await client.chat.completions.create({
243
- messages: [
244
- { role: 'system', content: systemPrompt },
245
- { role: 'user', content: messages },
246
- ],
247
- ...getOpenAiOptions(model, json),
248
- });
249
- if (!response.choices[0].message.content) {
250
- throw new Error('No response from OpenAI');
186
+ catch (error) {
187
+ console.error(`AI Engine: error in dumb step ${step.name}: ${error.message}`);
188
+ await (step.onError
189
+ ? step.onError(error.message, ctx)
190
+ : onError(error.message, ctx));
191
+ shouldRun = false;
251
192
  }
252
- return response.choices[0].message.content;
253
- }
254
- function loadFile(path) {
255
- // NOTE: there probably will be S3 loading stuff here
256
- return {
257
- content: async () => {
258
- logger.debug('AI Engine: loading prompt:', path);
259
- return fs_1.default.promises.readFile((0, path_1.join)(basePath, path), 'utf-8');
260
- },
261
- };
262
193
  }
263
- return {
264
- createWorkflow: createWorkflow,
265
- createStep,
266
- loadFile,
267
- createConversation: getConversation,
268
- renderPrompt
269
- };
270
- }
271
- AIEngine.createAIEngine = createAIEngine;
272
- function getOpenAiOptions(model, json) {
273
- const options = {
274
- model,
275
- };
276
- const isReasoningModel = ['o3-', 'o1-', 'o1-preview-'].some((m) => model.startsWith(m));
277
- if (isReasoningModel) {
278
- if (!model.startsWith('o1-preview-')) {
279
- options.reasoning_effort = 'high';
194
+ function checkAttempts(step) {
195
+ if (step.maxAttempts) {
196
+ if (!attempts.has(step)) {
197
+ attempts.set(step, 0);
198
+ }
199
+ attempts.set(step, attempts.get(step) + 1);
200
+ if (attempts.get(step) > step.maxAttempts) {
201
+ throw new Error(`Max attempts reached for step ${step.name}`);
202
+ }
280
203
  }
281
204
  }
282
- else {
283
- options.temperature = 0.1;
205
+ function resetAttempts(step) {
206
+ attempts.set(step, 0);
284
207
  }
285
- if (typeof json !== 'boolean') {
286
- options.response_format = {
287
- type: 'json_schema',
288
- json_schema: {
289
- name: 'detector_response',
290
- schema: (0, zod_to_json_schema_1.zodToJsonSchema)(json),
291
- },
292
- };
208
+ }
209
+ async function runLLM(apiKey, systemPrompt, messages, schema, model = 'gpt-4o-2024-08-06') {
210
+ logger.debug('AI Engine: model:', model);
211
+ logger.debug('----------- RENDERED PROMPT ---------------');
212
+ logger.debug(systemPrompt);
213
+ logger.debug('-------------------------------------------');
214
+ if (apiKey === '__TESTING__') {
215
+ await (0, core_1.sleep)(100);
216
+ if (!schema) {
217
+ return 'canned response';
218
+ }
219
+ return JSON.stringify({ message: 'canned response', reasons: [] });
293
220
  }
294
- else if (json) {
295
- options.response_format = { type: 'json_object' };
221
+ const client = new openai_1.default({ apiKey });
222
+ const response = await client.chat.completions.create({
223
+ messages: [
224
+ { role: 'system', content: systemPrompt },
225
+ { role: 'user', content: messages },
226
+ ],
227
+ ...getOpenAiOptions(model, schema),
228
+ });
229
+ if (!response.choices[0].message.content) {
230
+ throw new Error('No response from OpenAI');
296
231
  }
297
- else {
298
- options.response_format = { type: 'text' };
232
+ return response.choices[0].message.content;
233
+ }
234
+ return {
235
+ createWorkflow,
236
+ createConversation,
237
+ renderPrompt,
238
+ getStepBuilder() {
239
+ return (step) => step;
240
+ },
241
+ };
242
+ }
243
+ function getOpenAiOptions(model, schema) {
244
+ const options = {
245
+ model,
246
+ };
247
+ const isReasoningModel = ['o3-', 'o1-', 'o1-preview-'].some((m) => model.startsWith(m));
248
+ if (isReasoningModel) {
249
+ if (!model.startsWith('o1-preview-')) {
250
+ options.reasoning_effort = 'high';
299
251
  }
300
- return options;
301
252
  }
302
- function renderPrompt(prompt, context) {
303
- nunjucks_1.default.configure({
304
- autoescape: false,
305
- trimBlocks: true,
306
- lstripBlocks: true,
307
- });
308
- return nunjucks_1.default.renderString(prompt, context || {});
253
+ else {
254
+ options.temperature = 0.1;
255
+ }
256
+ if (schema) {
257
+ options.response_format = {
258
+ type: 'json_schema',
259
+ json_schema: {
260
+ name: 'detector_response',
261
+ schema: (0, zod_to_json_schema_1.zodToJsonSchema)(schema),
262
+ },
263
+ };
264
+ }
265
+ else {
266
+ options.response_format = { type: 'text' };
309
267
  }
310
- })(AIEngine || (exports.AIEngine = AIEngine = {}));
268
+ return options;
269
+ }
270
+ function renderPrompt(prompt, context) {
271
+ nunjucks_1.default.configure({
272
+ autoescape: false,
273
+ trimBlocks: true,
274
+ lstripBlocks: true,
275
+ });
276
+ return nunjucks_1.default.renderString(prompt, context || {});
277
+ }
278
+ function createConversation(initialMessages = []) {
279
+ const messages = initialMessages.map((msg) => ({
280
+ ...msg,
281
+ isAddedMessage: false,
282
+ formatter: undefined,
283
+ }));
284
+ const names = {
285
+ agent: 'Agent',
286
+ user: 'User',
287
+ system: 'System',
288
+ };
289
+ let defaultFormatter = (message) => `${names[message.sender]}: ${message.text}`;
290
+ let proposedFormatter = (message) => `Proposed reply: ${message}`;
291
+ let proposedReply = null;
292
+ return {
293
+ toString: (options) => {
294
+ return (messages
295
+ .filter((msg) => !options?.ignoreAddedMessages || !msg.isAddedMessage)
296
+ .map((msg) => {
297
+ return msg.formatter ? msg.formatter(msg) : defaultFormatter(msg);
298
+ })
299
+ .filter((msg) => msg !== null)
300
+ .join('\n') + (proposedReply ? `\n${proposedFormatter(proposedReply)}` : ''));
301
+ },
302
+ addMessage: (message, opts) => {
303
+ messages.push({
304
+ ...message,
305
+ isAddedMessage: true,
306
+ formatter: opts?.formatter ?? defaultFormatter,
307
+ });
308
+ },
309
+ setDefaultFormatter: (formatter) => {
310
+ defaultFormatter = formatter;
311
+ },
312
+ setProposedMessageFormatter: (formatter) => {
313
+ proposedFormatter = formatter;
314
+ },
315
+ setProposedReply: (message) => (proposedReply = message),
316
+ getProposedReply: () => proposedReply,
317
+ getHistory: () => messages,
318
+ setUserName: (name) => {
319
+ names.user = name;
320
+ },
321
+ setAgentName: (name) => {
322
+ names.agent = name;
323
+ },
324
+ };
325
+ }
326
+ function getStepBuilder() {
327
+ return (step) => step;
328
+ }