@ekairos/story 1.6.3 → 1.8.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +72 -72
- package/dist/agent.js +478 -478
- package/dist/document-parser.d.ts +15 -15
- package/dist/document-parser.js +156 -156
- package/dist/engine.d.ts +21 -21
- package/dist/engine.js +35 -35
- package/dist/events.d.ts +27 -27
- package/dist/events.js +203 -203
- package/dist/index.d.ts +11 -11
- package/dist/index.js +50 -50
- package/dist/schema.d.ts +107 -107
- package/dist/schema.js +63 -63
- package/dist/service.d.ts +44 -44
- package/dist/service.js +202 -202
- package/dist/steps/ai.d.ts +42 -42
- package/dist/steps/ai.js +135 -135
- package/dist/steps/base.d.ts +13 -13
- package/dist/steps/base.js +36 -36
- package/dist/steps/index.d.ts +3 -3
- package/dist/steps/index.js +19 -19
- package/dist/steps/registry.d.ts +4 -4
- package/dist/steps/registry.js +28 -28
- package/dist/steps/sampleStep.d.ts.map +1 -1
- package/dist/steps/sampleStep.js.map +1 -1
- package/dist/steps-context.d.ts +11 -11
- package/dist/steps-context.js +19 -19
- package/dist/story.d.ts +49 -49
- package/dist/story.js +54 -54
- package/dist/storyEngine.d.ts +54 -54
- package/dist/storyEngine.js +50 -50
- package/dist/storyRunner.d.ts +7 -7
- package/dist/storyRunner.js +55 -55
- package/dist/workflows/sampleWorkflow.d.ts.map +1 -1
- package/dist/workflows/sampleWorkflow.js.map +1 -1
- package/package.json +1 -1
package/dist/agent.js
CHANGED
|
@@ -1,479 +1,479 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Agent = exports.Story = void 0;
|
|
4
|
-
const admin_1 = require("@instantdb/admin");
|
|
5
|
-
const ai_1 = require("ai");
|
|
6
|
-
const openai_1 = require("@ai-sdk/openai");
|
|
7
|
-
const zod_1 = require("zod");
|
|
8
|
-
const braintrust_1 = require("braintrust");
|
|
9
|
-
const service_1 = require("./service");
|
|
10
|
-
const events_1 = require("./events");
|
|
11
|
-
// Inicializar Braintrust logger
|
|
12
|
-
const logger = (0, braintrust_1.initLogger)({
|
|
13
|
-
projectName: "pulzar platform",
|
|
14
|
-
apiKey: process.env.BRAINTRUST_API_KEY,
|
|
15
|
-
});
|
|
16
|
-
const createDataStream = ai_1.createUIMessageStream;
|
|
17
|
-
class Story {
|
|
18
|
-
constructor(opts = {}) {
|
|
19
|
-
this.opts = opts;
|
|
20
|
-
this.db = (0, admin_1.init)({
|
|
21
|
-
appId: process.env.NEXT_PUBLIC_INSTANT_APP_ID,
|
|
22
|
-
adminToken: process.env.INSTANT_APP_ADMIN_TOKEN
|
|
23
|
-
});
|
|
24
|
-
this.agentService = new service_1.AgentService();
|
|
25
|
-
}
|
|
26
|
-
getModel(context) {
|
|
27
|
-
return "openai/gpt-5";
|
|
28
|
-
}
|
|
29
|
-
includeBaseTools() {
|
|
30
|
-
return { createMessage: true, requestDirection: true, end: true };
|
|
31
|
-
}
|
|
32
|
-
async getFinalizationToolNames() {
|
|
33
|
-
return [];
|
|
34
|
-
}
|
|
35
|
-
getBaseTools(dataStream, threadId) {
|
|
36
|
-
const include = this.includeBaseTools();
|
|
37
|
-
const baseTools = {};
|
|
38
|
-
if (include.createMessage) {
|
|
39
|
-
baseTools.createMessage = (0, ai_1.tool)({
|
|
40
|
-
description: "Send a message to the user. Use for final confirmations or information.",
|
|
41
|
-
inputSchema: zod_1.z.object({
|
|
42
|
-
message: zod_1.z.string().describe("Message for the user in markdown format")
|
|
43
|
-
}),
|
|
44
|
-
});
|
|
45
|
-
}
|
|
46
|
-
if (include.requestDirection) {
|
|
47
|
-
baseTools.requestDirection = (0, ai_1.tool)({
|
|
48
|
-
description: "Ask a human for guidance when blocked or unsure.",
|
|
49
|
-
inputSchema: zod_1.z.object({
|
|
50
|
-
issue: zod_1.z.string(),
|
|
51
|
-
context: zod_1.z.string(),
|
|
52
|
-
suggestedActions: zod_1.z.array(zod_1.z.string()).optional(),
|
|
53
|
-
urgency: zod_1.z.enum(["low", "medium", "high"]).default("medium"),
|
|
54
|
-
}),
|
|
55
|
-
});
|
|
56
|
-
}
|
|
57
|
-
if (include.end) {
|
|
58
|
-
baseTools.end = (0, ai_1.tool)({
|
|
59
|
-
description: "End the current interaction loop.",
|
|
60
|
-
inputSchema: zod_1.z.object({}).strict(),
|
|
61
|
-
execute: async () => {
|
|
62
|
-
return { success: true, message: "Ended" };
|
|
63
|
-
},
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
return baseTools;
|
|
67
|
-
}
|
|
68
|
-
async executeCreateMessage(eventId, args, threadId, dataStream) {
|
|
69
|
-
const assistantMessage = { id: eventId, role: "assistant", content: args.message, createdAt: new Date() };
|
|
70
|
-
try {
|
|
71
|
-
await this.saveMessagesToThread(threadId, [assistantMessage]);
|
|
72
|
-
}
|
|
73
|
-
catch { }
|
|
74
|
-
if (dataStream) {
|
|
75
|
-
//dataStream.writeData({ type: "user-response", message: args.message, responseType: args.type, includeContext: Boolean(args.includeContext), timestamp: new Date().toISOString() } as any)
|
|
76
|
-
}
|
|
77
|
-
return { success: true, message: args.message, data: { messageId: assistantMessage.id, threadId } };
|
|
78
|
-
}
|
|
79
|
-
async executeRequestDirection(eventId, args, threadId, _dataStream) {
|
|
80
|
-
const systemMessage = { id: eventId, role: "assistant", content: `Direction requested: ${args.issue}\nContext: ${args.context}`, createdAt: new Date() };
|
|
81
|
-
return { success: true, message: "Direction requested", data: { messageId: systemMessage.id, threadId } };
|
|
82
|
-
}
|
|
83
|
-
async progressStream(incomingEvent, contextIdentifier, options) {
|
|
84
|
-
// get or create context
|
|
85
|
-
const currentContext = await this.agentService.getOrCreateContext(contextIdentifier);
|
|
86
|
-
const contextSelector = contextIdentifier?.id
|
|
87
|
-
? { id: contextIdentifier.id }
|
|
88
|
-
: contextIdentifier?.key
|
|
89
|
-
? { key: contextIdentifier.key }
|
|
90
|
-
: { id: currentContext.id };
|
|
91
|
-
// save incoming event
|
|
92
|
-
const triggerEvent = await this.agentService.saveEvent(contextSelector, incomingEvent);
|
|
93
|
-
const triggerEventId = triggerEvent.id; // trigger event id
|
|
94
|
-
const eventId = (0, admin_1.id)(); // reaction event id
|
|
95
|
-
// create execution and set context status
|
|
96
|
-
const execution = await this.agentService.createExecution(contextSelector, triggerEventId, eventId);
|
|
97
|
-
const executionId = execution.id;
|
|
98
|
-
let latestReactionEvent = null;
|
|
99
|
-
let executionStatus = "executing";
|
|
100
|
-
const markFailure = async () => {
|
|
101
|
-
if (latestReactionEvent && latestReactionEvent.status !== "failed") {
|
|
102
|
-
try {
|
|
103
|
-
latestReactionEvent = await this.agentService.updateEvent(latestReactionEvent.id, {
|
|
104
|
-
...latestReactionEvent,
|
|
105
|
-
status: "failed",
|
|
106
|
-
});
|
|
107
|
-
}
|
|
108
|
-
catch (eventError) {
|
|
109
|
-
console.error("Failed to mark reaction event as failed", eventError);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
if (executionStatus === "executing") {
|
|
113
|
-
try {
|
|
114
|
-
await this.agentService.completeExecution(contextSelector, executionId, "failed");
|
|
115
|
-
executionStatus = "failed";
|
|
116
|
-
}
|
|
117
|
-
catch (executionError) {
|
|
118
|
-
console.error("Failed to mark execution as failed", executionError);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
const dataStreamResult = createDataStream({
|
|
123
|
-
execute: async ({ writer: dataStream }) => {
|
|
124
|
-
let loopSafety = 0;
|
|
125
|
-
const MAX_LOOPS = 20;
|
|
126
|
-
// load previous events
|
|
127
|
-
const previousEvents = await this.agentService.getEvents(contextSelector);
|
|
128
|
-
const events = previousEvents;
|
|
129
|
-
const contextId = currentContext.id;
|
|
130
|
-
let reactionEvent = await this.agentService.saveEvent(contextSelector, {
|
|
131
|
-
id: eventId,
|
|
132
|
-
type: "assistant",
|
|
133
|
-
channel: "agent",
|
|
134
|
-
createdAt: new Date().toISOString(),
|
|
135
|
-
content: { parts: [] },
|
|
136
|
-
status: "pending",
|
|
137
|
-
});
|
|
138
|
-
latestReactionEvent = reactionEvent;
|
|
139
|
-
dataStream.write({ type: "event-start", data: { eventId: eventId } });
|
|
140
|
-
while (loopSafety < MAX_LOOPS) {
|
|
141
|
-
dataStream.write({ type: "start-step" });
|
|
142
|
-
loopSafety++;
|
|
143
|
-
// Read context
|
|
144
|
-
const currentContext = await this.agentService.getContext(contextSelector);
|
|
145
|
-
dataStream.write({ type: "data-context-id", data: { contextId: currentContext.id } });
|
|
146
|
-
// Initialize on each loop and get new context data
|
|
147
|
-
const contextContent = await this.initialize(currentContext);
|
|
148
|
-
// Update context
|
|
149
|
-
const updatedContext = await this.agentService.updateContextContent({ id: currentContext.id }, contextContent);
|
|
150
|
-
// Build tools
|
|
151
|
-
const subclassToolsAll = await this.buildTools(updatedContext, dataStream);
|
|
152
|
-
// Build base tools for agent loop control
|
|
153
|
-
const baseTools = this.getBaseTools(dataStream, updatedContext.id);
|
|
154
|
-
const tools = { ...subclassToolsAll, ...baseTools };
|
|
155
|
-
// Add web search if enabled
|
|
156
|
-
if (options?.webSearch) {
|
|
157
|
-
tools.web_search = openai_1.openai.tools.webSearch();
|
|
158
|
-
}
|
|
159
|
-
// Extract execute functions from tools
|
|
160
|
-
const executeMap = {};
|
|
161
|
-
for (const [name, t] of Object.entries(subclassToolsAll)) {
|
|
162
|
-
if (t.execute) {
|
|
163
|
-
executeMap[name] = t.execute;
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
const include = this.includeBaseTools();
|
|
167
|
-
if (include.createMessage) {
|
|
168
|
-
executeMap["createMessage"] = (args) => this.executeCreateMessage(eventId, args, updatedContext.id, dataStream);
|
|
169
|
-
}
|
|
170
|
-
if (include.requestDirection) {
|
|
171
|
-
executeMap["requestDirection"] = (args) => this.executeRequestDirection(eventId, args, updatedContext.id, dataStream);
|
|
172
|
-
}
|
|
173
|
-
for (const [, t] of Object.entries(tools)) {
|
|
174
|
-
delete t.execute;
|
|
175
|
-
}
|
|
176
|
-
const messagesForModel = await (0, events_1.convertEventsToModelMessages)(reactionEvent.status !== "pending"
|
|
177
|
-
? [...events, reactionEvent]
|
|
178
|
-
: [...events]);
|
|
179
|
-
const systemPrompt = await this.buildSystemPrompt(updatedContext);
|
|
180
|
-
const providerOptions = {};
|
|
181
|
-
if (options?.reasoningEffort) {
|
|
182
|
-
providerOptions.openai = {
|
|
183
|
-
reasoningEffort: options.reasoningEffort,
|
|
184
|
-
reasoningSummary: 'detailed',
|
|
185
|
-
};
|
|
186
|
-
}
|
|
187
|
-
const result = (0, ai_1.streamText)({
|
|
188
|
-
model: this.getModel(updatedContext),
|
|
189
|
-
system: systemPrompt,
|
|
190
|
-
messages: messagesForModel,
|
|
191
|
-
tools,
|
|
192
|
-
toolChoice: "required",
|
|
193
|
-
onStepFinish: (step) => {
|
|
194
|
-
console.log("onStepFinish", step);
|
|
195
|
-
},
|
|
196
|
-
stopWhen: (0, ai_1.stepCountIs)(1),
|
|
197
|
-
experimental_transform: (0, ai_1.smoothStream)({
|
|
198
|
-
delayInMs: 30,
|
|
199
|
-
chunking: 'word',
|
|
200
|
-
}),
|
|
201
|
-
...(Object.keys(providerOptions).length > 0 && { providerOptions }),
|
|
202
|
-
});
|
|
203
|
-
result.consumeStream();
|
|
204
|
-
// create promise
|
|
205
|
-
let resolveFinish;
|
|
206
|
-
let rejectFinish;
|
|
207
|
-
const finishPromise = new Promise((resolve, reject) => {
|
|
208
|
-
resolveFinish = resolve;
|
|
209
|
-
rejectFinish = reject;
|
|
210
|
-
});
|
|
211
|
-
dataStream.merge(result.toUIMessageStream({
|
|
212
|
-
sendStart: false,
|
|
213
|
-
generateMessageId: () => {
|
|
214
|
-
return eventId;
|
|
215
|
-
},
|
|
216
|
-
messageMetadata(options) {
|
|
217
|
-
return {
|
|
218
|
-
eventId: eventId,
|
|
219
|
-
};
|
|
220
|
-
},
|
|
221
|
-
onFinish: ({ messages }) => {
|
|
222
|
-
console.log("messages", messages);
|
|
223
|
-
const lastEvent = (0, events_1.createAssistantEventFromUIMessages)(eventId, messages);
|
|
224
|
-
resolveFinish(lastEvent);
|
|
225
|
-
},
|
|
226
|
-
onError: (e) => {
|
|
227
|
-
console.error("Agent error:", e);
|
|
228
|
-
rejectFinish(e);
|
|
229
|
-
const message = e instanceof Error ? e.message : String(e);
|
|
230
|
-
return message;
|
|
231
|
-
}
|
|
232
|
-
}).pipeThrough(new TransformStream({
|
|
233
|
-
transform(chunk, controller) {
|
|
234
|
-
if (chunk.type === "start") {
|
|
235
|
-
return;
|
|
236
|
-
}
|
|
237
|
-
if (chunk.type === "finish-step") {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
if (chunk.type === "start-step") {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
if (chunk.type === "finish") {
|
|
244
|
-
return;
|
|
245
|
-
}
|
|
246
|
-
controller.enqueue(chunk);
|
|
247
|
-
}
|
|
248
|
-
})));
|
|
249
|
-
// wait for the on finish here
|
|
250
|
-
const lastEvent = await finishPromise;
|
|
251
|
-
const toolCalls = lastEvent.content.parts.reduce((acc, p) => {
|
|
252
|
-
if (typeof p.type === "string" && p.type.startsWith("tool-")) {
|
|
253
|
-
const toolName = p.type.split("-")[1];
|
|
254
|
-
acc.push({ toolCallId: p.toolCallId, toolName: toolName, args: p.input });
|
|
255
|
-
}
|
|
256
|
-
return acc;
|
|
257
|
-
}, []);
|
|
258
|
-
console.log("agent.toolCalls.detected", {
|
|
259
|
-
eventId,
|
|
260
|
-
toolCalls: toolCalls.map((call) => ({ toolCallId: call.toolCallId, toolName: call.toolName }))
|
|
261
|
-
});
|
|
262
|
-
if (!toolCalls.length) {
|
|
263
|
-
const shouldEndInteraction = await this.callOnEnd(lastEvent);
|
|
264
|
-
if (shouldEndInteraction) {
|
|
265
|
-
break;
|
|
266
|
-
}
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
|
-
const reactionEventWithParts = {
|
|
270
|
-
...reactionEvent,
|
|
271
|
-
content: { parts: [...reactionEvent.content.parts, ...lastEvent.content.parts] },
|
|
272
|
-
};
|
|
273
|
-
let currentEventState = await this.agentService.updateEvent(reactionEvent.id, reactionEventWithParts);
|
|
274
|
-
latestReactionEvent = currentEventState;
|
|
275
|
-
const executionResults = await Promise.all(toolCalls.map(async (tc) => {
|
|
276
|
-
console.log("agent.toolCall.selected", {
|
|
277
|
-
eventId,
|
|
278
|
-
toolCallId: tc.toolCallId,
|
|
279
|
-
toolName: tc.toolName
|
|
280
|
-
});
|
|
281
|
-
let execSuccess = true;
|
|
282
|
-
let execMessage = "Executed";
|
|
283
|
-
let execResult = null;
|
|
284
|
-
try {
|
|
285
|
-
const execFn = executeMap[tc.toolName];
|
|
286
|
-
if (execFn) {
|
|
287
|
-
console.log("agent.toolCall.execute.start", { toolCallId: tc.toolCallId, toolName: tc.toolName });
|
|
288
|
-
execResult = await execFn(tc.args);
|
|
289
|
-
execSuccess = execResult?.success !== false;
|
|
290
|
-
execMessage = execResult?.message || execMessage;
|
|
291
|
-
console.log("agent.toolCall.execute.success", {
|
|
292
|
-
toolCallId: tc.toolCallId,
|
|
293
|
-
toolName: tc.toolName,
|
|
294
|
-
success: execSuccess
|
|
295
|
-
});
|
|
296
|
-
console.log("agent.toolCall.execute.result", {
|
|
297
|
-
toolCallId: tc.toolCallId,
|
|
298
|
-
toolName: tc.toolName,
|
|
299
|
-
result: execResult
|
|
300
|
-
});
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
catch (err) {
|
|
304
|
-
execSuccess = false;
|
|
305
|
-
execMessage = err.message;
|
|
306
|
-
console.error("agent.toolCall.execute.error", {
|
|
307
|
-
toolCallId: tc.toolCallId,
|
|
308
|
-
toolName: tc.toolName,
|
|
309
|
-
error: err
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
return { tc, execSuccess, execMessage, execResult };
|
|
313
|
-
}));
|
|
314
|
-
let exitOuterLoop = false;
|
|
315
|
-
const customFinalizationTools = await this.getFinalizationToolNames();
|
|
316
|
-
const allFinalToolNames = [...Story.FINAL_TOOL_NAMES, ...customFinalizationTools];
|
|
317
|
-
for (const { tc, execSuccess, execMessage, execResult } of executionResults) {
|
|
318
|
-
try {
|
|
319
|
-
if (execSuccess) {
|
|
320
|
-
dataStream.write({
|
|
321
|
-
type: "tool-output-available",
|
|
322
|
-
toolCallId: tc.toolCallId,
|
|
323
|
-
output: execResult,
|
|
324
|
-
});
|
|
325
|
-
}
|
|
326
|
-
else {
|
|
327
|
-
dataStream.write({
|
|
328
|
-
type: "tool-output-error",
|
|
329
|
-
toolCallId: tc.toolCallId,
|
|
330
|
-
errorText: String(execMessage || "Error"),
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
catch (e) {
|
|
335
|
-
console.error("Failed to write tool result to stream", e);
|
|
336
|
-
}
|
|
337
|
-
const existingParts = currentEventState?.content?.parts || [];
|
|
338
|
-
const mergedParts = existingParts.map((p) => {
|
|
339
|
-
if (p.type === `tool-${tc.toolName}` && p.toolCallId === tc.toolCallId) {
|
|
340
|
-
if (execSuccess) {
|
|
341
|
-
return {
|
|
342
|
-
...p,
|
|
343
|
-
state: "output-available",
|
|
344
|
-
output: execResult,
|
|
345
|
-
};
|
|
346
|
-
}
|
|
347
|
-
return {
|
|
348
|
-
...p,
|
|
349
|
-
state: "output-error",
|
|
350
|
-
errorText: String(execMessage || "Error"),
|
|
351
|
-
};
|
|
352
|
-
}
|
|
353
|
-
return p;
|
|
354
|
-
});
|
|
355
|
-
currentEventState = await this.agentService.updateEvent(currentEventState.id, {
|
|
356
|
-
id: currentEventState.id,
|
|
357
|
-
type: currentEventState.type,
|
|
358
|
-
channel: "agent",
|
|
359
|
-
createdAt: currentEventState.createdAt,
|
|
360
|
-
content: { parts: mergedParts },
|
|
361
|
-
});
|
|
362
|
-
dataStream.write({ type: "finish-step" });
|
|
363
|
-
await this.opts.onToolCallExecuted?.({
|
|
364
|
-
id: currentEventState.id,
|
|
365
|
-
toolCall: tc,
|
|
366
|
-
event: currentEventState.id,
|
|
367
|
-
success: execSuccess,
|
|
368
|
-
message: execMessage,
|
|
369
|
-
result: execResult,
|
|
370
|
-
});
|
|
371
|
-
let shouldEnd = false;
|
|
372
|
-
if (!execSuccess) {
|
|
373
|
-
const shouldEndInteraction = await this.callOnEnd(lastEvent);
|
|
374
|
-
if (shouldEndInteraction) {
|
|
375
|
-
shouldEnd = true;
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
if (!shouldEnd) {
|
|
379
|
-
if (allFinalToolNames.includes(tc.toolName)) {
|
|
380
|
-
const shouldEndInteraction = await this.callOnEnd(lastEvent);
|
|
381
|
-
if (shouldEndInteraction) {
|
|
382
|
-
shouldEnd = true;
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
if (shouldEnd) {
|
|
387
|
-
dataStream.write({ type: "finish", override: true });
|
|
388
|
-
exitOuterLoop = true;
|
|
389
|
-
break;
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
reactionEvent = currentEventState;
|
|
393
|
-
if (exitOuterLoop) {
|
|
394
|
-
break;
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
reactionEvent = await this.agentService.updateEvent(reactionEvent.id, {
|
|
398
|
-
...reactionEvent,
|
|
399
|
-
status: "completed",
|
|
400
|
-
});
|
|
401
|
-
latestReactionEvent = reactionEvent;
|
|
402
|
-
try {
|
|
403
|
-
await this.agentService.completeExecution(contextSelector, executionId, "completed");
|
|
404
|
-
executionStatus = "completed";
|
|
405
|
-
}
|
|
406
|
-
catch (error) {
|
|
407
|
-
console.error("Failed to mark execution as completed", error);
|
|
408
|
-
}
|
|
409
|
-
},
|
|
410
|
-
onError: (error) => {
|
|
411
|
-
console.error("Agent error:", error);
|
|
412
|
-
void markFailure();
|
|
413
|
-
return error instanceof Error ? error.message : String(error);
|
|
414
|
-
},
|
|
415
|
-
onFinish: async () => {
|
|
416
|
-
if (executionStatus === "executing") {
|
|
417
|
-
try {
|
|
418
|
-
await this.agentService.completeExecution(contextSelector, executionId, "completed");
|
|
419
|
-
executionStatus = "completed";
|
|
420
|
-
}
|
|
421
|
-
catch (executionError) {
|
|
422
|
-
console.error("Failed to finalize execution on finish", executionError);
|
|
423
|
-
}
|
|
424
|
-
}
|
|
425
|
-
console.log("Agent finished");
|
|
426
|
-
}
|
|
427
|
-
});
|
|
428
|
-
// start the stream
|
|
429
|
-
const dataStreamFilteredResult = dataStreamResult.pipeThrough(new TransformStream({
|
|
430
|
-
transform(chunk, controller) {
|
|
431
|
-
if (chunk.type === "start") {
|
|
432
|
-
console.log("start", chunk.data);
|
|
433
|
-
return;
|
|
434
|
-
}
|
|
435
|
-
if (chunk.type === "event-start") {
|
|
436
|
-
controller.enqueue({ type: "start", messageId: chunk.data.eventId });
|
|
437
|
-
return;
|
|
438
|
-
}
|
|
439
|
-
controller.enqueue(chunk);
|
|
440
|
-
}
|
|
441
|
-
}));
|
|
442
|
-
return {
|
|
443
|
-
contextId: currentContext.id,
|
|
444
|
-
triggerEventId,
|
|
445
|
-
reactionEventId: eventId,
|
|
446
|
-
stream: dataStreamFilteredResult,
|
|
447
|
-
executionId,
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
async saveMessagesToThread(threadId, messages) {
|
|
451
|
-
// Placeholder for persistence hook. Not implemented in current scope.
|
|
452
|
-
return;
|
|
453
|
-
}
|
|
454
|
-
async callOnEnd(lastEvent) {
|
|
455
|
-
if (!this.opts.onEnd) {
|
|
456
|
-
return true;
|
|
457
|
-
}
|
|
458
|
-
try {
|
|
459
|
-
const result = await this.opts.onEnd(lastEvent);
|
|
460
|
-
if (typeof result === "boolean") {
|
|
461
|
-
return result;
|
|
462
|
-
}
|
|
463
|
-
if (result && typeof result === "object") {
|
|
464
|
-
if (Object.prototype.hasOwnProperty.call(result, "end")) {
|
|
465
|
-
return Boolean(result.end);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
return true;
|
|
469
|
-
}
|
|
470
|
-
catch (error) {
|
|
471
|
-
console.error("onEnd callback failed", error);
|
|
472
|
-
return true;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
exports.Story = Story;
|
|
477
|
-
exports.Agent = Story;
|
|
478
|
-
Story.FINAL_TOOL_NAMES = ["createMessage", "requestDirection", "end"];
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Agent = exports.Story = void 0;
|
|
4
|
+
const admin_1 = require("@instantdb/admin");
|
|
5
|
+
const ai_1 = require("ai");
|
|
6
|
+
const openai_1 = require("@ai-sdk/openai");
|
|
7
|
+
const zod_1 = require("zod");
|
|
8
|
+
const braintrust_1 = require("braintrust");
|
|
9
|
+
const service_1 = require("./service");
|
|
10
|
+
const events_1 = require("./events");
|
|
11
|
+
// Inicializar Braintrust logger
|
|
12
|
+
const logger = (0, braintrust_1.initLogger)({
|
|
13
|
+
projectName: "pulzar platform",
|
|
14
|
+
apiKey: process.env.BRAINTRUST_API_KEY,
|
|
15
|
+
});
|
|
16
|
+
const createDataStream = ai_1.createUIMessageStream;
|
|
17
|
+
class Story {
|
|
18
|
+
constructor(opts = {}) {
|
|
19
|
+
this.opts = opts;
|
|
20
|
+
this.db = (0, admin_1.init)({
|
|
21
|
+
appId: process.env.NEXT_PUBLIC_INSTANT_APP_ID,
|
|
22
|
+
adminToken: process.env.INSTANT_APP_ADMIN_TOKEN
|
|
23
|
+
});
|
|
24
|
+
this.agentService = new service_1.AgentService();
|
|
25
|
+
}
|
|
26
|
+
getModel(context) {
|
|
27
|
+
return "openai/gpt-5";
|
|
28
|
+
}
|
|
29
|
+
includeBaseTools() {
|
|
30
|
+
return { createMessage: true, requestDirection: true, end: true };
|
|
31
|
+
}
|
|
32
|
+
async getFinalizationToolNames() {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
getBaseTools(dataStream, threadId) {
|
|
36
|
+
const include = this.includeBaseTools();
|
|
37
|
+
const baseTools = {};
|
|
38
|
+
if (include.createMessage) {
|
|
39
|
+
baseTools.createMessage = (0, ai_1.tool)({
|
|
40
|
+
description: "Send a message to the user. Use for final confirmations or information.",
|
|
41
|
+
inputSchema: zod_1.z.object({
|
|
42
|
+
message: zod_1.z.string().describe("Message for the user in markdown format")
|
|
43
|
+
}),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
if (include.requestDirection) {
|
|
47
|
+
baseTools.requestDirection = (0, ai_1.tool)({
|
|
48
|
+
description: "Ask a human for guidance when blocked or unsure.",
|
|
49
|
+
inputSchema: zod_1.z.object({
|
|
50
|
+
issue: zod_1.z.string(),
|
|
51
|
+
context: zod_1.z.string(),
|
|
52
|
+
suggestedActions: zod_1.z.array(zod_1.z.string()).optional(),
|
|
53
|
+
urgency: zod_1.z.enum(["low", "medium", "high"]).default("medium"),
|
|
54
|
+
}),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (include.end) {
|
|
58
|
+
baseTools.end = (0, ai_1.tool)({
|
|
59
|
+
description: "End the current interaction loop.",
|
|
60
|
+
inputSchema: zod_1.z.object({}).strict(),
|
|
61
|
+
execute: async () => {
|
|
62
|
+
return { success: true, message: "Ended" };
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
return baseTools;
|
|
67
|
+
}
|
|
68
|
+
async executeCreateMessage(eventId, args, threadId, dataStream) {
|
|
69
|
+
const assistantMessage = { id: eventId, role: "assistant", content: args.message, createdAt: new Date() };
|
|
70
|
+
try {
|
|
71
|
+
await this.saveMessagesToThread(threadId, [assistantMessage]);
|
|
72
|
+
}
|
|
73
|
+
catch { }
|
|
74
|
+
if (dataStream) {
|
|
75
|
+
//dataStream.writeData({ type: "user-response", message: args.message, responseType: args.type, includeContext: Boolean(args.includeContext), timestamp: new Date().toISOString() } as any)
|
|
76
|
+
}
|
|
77
|
+
return { success: true, message: args.message, data: { messageId: assistantMessage.id, threadId } };
|
|
78
|
+
}
|
|
79
|
+
async executeRequestDirection(eventId, args, threadId, _dataStream) {
|
|
80
|
+
const systemMessage = { id: eventId, role: "assistant", content: `Direction requested: ${args.issue}\nContext: ${args.context}`, createdAt: new Date() };
|
|
81
|
+
return { success: true, message: "Direction requested", data: { messageId: systemMessage.id, threadId } };
|
|
82
|
+
}
|
|
83
|
+
async progressStream(incomingEvent, contextIdentifier, options) {
|
|
84
|
+
// get or create context
|
|
85
|
+
const currentContext = await this.agentService.getOrCreateContext(contextIdentifier);
|
|
86
|
+
const contextSelector = contextIdentifier?.id
|
|
87
|
+
? { id: contextIdentifier.id }
|
|
88
|
+
: contextIdentifier?.key
|
|
89
|
+
? { key: contextIdentifier.key }
|
|
90
|
+
: { id: currentContext.id };
|
|
91
|
+
// save incoming event
|
|
92
|
+
const triggerEvent = await this.agentService.saveEvent(contextSelector, incomingEvent);
|
|
93
|
+
const triggerEventId = triggerEvent.id; // trigger event id
|
|
94
|
+
const eventId = (0, admin_1.id)(); // reaction event id
|
|
95
|
+
// create execution and set context status
|
|
96
|
+
const execution = await this.agentService.createExecution(contextSelector, triggerEventId, eventId);
|
|
97
|
+
const executionId = execution.id;
|
|
98
|
+
let latestReactionEvent = null;
|
|
99
|
+
let executionStatus = "executing";
|
|
100
|
+
const markFailure = async () => {
|
|
101
|
+
if (latestReactionEvent && latestReactionEvent.status !== "failed") {
|
|
102
|
+
try {
|
|
103
|
+
latestReactionEvent = await this.agentService.updateEvent(latestReactionEvent.id, {
|
|
104
|
+
...latestReactionEvent,
|
|
105
|
+
status: "failed",
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
catch (eventError) {
|
|
109
|
+
console.error("Failed to mark reaction event as failed", eventError);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
if (executionStatus === "executing") {
|
|
113
|
+
try {
|
|
114
|
+
await this.agentService.completeExecution(contextSelector, executionId, "failed");
|
|
115
|
+
executionStatus = "failed";
|
|
116
|
+
}
|
|
117
|
+
catch (executionError) {
|
|
118
|
+
console.error("Failed to mark execution as failed", executionError);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
const dataStreamResult = createDataStream({
|
|
123
|
+
execute: async ({ writer: dataStream }) => {
|
|
124
|
+
let loopSafety = 0;
|
|
125
|
+
const MAX_LOOPS = 20;
|
|
126
|
+
// load previous events
|
|
127
|
+
const previousEvents = await this.agentService.getEvents(contextSelector);
|
|
128
|
+
const events = previousEvents;
|
|
129
|
+
const contextId = currentContext.id;
|
|
130
|
+
let reactionEvent = await this.agentService.saveEvent(contextSelector, {
|
|
131
|
+
id: eventId,
|
|
132
|
+
type: "assistant",
|
|
133
|
+
channel: "agent",
|
|
134
|
+
createdAt: new Date().toISOString(),
|
|
135
|
+
content: { parts: [] },
|
|
136
|
+
status: "pending",
|
|
137
|
+
});
|
|
138
|
+
latestReactionEvent = reactionEvent;
|
|
139
|
+
dataStream.write({ type: "event-start", data: { eventId: eventId } });
|
|
140
|
+
while (loopSafety < MAX_LOOPS) {
|
|
141
|
+
dataStream.write({ type: "start-step" });
|
|
142
|
+
loopSafety++;
|
|
143
|
+
// Read context
|
|
144
|
+
const currentContext = await this.agentService.getContext(contextSelector);
|
|
145
|
+
dataStream.write({ type: "data-context-id", data: { contextId: currentContext.id } });
|
|
146
|
+
// Initialize on each loop and get new context data
|
|
147
|
+
const contextContent = await this.initialize(currentContext);
|
|
148
|
+
// Update context
|
|
149
|
+
const updatedContext = await this.agentService.updateContextContent({ id: currentContext.id }, contextContent);
|
|
150
|
+
// Build tools
|
|
151
|
+
const subclassToolsAll = await this.buildTools(updatedContext, dataStream);
|
|
152
|
+
// Build base tools for agent loop control
|
|
153
|
+
const baseTools = this.getBaseTools(dataStream, updatedContext.id);
|
|
154
|
+
const tools = { ...subclassToolsAll, ...baseTools };
|
|
155
|
+
// Add web search if enabled
|
|
156
|
+
if (options?.webSearch) {
|
|
157
|
+
tools.web_search = openai_1.openai.tools.webSearch();
|
|
158
|
+
}
|
|
159
|
+
// Extract execute functions from tools
|
|
160
|
+
const executeMap = {};
|
|
161
|
+
for (const [name, t] of Object.entries(subclassToolsAll)) {
|
|
162
|
+
if (t.execute) {
|
|
163
|
+
executeMap[name] = t.execute;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
const include = this.includeBaseTools();
|
|
167
|
+
if (include.createMessage) {
|
|
168
|
+
executeMap["createMessage"] = (args) => this.executeCreateMessage(eventId, args, updatedContext.id, dataStream);
|
|
169
|
+
}
|
|
170
|
+
if (include.requestDirection) {
|
|
171
|
+
executeMap["requestDirection"] = (args) => this.executeRequestDirection(eventId, args, updatedContext.id, dataStream);
|
|
172
|
+
}
|
|
173
|
+
for (const [, t] of Object.entries(tools)) {
|
|
174
|
+
delete t.execute;
|
|
175
|
+
}
|
|
176
|
+
const messagesForModel = await (0, events_1.convertEventsToModelMessages)(reactionEvent.status !== "pending"
|
|
177
|
+
? [...events, reactionEvent]
|
|
178
|
+
: [...events]);
|
|
179
|
+
const systemPrompt = await this.buildSystemPrompt(updatedContext);
|
|
180
|
+
const providerOptions = {};
|
|
181
|
+
if (options?.reasoningEffort) {
|
|
182
|
+
providerOptions.openai = {
|
|
183
|
+
reasoningEffort: options.reasoningEffort,
|
|
184
|
+
reasoningSummary: 'detailed',
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
const result = (0, ai_1.streamText)({
|
|
188
|
+
model: this.getModel(updatedContext),
|
|
189
|
+
system: systemPrompt,
|
|
190
|
+
messages: messagesForModel,
|
|
191
|
+
tools,
|
|
192
|
+
toolChoice: "required",
|
|
193
|
+
onStepFinish: (step) => {
|
|
194
|
+
console.log("onStepFinish", step);
|
|
195
|
+
},
|
|
196
|
+
stopWhen: (0, ai_1.stepCountIs)(1),
|
|
197
|
+
experimental_transform: (0, ai_1.smoothStream)({
|
|
198
|
+
delayInMs: 30,
|
|
199
|
+
chunking: 'word',
|
|
200
|
+
}),
|
|
201
|
+
...(Object.keys(providerOptions).length > 0 && { providerOptions }),
|
|
202
|
+
});
|
|
203
|
+
result.consumeStream();
|
|
204
|
+
// create promise
|
|
205
|
+
let resolveFinish;
|
|
206
|
+
let rejectFinish;
|
|
207
|
+
const finishPromise = new Promise((resolve, reject) => {
|
|
208
|
+
resolveFinish = resolve;
|
|
209
|
+
rejectFinish = reject;
|
|
210
|
+
});
|
|
211
|
+
dataStream.merge(result.toUIMessageStream({
|
|
212
|
+
sendStart: false,
|
|
213
|
+
generateMessageId: () => {
|
|
214
|
+
return eventId;
|
|
215
|
+
},
|
|
216
|
+
messageMetadata(options) {
|
|
217
|
+
return {
|
|
218
|
+
eventId: eventId,
|
|
219
|
+
};
|
|
220
|
+
},
|
|
221
|
+
onFinish: ({ messages }) => {
|
|
222
|
+
console.log("messages", messages);
|
|
223
|
+
const lastEvent = (0, events_1.createAssistantEventFromUIMessages)(eventId, messages);
|
|
224
|
+
resolveFinish(lastEvent);
|
|
225
|
+
},
|
|
226
|
+
onError: (e) => {
|
|
227
|
+
console.error("Agent error:", e);
|
|
228
|
+
rejectFinish(e);
|
|
229
|
+
const message = e instanceof Error ? e.message : String(e);
|
|
230
|
+
return message;
|
|
231
|
+
}
|
|
232
|
+
}).pipeThrough(new TransformStream({
|
|
233
|
+
transform(chunk, controller) {
|
|
234
|
+
if (chunk.type === "start") {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (chunk.type === "finish-step") {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (chunk.type === "start-step") {
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
if (chunk.type === "finish") {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
controller.enqueue(chunk);
|
|
247
|
+
}
|
|
248
|
+
})));
|
|
249
|
+
// wait for the on finish here
|
|
250
|
+
const lastEvent = await finishPromise;
|
|
251
|
+
const toolCalls = lastEvent.content.parts.reduce((acc, p) => {
|
|
252
|
+
if (typeof p.type === "string" && p.type.startsWith("tool-")) {
|
|
253
|
+
const toolName = p.type.split("-")[1];
|
|
254
|
+
acc.push({ toolCallId: p.toolCallId, toolName: toolName, args: p.input });
|
|
255
|
+
}
|
|
256
|
+
return acc;
|
|
257
|
+
}, []);
|
|
258
|
+
console.log("agent.toolCalls.detected", {
|
|
259
|
+
eventId,
|
|
260
|
+
toolCalls: toolCalls.map((call) => ({ toolCallId: call.toolCallId, toolName: call.toolName }))
|
|
261
|
+
});
|
|
262
|
+
if (!toolCalls.length) {
|
|
263
|
+
const shouldEndInteraction = await this.callOnEnd(lastEvent);
|
|
264
|
+
if (shouldEndInteraction) {
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
const reactionEventWithParts = {
|
|
270
|
+
...reactionEvent,
|
|
271
|
+
content: { parts: [...reactionEvent.content.parts, ...lastEvent.content.parts] },
|
|
272
|
+
};
|
|
273
|
+
let currentEventState = await this.agentService.updateEvent(reactionEvent.id, reactionEventWithParts);
|
|
274
|
+
latestReactionEvent = currentEventState;
|
|
275
|
+
const executionResults = await Promise.all(toolCalls.map(async (tc) => {
|
|
276
|
+
console.log("agent.toolCall.selected", {
|
|
277
|
+
eventId,
|
|
278
|
+
toolCallId: tc.toolCallId,
|
|
279
|
+
toolName: tc.toolName
|
|
280
|
+
});
|
|
281
|
+
let execSuccess = true;
|
|
282
|
+
let execMessage = "Executed";
|
|
283
|
+
let execResult = null;
|
|
284
|
+
try {
|
|
285
|
+
const execFn = executeMap[tc.toolName];
|
|
286
|
+
if (execFn) {
|
|
287
|
+
console.log("agent.toolCall.execute.start", { toolCallId: tc.toolCallId, toolName: tc.toolName });
|
|
288
|
+
execResult = await execFn(tc.args);
|
|
289
|
+
execSuccess = execResult?.success !== false;
|
|
290
|
+
execMessage = execResult?.message || execMessage;
|
|
291
|
+
console.log("agent.toolCall.execute.success", {
|
|
292
|
+
toolCallId: tc.toolCallId,
|
|
293
|
+
toolName: tc.toolName,
|
|
294
|
+
success: execSuccess
|
|
295
|
+
});
|
|
296
|
+
console.log("agent.toolCall.execute.result", {
|
|
297
|
+
toolCallId: tc.toolCallId,
|
|
298
|
+
toolName: tc.toolName,
|
|
299
|
+
result: execResult
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
catch (err) {
|
|
304
|
+
execSuccess = false;
|
|
305
|
+
execMessage = err.message;
|
|
306
|
+
console.error("agent.toolCall.execute.error", {
|
|
307
|
+
toolCallId: tc.toolCallId,
|
|
308
|
+
toolName: tc.toolName,
|
|
309
|
+
error: err
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
return { tc, execSuccess, execMessage, execResult };
|
|
313
|
+
}));
|
|
314
|
+
let exitOuterLoop = false;
|
|
315
|
+
const customFinalizationTools = await this.getFinalizationToolNames();
|
|
316
|
+
const allFinalToolNames = [...Story.FINAL_TOOL_NAMES, ...customFinalizationTools];
|
|
317
|
+
for (const { tc, execSuccess, execMessage, execResult } of executionResults) {
|
|
318
|
+
try {
|
|
319
|
+
if (execSuccess) {
|
|
320
|
+
dataStream.write({
|
|
321
|
+
type: "tool-output-available",
|
|
322
|
+
toolCallId: tc.toolCallId,
|
|
323
|
+
output: execResult,
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
dataStream.write({
|
|
328
|
+
type: "tool-output-error",
|
|
329
|
+
toolCallId: tc.toolCallId,
|
|
330
|
+
errorText: String(execMessage || "Error"),
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
catch (e) {
|
|
335
|
+
console.error("Failed to write tool result to stream", e);
|
|
336
|
+
}
|
|
337
|
+
const existingParts = currentEventState?.content?.parts || [];
|
|
338
|
+
const mergedParts = existingParts.map((p) => {
|
|
339
|
+
if (p.type === `tool-${tc.toolName}` && p.toolCallId === tc.toolCallId) {
|
|
340
|
+
if (execSuccess) {
|
|
341
|
+
return {
|
|
342
|
+
...p,
|
|
343
|
+
state: "output-available",
|
|
344
|
+
output: execResult,
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
return {
|
|
348
|
+
...p,
|
|
349
|
+
state: "output-error",
|
|
350
|
+
errorText: String(execMessage || "Error"),
|
|
351
|
+
};
|
|
352
|
+
}
|
|
353
|
+
return p;
|
|
354
|
+
});
|
|
355
|
+
currentEventState = await this.agentService.updateEvent(currentEventState.id, {
|
|
356
|
+
id: currentEventState.id,
|
|
357
|
+
type: currentEventState.type,
|
|
358
|
+
channel: "agent",
|
|
359
|
+
createdAt: currentEventState.createdAt,
|
|
360
|
+
content: { parts: mergedParts },
|
|
361
|
+
});
|
|
362
|
+
dataStream.write({ type: "finish-step" });
|
|
363
|
+
await this.opts.onToolCallExecuted?.({
|
|
364
|
+
id: currentEventState.id,
|
|
365
|
+
toolCall: tc,
|
|
366
|
+
event: currentEventState.id,
|
|
367
|
+
success: execSuccess,
|
|
368
|
+
message: execMessage,
|
|
369
|
+
result: execResult,
|
|
370
|
+
});
|
|
371
|
+
let shouldEnd = false;
|
|
372
|
+
if (!execSuccess) {
|
|
373
|
+
const shouldEndInteraction = await this.callOnEnd(lastEvent);
|
|
374
|
+
if (shouldEndInteraction) {
|
|
375
|
+
shouldEnd = true;
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
if (!shouldEnd) {
|
|
379
|
+
if (allFinalToolNames.includes(tc.toolName)) {
|
|
380
|
+
const shouldEndInteraction = await this.callOnEnd(lastEvent);
|
|
381
|
+
if (shouldEndInteraction) {
|
|
382
|
+
shouldEnd = true;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
if (shouldEnd) {
|
|
387
|
+
dataStream.write({ type: "finish", override: true });
|
|
388
|
+
exitOuterLoop = true;
|
|
389
|
+
break;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
reactionEvent = currentEventState;
|
|
393
|
+
if (exitOuterLoop) {
|
|
394
|
+
break;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
reactionEvent = await this.agentService.updateEvent(reactionEvent.id, {
|
|
398
|
+
...reactionEvent,
|
|
399
|
+
status: "completed",
|
|
400
|
+
});
|
|
401
|
+
latestReactionEvent = reactionEvent;
|
|
402
|
+
try {
|
|
403
|
+
await this.agentService.completeExecution(contextSelector, executionId, "completed");
|
|
404
|
+
executionStatus = "completed";
|
|
405
|
+
}
|
|
406
|
+
catch (error) {
|
|
407
|
+
console.error("Failed to mark execution as completed", error);
|
|
408
|
+
}
|
|
409
|
+
},
|
|
410
|
+
onError: (error) => {
|
|
411
|
+
console.error("Agent error:", error);
|
|
412
|
+
void markFailure();
|
|
413
|
+
return error instanceof Error ? error.message : String(error);
|
|
414
|
+
},
|
|
415
|
+
onFinish: async () => {
|
|
416
|
+
if (executionStatus === "executing") {
|
|
417
|
+
try {
|
|
418
|
+
await this.agentService.completeExecution(contextSelector, executionId, "completed");
|
|
419
|
+
executionStatus = "completed";
|
|
420
|
+
}
|
|
421
|
+
catch (executionError) {
|
|
422
|
+
console.error("Failed to finalize execution on finish", executionError);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
console.log("Agent finished");
|
|
426
|
+
}
|
|
427
|
+
});
|
|
428
|
+
// start the stream
|
|
429
|
+
const dataStreamFilteredResult = dataStreamResult.pipeThrough(new TransformStream({
|
|
430
|
+
transform(chunk, controller) {
|
|
431
|
+
if (chunk.type === "start") {
|
|
432
|
+
console.log("start", chunk.data);
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (chunk.type === "event-start") {
|
|
436
|
+
controller.enqueue({ type: "start", messageId: chunk.data.eventId });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
controller.enqueue(chunk);
|
|
440
|
+
}
|
|
441
|
+
}));
|
|
442
|
+
return {
|
|
443
|
+
contextId: currentContext.id,
|
|
444
|
+
triggerEventId,
|
|
445
|
+
reactionEventId: eventId,
|
|
446
|
+
stream: dataStreamFilteredResult,
|
|
447
|
+
executionId,
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
async saveMessagesToThread(threadId, messages) {
|
|
451
|
+
// Placeholder for persistence hook. Not implemented in current scope.
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
async callOnEnd(lastEvent) {
|
|
455
|
+
if (!this.opts.onEnd) {
|
|
456
|
+
return true;
|
|
457
|
+
}
|
|
458
|
+
try {
|
|
459
|
+
const result = await this.opts.onEnd(lastEvent);
|
|
460
|
+
if (typeof result === "boolean") {
|
|
461
|
+
return result;
|
|
462
|
+
}
|
|
463
|
+
if (result && typeof result === "object") {
|
|
464
|
+
if (Object.prototype.hasOwnProperty.call(result, "end")) {
|
|
465
|
+
return Boolean(result.end);
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
return true;
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
console.error("onEnd callback failed", error);
|
|
472
|
+
return true;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
exports.Story = Story;
|
|
477
|
+
exports.Agent = Story;
|
|
478
|
+
Story.FINAL_TOOL_NAMES = ["createMessage", "requestDirection", "end"];
|
|
479
479
|
//# sourceMappingURL=agent.js.map
|