@flink-app/flink 2.0.0-alpha.91 → 2.0.0-alpha.93

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.
@@ -77,16 +77,20 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
77
77
  };
78
78
  Object.defineProperty(exports, "__esModule", { value: true });
79
79
  exports.AgentRunner = void 0;
80
+ var uuid_1 = require("uuid");
81
+ var FlinkLogFactory_1 = require("../FlinkLogFactory");
80
82
  var FlinkLog_1 = require("../FlinkLog");
83
+ var observerLog = FlinkLogFactory_1.FlinkLogFactory.createLogger("flink.ai.observer");
81
84
  var AgentRunner = /** @class */ (function () {
82
85
  function AgentRunner(agentProps, tools, llmAdapters, agentName, // Optional agent name for logging
83
- ctx // FlinkContext for instruction callbacks (any for flexibility)
84
- ) {
86
+ ctx, // FlinkContext for instruction callbacks (any for flexibility)
87
+ observer) {
85
88
  var _a, _b, _c, _d, _e;
86
89
  this.agentProps = agentProps;
87
90
  this.tools = tools;
88
91
  this.agentName = agentName;
89
92
  this.ctx = ctx;
93
+ this.observer = observer;
90
94
  // Get appropriate LLM adapter based on adapterId
91
95
  var adapterId = ((_a = agentProps.model) === null || _a === void 0 ? void 0 : _a.adapterId) || "default";
92
96
  var adapter = llmAdapters.get(adapterId);
@@ -101,37 +105,47 @@ var AgentRunner = /** @class */ (function () {
101
105
  }
102
106
  AgentRunner.prototype.streamGenerator = function (input) {
103
107
  return __asyncGenerator(this, arguments, function streamGenerator_1() {
104
- var maxSteps, toolCalls, execContext, resolvedInstructions, _a, err_1, messages, step, finalMessage, stoppedEarly, totalInputTokens, totalOutputTokens, totalCachedInputTokens, totalCacheCreationInputTokens, finalProviderMetadata, availableTools, needsCompaction, beforeCount, originalMessages, compactedMessages, error_1, llmStream, textContent, toolCallsFromStream, usage, stopReason, providerMetadata, _b, llmStream_1, llmStream_1_1, chunk, _c, e_1_1, llmResponse, assistantContent, _i, _d, toolCall, stepContext, toolResults, _e, _f, toolCall, toolExecutor, toolOutput, toolError, toolResult, formattedResult, err_2, stepContext, result, finishContext;
105
- var _g, e_1, _h, _j;
106
- var _k, _l, _m;
107
- return __generator(this, function (_o) {
108
- switch (_o.label) {
108
+ var maxSteps, toolCalls, runId, runStartedAt, agentId, modelInfo, declaredToolNames, execContext, resolvedInstructions, _a, err_1, messages, step, finalMessage, stoppedEarly, totalInputTokens, totalOutputTokens, totalCachedInputTokens, totalCacheCreationInputTokens, finalProviderMetadata, buildResult, _loop_1, this_1, state_1, result_1, finishContext, err_2;
109
+ var _this = this;
110
+ var _b, e_1, _c, _d;
111
+ var _e, _f, _g, _h;
112
+ return __generator(this, function (_j) {
113
+ switch (_j.label) {
109
114
  case 0:
110
- maxSteps = ((_k = input.options) === null || _k === void 0 ? void 0 : _k.maxSteps) || this.maxSteps;
115
+ maxSteps = ((_e = input.options) === null || _e === void 0 ? void 0 : _e.maxSteps) || this.maxSteps;
111
116
  toolCalls = [];
117
+ runId = (0, uuid_1.v4)();
118
+ runStartedAt = Date.now();
119
+ agentId = this.agentName || "unknown";
120
+ modelInfo = {
121
+ adapterId: (_f = this.agentProps.model) === null || _f === void 0 ? void 0 : _f.adapterId,
122
+ maxTokens: this.maxTokens,
123
+ temperature: this.temperature,
124
+ };
125
+ declaredToolNames = Array.from(this.tools.keys());
112
126
  execContext = {
113
- agentId: this.agentName || "unknown",
127
+ agentId: agentId,
114
128
  conversationId: input.conversationId,
115
129
  user: input.user,
116
130
  metadata: input.metadata,
117
131
  conversationContext: input.conversationContext,
118
132
  };
119
- _o.label = 1;
133
+ _j.label = 1;
120
134
  case 1:
121
- _o.trys.push([1, 5, , 6]);
135
+ _j.trys.push([1, 5, , 6]);
122
136
  if (!(typeof this.agentProps.instructions === "function")) return [3 /*break*/, 3];
123
137
  return [4 /*yield*/, __await(this.agentProps.instructions(this.ctx, execContext))];
124
138
  case 2:
125
- _a = _o.sent();
139
+ _a = _j.sent();
126
140
  return [3 /*break*/, 4];
127
141
  case 3:
128
142
  _a = this.agentProps.instructions;
129
- _o.label = 4;
143
+ _j.label = 4;
130
144
  case 4:
131
145
  resolvedInstructions = _a;
132
146
  return [3 /*break*/, 6];
133
147
  case 5:
134
- err_1 = _o.sent();
148
+ err_1 = _j.sent();
135
149
  throw new Error("Failed to resolve instructions for agent ".concat(this.agentName, ": ").concat(err_1.message));
136
150
  case 6:
137
151
  if (input.history && input.history.length > 0) {
@@ -152,6 +166,20 @@ var AgentRunner = /** @class */ (function () {
152
166
  else {
153
167
  messages.push.apply(messages, this.convertMessages(input.message));
154
168
  }
169
+ // Dispatch observer onRun (pre-loop, before compaction / tool filtering)
170
+ this.safeDispatch("onRun", function () {
171
+ var _a, _b;
172
+ return (_b = (_a = _this.observer) === null || _a === void 0 ? void 0 : _a.onRun) === null || _b === void 0 ? void 0 : _b.call(_a, {
173
+ runId: runId,
174
+ agentId: agentId,
175
+ instructions: resolvedInstructions,
176
+ input: input,
177
+ messages: __spreadArray([], messages, true),
178
+ tools: declaredToolNames,
179
+ model: modelInfo,
180
+ context: execContext,
181
+ });
182
+ });
155
183
  step = 0;
156
184
  finalMessage = "";
157
185
  stoppedEarly = false;
@@ -160,371 +188,487 @@ var AgentRunner = /** @class */ (function () {
160
188
  totalCachedInputTokens = 0;
161
189
  totalCacheCreationInputTokens = 0;
162
190
  finalProviderMetadata = {};
163
- _o.label = 7;
191
+ buildResult = function () { return ({
192
+ runId: runId,
193
+ message: finalMessage,
194
+ toolCalls: toolCalls,
195
+ stepsUsed: step,
196
+ stoppedEarly: stoppedEarly,
197
+ usage: __assign(__assign({ inputTokens: totalInputTokens, outputTokens: totalOutputTokens }, (totalCachedInputTokens > 0 && { cachedInputTokens: totalCachedInputTokens })), (totalCacheCreationInputTokens > 0 && { cacheCreationInputTokens: totalCacheCreationInputTokens })),
198
+ providerMetadata: Object.keys(finalProviderMetadata).length > 0 ? finalProviderMetadata : undefined,
199
+ }); };
200
+ _j.label = 7;
164
201
  case 7:
165
- if (!(step < maxSteps)) return [3 /*break*/, 53];
166
- step++;
167
- return [4 /*yield*/, __await(this.filterToolsByPermissions(input.user, input.userPermissions, input.conversationContext))];
202
+ _j.trys.push([7, 16, , 17]);
203
+ _loop_1 = function () {
204
+ var availableTools, needsCompaction, beforeCount, originalMessages, compactedMessages, error_1, toolCallsBeforeStep, llmStream, textContent, toolCallsFromStream, usage, stopReason, providerMetadata, _k, llmStream_1, llmStream_1_1, chunk, _l, e_1_1, llmResponse, assistantContent, _i, _m, toolCall, stepContext, toolResults, _o, _p, toolCall, toolExecutor, toolOutput, toolError, toolResult, formattedResult, err_3, stepContext;
205
+ return __generator(this, function (_q) {
206
+ switch (_q.label) {
207
+ case 0:
208
+ step++;
209
+ return [4 /*yield*/, __await(this_1.filterToolsByPermissions(input.user, input.userPermissions, input.conversationContext))];
210
+ case 1:
211
+ availableTools = _q.sent();
212
+ if (!this_1.agentProps.shouldCompact) return [3 /*break*/, 9];
213
+ _q.label = 2;
214
+ case 2:
215
+ _q.trys.push([2, 8, , 9]);
216
+ return [4 /*yield*/, __await(this_1.agentProps.shouldCompact(messages, step))];
217
+ case 3:
218
+ needsCompaction = _q.sent();
219
+ if (!needsCompaction) return [3 /*break*/, 7];
220
+ beforeCount = messages.length;
221
+ originalMessages = messages;
222
+ compactedMessages = void 0;
223
+ if (!this_1.agentProps.compactHistory) return [3 /*break*/, 5];
224
+ return [4 /*yield*/, __await(this_1.agentProps.compactHistory(messages, step))];
225
+ case 4:
226
+ compactedMessages = _q.sent();
227
+ return [3 /*break*/, 6];
228
+ case 5:
229
+ // Default strategy: sliding window keeping last 10 messages
230
+ compactedMessages = messages.slice(-10);
231
+ _q.label = 6;
232
+ case 6:
233
+ // Validation: ensure compacted array is not empty
234
+ if (!compactedMessages || compactedMessages.length === 0) {
235
+ throw new Error("compactHistory must return at least one message");
236
+ }
237
+ // Apply compaction
238
+ messages = compactedMessages;
239
+ // Log compaction for debugging
240
+ FlinkLog_1.log.debug("[Agent:".concat(this_1.agentName, "] Step ").concat(step, ": Compacted ").concat(beforeCount, " messages \u2192 ").concat(messages.length));
241
+ FlinkLog_1.log.debug("[Agent:".concat(this_1.agentName, "] Compacted messages:"), {
242
+ messageCount: messages.length,
243
+ messages: messages.map(function (m) { return ({
244
+ role: m.role,
245
+ contentPreview: typeof m.content === "string"
246
+ ? m.content.substring(0, 100) + (m.content.length > 100 ? "..." : "")
247
+ : "".concat(m.content.length, " blocks"),
248
+ }); }),
249
+ });
250
+ _q.label = 7;
251
+ case 7: return [3 /*break*/, 9];
252
+ case 8:
253
+ error_1 = _q.sent();
254
+ // Log error but don't fail execution - compaction is optional optimization
255
+ FlinkLog_1.log.error("[Agent:".concat(this_1.agentName, "] Context compaction failed:"), error_1.message);
256
+ return [3 /*break*/, 9];
257
+ case 9:
258
+ FlinkLog_1.log.debug("[Agent:".concat(this_1.agentName, "] Step ").concat(step, "/").concat(maxSteps, " - Calling LLM with:"), {
259
+ instructionsType: typeof this_1.agentProps.instructions === "function" ? "dynamic-callback" : "static",
260
+ messageCount: messages.length,
261
+ messages: messages.map(function (m) { return ({
262
+ role: m.role,
263
+ contentPreview: typeof m.content === "string"
264
+ ? m.content.substring(0, 100) + (m.content.length > 100 ? "..." : "")
265
+ : "".concat(m.content.length, " blocks"),
266
+ }); }),
267
+ toolCount: availableTools.length,
268
+ tools: availableTools.map(function (t) { return t.name; }),
269
+ maxTokens: this_1.maxTokens,
270
+ temperature: this_1.temperature,
271
+ });
272
+ // Dispatch observer onLlmCall — messages reflect post-compaction state;
273
+ // tools reflect per-step permission filtering
274
+ this_1.safeDispatch("onLlmCall", function () {
275
+ var _a, _b;
276
+ return (_b = (_a = _this.observer) === null || _a === void 0 ? void 0 : _a.onLlmCall) === null || _b === void 0 ? void 0 : _b.call(_a, {
277
+ runId: runId,
278
+ agentId: agentId,
279
+ step: step,
280
+ maxSteps: maxSteps,
281
+ instructions: resolvedInstructions,
282
+ messages: __spreadArray([], messages, true),
283
+ tools: availableTools.map(function (t) { return t.name; }),
284
+ model: modelInfo,
285
+ context: execContext,
286
+ });
287
+ });
288
+ toolCallsBeforeStep = toolCalls.length;
289
+ llmStream = this_1.llmAdapter.stream({
290
+ instructions: resolvedInstructions,
291
+ messages: messages,
292
+ tools: availableTools,
293
+ maxTokens: this_1.maxTokens,
294
+ temperature: this_1.temperature,
295
+ providerMetadata: input.providerMetadata,
296
+ });
297
+ textContent = "";
298
+ toolCallsFromStream = [];
299
+ usage = { inputTokens: 0, outputTokens: 0 };
300
+ stopReason = "end_turn";
301
+ providerMetadata = {};
302
+ _q.label = 10;
303
+ case 10:
304
+ _q.trys.push([10, 22, 23, 28]);
305
+ _k = true, llmStream_1 = (e_1 = void 0, __asyncValues(llmStream));
306
+ _q.label = 11;
307
+ case 11: return [4 /*yield*/, __await(llmStream_1.next())];
308
+ case 12:
309
+ if (!(llmStream_1_1 = _q.sent(), _b = llmStream_1_1.done, !_b)) return [3 /*break*/, 21];
310
+ _d = llmStream_1_1.value;
311
+ _k = false;
312
+ chunk = _d;
313
+ _l = chunk.type;
314
+ switch (_l) {
315
+ case "text": return [3 /*break*/, 13];
316
+ case "tool_call": return [3 /*break*/, 16];
317
+ case "usage": return [3 /*break*/, 17];
318
+ case "metadata": return [3 /*break*/, 18];
319
+ case "done": return [3 /*break*/, 19];
320
+ }
321
+ return [3 /*break*/, 20];
322
+ case 13:
323
+ textContent += chunk.delta;
324
+ return [4 /*yield*/, __await({ type: "text_delta", delta: chunk.delta })];
325
+ case 14:
326
+ // Yield text_delta event in real-time
327
+ return [4 /*yield*/, _q.sent()];
328
+ case 15:
329
+ // Yield text_delta event in real-time
330
+ _q.sent();
331
+ return [3 /*break*/, 20];
332
+ case 16:
333
+ toolCallsFromStream.push(chunk.toolCall);
334
+ return [3 /*break*/, 20];
335
+ case 17:
336
+ usage = chunk.usage;
337
+ totalInputTokens += chunk.usage.inputTokens;
338
+ totalOutputTokens += chunk.usage.outputTokens;
339
+ totalCachedInputTokens += chunk.usage.cachedInputTokens || 0;
340
+ totalCacheCreationInputTokens += chunk.usage.cacheCreationInputTokens || 0;
341
+ return [3 /*break*/, 20];
342
+ case 18:
343
+ // Merge provider metadata (e.g., responseId for continuation)
344
+ providerMetadata = __assign(__assign({}, providerMetadata), chunk.metadata);
345
+ finalProviderMetadata = __assign(__assign({}, finalProviderMetadata), chunk.metadata);
346
+ return [3 /*break*/, 20];
347
+ case 19:
348
+ stopReason = chunk.stopReason;
349
+ return [3 /*break*/, 20];
350
+ case 20:
351
+ _k = true;
352
+ return [3 /*break*/, 11];
353
+ case 21: return [3 /*break*/, 28];
354
+ case 22:
355
+ e_1_1 = _q.sent();
356
+ e_1 = { error: e_1_1 };
357
+ return [3 /*break*/, 28];
358
+ case 23:
359
+ _q.trys.push([23, , 26, 27]);
360
+ if (!(!_k && !_b && (_c = llmStream_1.return))) return [3 /*break*/, 25];
361
+ return [4 /*yield*/, __await(_c.call(llmStream_1))];
362
+ case 24:
363
+ _q.sent();
364
+ _q.label = 25;
365
+ case 25: return [3 /*break*/, 27];
366
+ case 26:
367
+ if (e_1) throw e_1.error;
368
+ return [7 /*endfinally*/];
369
+ case 27: return [7 /*endfinally*/];
370
+ case 28:
371
+ llmResponse = {
372
+ textContent: textContent || undefined,
373
+ toolCalls: toolCallsFromStream,
374
+ usage: usage,
375
+ stopReason: stopReason,
376
+ };
377
+ FlinkLog_1.log.debug("[Agent:".concat(this_1.agentName, "] Step ").concat(step, " - LLM Response:"), {
378
+ textLength: ((_g = llmResponse.textContent) === null || _g === void 0 ? void 0 : _g.length) || 0,
379
+ textPreview: ((_h = llmResponse.textContent) === null || _h === void 0 ? void 0 : _h.substring(0, 200)) + (llmResponse.textContent && llmResponse.textContent.length > 200 ? "..." : ""),
380
+ toolCallsCount: llmResponse.toolCalls.length,
381
+ toolCalls: llmResponse.toolCalls.map(function (tc) { return ({
382
+ name: tc.name,
383
+ inputKeys: Object.keys(tc.input),
384
+ input: tc.input,
385
+ }); }),
386
+ stopReason: llmResponse.stopReason,
387
+ usage: llmResponse.usage,
388
+ });
389
+ // Extract text response
390
+ if (llmResponse.textContent) {
391
+ finalMessage = llmResponse.textContent;
392
+ }
393
+ assistantContent = [];
394
+ if (llmResponse.textContent) {
395
+ assistantContent.push({
396
+ type: "text",
397
+ text: llmResponse.textContent,
398
+ });
399
+ }
400
+ for (_i = 0, _m = llmResponse.toolCalls; _i < _m.length; _i++) {
401
+ toolCall = _m[_i];
402
+ assistantContent.push({
403
+ type: "tool_use",
404
+ id: toolCall.id,
405
+ name: toolCall.name,
406
+ input: toolCall.input,
407
+ });
408
+ }
409
+ messages.push({
410
+ role: "assistant",
411
+ content: assistantContent,
412
+ });
413
+ if (!(llmResponse.toolCalls.length === 0)) return [3 /*break*/, 31];
414
+ if (!this_1.agentProps.onStep) return [3 /*break*/, 30];
415
+ stepContext = __assign(__assign({}, execContext), { step: step, maxSteps: maxSteps, messages: __spreadArray([], messages, true) });
416
+ return [4 /*yield*/, __await(this_1.agentProps.onStep(stepContext))];
417
+ case 29:
418
+ _q.sent();
419
+ _q.label = 30;
420
+ case 30:
421
+ // Dispatch observer onStep (no tool calls executed this step)
422
+ this_1.safeDispatch("onStep", function () {
423
+ var _a, _b;
424
+ return (_b = (_a = _this.observer) === null || _a === void 0 ? void 0 : _a.onStep) === null || _b === void 0 ? void 0 : _b.call(_a, {
425
+ runId: runId,
426
+ agentId: agentId,
427
+ step: step,
428
+ maxSteps: maxSteps,
429
+ messages: __spreadArray([], messages, true),
430
+ assistantText: llmResponse.textContent,
431
+ toolCalls: toolCalls.slice(toolCallsBeforeStep),
432
+ usage: usage,
433
+ context: execContext,
434
+ });
435
+ });
436
+ return [2 /*return*/, "break"];
437
+ case 31:
438
+ toolResults = [];
439
+ _o = 0, _p = llmResponse.toolCalls;
440
+ _q.label = 32;
441
+ case 32:
442
+ if (!(_o < _p.length)) return [3 /*break*/, 43];
443
+ toolCall = _p[_o];
444
+ toolExecutor = this_1.tools.get(toolCall.name);
445
+ toolOutput = void 0;
446
+ toolError = void 0;
447
+ FlinkLog_1.log.debug("[Agent:".concat(this_1.agentName, "] Executing tool '").concat(toolCall.name, "':"), {
448
+ input: toolCall.input,
449
+ inputSize: JSON.stringify(toolCall.input).length,
450
+ });
451
+ _q.label = 33;
452
+ case 33:
453
+ _q.trys.push([33, 39, , 42]);
454
+ if (!toolExecutor) {
455
+ throw new Error("Tool ".concat(toolCall.name, " not found"));
456
+ }
457
+ return [4 /*yield*/, __await({
458
+ type: "tool_call_start",
459
+ toolCall: {
460
+ id: toolCall.id,
461
+ name: toolCall.name,
462
+ input: toolCall.input,
463
+ },
464
+ })];
465
+ case 34:
466
+ // Yield tool_call_start event
467
+ return [4 /*yield*/, _q.sent()];
468
+ case 35:
469
+ // Yield tool_call_start event
470
+ _q.sent();
471
+ return [4 /*yield*/, __await(toolExecutor.execute(toolCall.input, {
472
+ user: input.user,
473
+ permissions: input.userPermissions,
474
+ conversationContext: input.conversationContext,
475
+ }))];
476
+ case 36:
477
+ toolResult = _q.sent();
478
+ formattedResult = toolExecutor.formatResultForAI(toolResult);
479
+ toolResults.push({
480
+ type: "tool_result",
481
+ tool_use_id: toolCall.id,
482
+ content: formattedResult,
483
+ is_error: !toolResult.success,
484
+ });
485
+ return [4 /*yield*/, __await({
486
+ type: "tool_call_result",
487
+ toolCall: {
488
+ id: toolCall.id,
489
+ name: toolCall.name,
490
+ input: toolCall.input,
491
+ },
492
+ output: toolResult.success ? toolResult.data : null,
493
+ error: toolResult.success ? undefined : toolResult.error,
494
+ })];
495
+ case 37:
496
+ // Yield tool_call_result event
497
+ return [4 /*yield*/, _q.sent()];
498
+ case 38:
499
+ // Yield tool_call_result event
500
+ _q.sent();
501
+ toolCalls.push({
502
+ name: toolCall.name,
503
+ input: toolCall.input,
504
+ output: toolResult.success ? toolResult.data : null,
505
+ error: toolResult.success ? undefined : toolResult.error,
506
+ });
507
+ FlinkLog_1.log.debug("[Agent:".concat(this_1.agentName, "] Tool '").concat(toolCall.name, "' ").concat(toolResult.success ? "succeeded" : "failed", ":"), {
508
+ success: toolResult.success,
509
+ outputSize: toolResult.success ? JSON.stringify(toolResult.data).length : 0,
510
+ outputPreview: toolResult.success
511
+ ? JSON.stringify(toolResult.data).substring(0, 200) + (JSON.stringify(toolResult.data).length > 200 ? "..." : "")
512
+ : toolResult.error,
513
+ code: toolResult.code,
514
+ });
515
+ if (!toolResult.success) {
516
+ FlinkLog_1.log.warn("Tool ".concat(toolCall.name, " returned error:"), toolResult.error);
517
+ }
518
+ return [3 /*break*/, 42];
519
+ case 39:
520
+ err_3 = _q.sent();
521
+ // Unexpected errors (not from tool itself)
522
+ toolError = err_3.message;
523
+ return [4 /*yield*/, __await({
524
+ type: "tool_call_result",
525
+ toolCall: {
526
+ id: toolCall.id,
527
+ name: toolCall.name,
528
+ input: toolCall.input,
529
+ },
530
+ output: null,
531
+ error: toolError,
532
+ })];
533
+ case 40:
534
+ // Yield tool_call_result with error
535
+ return [4 /*yield*/, _q.sent()];
536
+ case 41:
537
+ // Yield tool_call_result with error
538
+ _q.sent();
539
+ toolResults.push({
540
+ type: "tool_result",
541
+ tool_use_id: toolCall.id,
542
+ content: "Error: ".concat(err_3.message),
543
+ is_error: true,
544
+ });
545
+ toolCalls.push({
546
+ name: toolCall.name,
547
+ input: toolCall.input,
548
+ output: null,
549
+ error: toolError,
550
+ });
551
+ FlinkLog_1.log.error("Tool ".concat(toolCall.name, " execution failed:"), err_3.message);
552
+ return [3 /*break*/, 42];
553
+ case 42:
554
+ _o++;
555
+ return [3 /*break*/, 32];
556
+ case 43:
557
+ // Add tool results to conversation
558
+ messages.push({
559
+ role: "user",
560
+ content: toolResults,
561
+ });
562
+ if (!this_1.agentProps.onStep) return [3 /*break*/, 45];
563
+ stepContext = __assign(__assign({}, execContext), { step: step, maxSteps: maxSteps, messages: __spreadArray([], messages, true) });
564
+ return [4 /*yield*/, __await(this_1.agentProps.onStep(stepContext))];
565
+ case 44:
566
+ _q.sent();
567
+ _q.label = 45;
568
+ case 45:
569
+ // Dispatch observer onStep with per-step tool calls slice
570
+ this_1.safeDispatch("onStep", function () {
571
+ var _a, _b;
572
+ return (_b = (_a = _this.observer) === null || _a === void 0 ? void 0 : _a.onStep) === null || _b === void 0 ? void 0 : _b.call(_a, {
573
+ runId: runId,
574
+ agentId: agentId,
575
+ step: step,
576
+ maxSteps: maxSteps,
577
+ messages: __spreadArray([], messages, true),
578
+ assistantText: llmResponse.textContent,
579
+ toolCalls: toolCalls.slice(toolCallsBeforeStep),
580
+ usage: usage,
581
+ context: execContext,
582
+ });
583
+ });
584
+ return [2 /*return*/];
585
+ }
586
+ });
587
+ };
588
+ this_1 = this;
589
+ _j.label = 8;
168
590
  case 8:
169
- availableTools = _o.sent();
170
- if (!this.agentProps.shouldCompact) return [3 /*break*/, 16];
171
- _o.label = 9;
591
+ if (!(step < maxSteps)) return [3 /*break*/, 10];
592
+ return [5 /*yield**/, _loop_1()];
172
593
  case 9:
173
- _o.trys.push([9, 15, , 16]);
174
- return [4 /*yield*/, __await(this.agentProps.shouldCompact(messages, step))];
594
+ state_1 = _j.sent();
595
+ if (state_1 === "break")
596
+ return [3 /*break*/, 10];
597
+ return [3 /*break*/, 8];
175
598
  case 10:
176
- needsCompaction = _o.sent();
177
- if (!needsCompaction) return [3 /*break*/, 14];
178
- beforeCount = messages.length;
179
- originalMessages = messages;
180
- compactedMessages = void 0;
181
- if (!this.agentProps.compactHistory) return [3 /*break*/, 12];
182
- return [4 /*yield*/, __await(this.agentProps.compactHistory(messages, step))];
183
- case 11:
184
- compactedMessages = _o.sent();
185
- return [3 /*break*/, 13];
186
- case 12:
187
- // Default strategy: sliding window keeping last 10 messages
188
- compactedMessages = messages.slice(-10);
189
- _o.label = 13;
190
- case 13:
191
- // Validation: ensure compacted array is not empty
192
- if (!compactedMessages || compactedMessages.length === 0) {
193
- throw new Error("compactHistory must return at least one message");
194
- }
195
- // Apply compaction
196
- messages = compactedMessages;
197
- // Log compaction for debugging
198
- FlinkLog_1.log.debug("[Agent:".concat(this.agentName, "] Step ").concat(step, ": Compacted ").concat(beforeCount, " messages \u2192 ").concat(messages.length));
199
- FlinkLog_1.log.debug("[Agent:".concat(this.agentName, "] Compacted messages:"), {
200
- messageCount: messages.length,
201
- messages: messages.map(function (m) { return ({
202
- role: m.role,
203
- contentPreview: typeof m.content === "string"
204
- ? m.content.substring(0, 100) + (m.content.length > 100 ? "..." : "")
205
- : "".concat(m.content.length, " blocks"),
206
- }); }),
207
- });
208
- _o.label = 14;
209
- case 14: return [3 /*break*/, 16];
210
- case 15:
211
- error_1 = _o.sent();
212
- // Log error but don't fail execution - compaction is optional optimization
213
- FlinkLog_1.log.error("[Agent:".concat(this.agentName, "] Context compaction failed:"), error_1.message);
214
- return [3 /*break*/, 16];
215
- case 16:
216
- FlinkLog_1.log.debug("[Agent:".concat(this.agentName, "] Step ").concat(step, "/").concat(maxSteps, " - Calling LLM with:"), {
217
- instructionsType: typeof this.agentProps.instructions === "function" ? "dynamic-callback" : "static",
218
- messageCount: messages.length,
219
- messages: messages.map(function (m) { return ({
220
- role: m.role,
221
- contentPreview: typeof m.content === "string"
222
- ? m.content.substring(0, 100) + (m.content.length > 100 ? "..." : "")
223
- : "".concat(m.content.length, " blocks"),
224
- }); }),
225
- toolCount: availableTools.length,
226
- tools: availableTools.map(function (t) { return t.name; }),
227
- maxTokens: this.maxTokens,
228
- temperature: this.temperature,
229
- });
230
- llmStream = this.llmAdapter.stream({
231
- instructions: resolvedInstructions,
232
- messages: messages,
233
- tools: availableTools,
234
- maxTokens: this.maxTokens,
235
- temperature: this.temperature,
236
- providerMetadata: input.providerMetadata,
237
- });
238
- textContent = "";
239
- toolCallsFromStream = [];
240
- usage = { inputTokens: 0, outputTokens: 0 };
241
- stopReason = "end_turn";
242
- providerMetadata = {};
243
- _o.label = 17;
244
- case 17:
245
- _o.trys.push([17, 29, 30, 35]);
246
- _b = true, llmStream_1 = (e_1 = void 0, __asyncValues(llmStream));
247
- _o.label = 18;
248
- case 18: return [4 /*yield*/, __await(llmStream_1.next())];
249
- case 19:
250
- if (!(llmStream_1_1 = _o.sent(), _g = llmStream_1_1.done, !_g)) return [3 /*break*/, 28];
251
- _j = llmStream_1_1.value;
252
- _b = false;
253
- chunk = _j;
254
- _c = chunk.type;
255
- switch (_c) {
256
- case "text": return [3 /*break*/, 20];
257
- case "tool_call": return [3 /*break*/, 23];
258
- case "usage": return [3 /*break*/, 24];
259
- case "metadata": return [3 /*break*/, 25];
260
- case "done": return [3 /*break*/, 26];
261
- }
262
- return [3 /*break*/, 27];
263
- case 20:
264
- textContent += chunk.delta;
265
- return [4 /*yield*/, __await({ type: "text_delta", delta: chunk.delta })];
266
- case 21:
267
- // Yield text_delta event in real-time
268
- return [4 /*yield*/, _o.sent()];
269
- case 22:
270
- // Yield text_delta event in real-time
271
- _o.sent();
272
- return [3 /*break*/, 27];
273
- case 23:
274
- toolCallsFromStream.push(chunk.toolCall);
275
- return [3 /*break*/, 27];
276
- case 24:
277
- usage = chunk.usage;
278
- totalInputTokens += chunk.usage.inputTokens;
279
- totalOutputTokens += chunk.usage.outputTokens;
280
- totalCachedInputTokens += chunk.usage.cachedInputTokens || 0;
281
- totalCacheCreationInputTokens += chunk.usage.cacheCreationInputTokens || 0;
282
- return [3 /*break*/, 27];
283
- case 25:
284
- // Merge provider metadata (e.g., responseId for continuation)
285
- providerMetadata = __assign(__assign({}, providerMetadata), chunk.metadata);
286
- finalProviderMetadata = __assign(__assign({}, finalProviderMetadata), chunk.metadata);
287
- return [3 /*break*/, 27];
288
- case 26:
289
- stopReason = chunk.stopReason;
290
- return [3 /*break*/, 27];
291
- case 27:
292
- _b = true;
293
- return [3 /*break*/, 18];
294
- case 28: return [3 /*break*/, 35];
295
- case 29:
296
- e_1_1 = _o.sent();
297
- e_1 = { error: e_1_1 };
298
- return [3 /*break*/, 35];
299
- case 30:
300
- _o.trys.push([30, , 33, 34]);
301
- if (!(!_b && !_g && (_h = llmStream_1.return))) return [3 /*break*/, 32];
302
- return [4 /*yield*/, __await(_h.call(llmStream_1))];
303
- case 31:
304
- _o.sent();
305
- _o.label = 32;
306
- case 32: return [3 /*break*/, 34];
307
- case 33:
308
- if (e_1) throw e_1.error;
309
- return [7 /*endfinally*/];
310
- case 34: return [7 /*endfinally*/];
311
- case 35:
312
- llmResponse = {
313
- textContent: textContent || undefined,
314
- toolCalls: toolCallsFromStream,
315
- usage: usage,
316
- stopReason: stopReason,
317
- };
318
- FlinkLog_1.log.debug("[Agent:".concat(this.agentName, "] Step ").concat(step, " - LLM Response:"), {
319
- textLength: ((_l = llmResponse.textContent) === null || _l === void 0 ? void 0 : _l.length) || 0,
320
- textPreview: ((_m = llmResponse.textContent) === null || _m === void 0 ? void 0 : _m.substring(0, 200)) + (llmResponse.textContent && llmResponse.textContent.length > 200 ? "..." : ""),
321
- toolCallsCount: llmResponse.toolCalls.length,
322
- toolCalls: llmResponse.toolCalls.map(function (tc) { return ({
323
- name: tc.name,
324
- inputKeys: Object.keys(tc.input),
325
- input: tc.input,
326
- }); }),
327
- stopReason: llmResponse.stopReason,
328
- usage: llmResponse.usage,
329
- });
330
- // Extract text response
331
- if (llmResponse.textContent) {
332
- finalMessage = llmResponse.textContent;
333
- }
334
- assistantContent = [];
335
- if (llmResponse.textContent) {
336
- assistantContent.push({
337
- type: "text",
338
- text: llmResponse.textContent,
339
- });
340
- }
341
- for (_i = 0, _d = llmResponse.toolCalls; _i < _d.length; _i++) {
342
- toolCall = _d[_i];
343
- assistantContent.push({
344
- type: "tool_use",
345
- id: toolCall.id,
346
- name: toolCall.name,
347
- input: toolCall.input,
348
- });
349
- }
350
- messages.push({
351
- role: "assistant",
352
- content: assistantContent,
353
- });
354
- if (!(llmResponse.toolCalls.length === 0)) return [3 /*break*/, 38];
355
- if (!this.agentProps.onStep) return [3 /*break*/, 37];
356
- stepContext = __assign(__assign({}, execContext), { step: step, maxSteps: maxSteps, messages: __spreadArray([], messages, true) });
357
- return [4 /*yield*/, __await(this.agentProps.onStep(stepContext))];
358
- case 36:
359
- _o.sent();
360
- _o.label = 37;
361
- case 37: return [3 /*break*/, 53]; // No more tool calls - done
362
- case 38:
363
- toolResults = [];
364
- _e = 0, _f = llmResponse.toolCalls;
365
- _o.label = 39;
366
- case 39:
367
- if (!(_e < _f.length)) return [3 /*break*/, 50];
368
- toolCall = _f[_e];
369
- toolExecutor = this.tools.get(toolCall.name);
370
- toolOutput = void 0;
371
- toolError = void 0;
372
- FlinkLog_1.log.debug("[Agent:".concat(this.agentName, "] Executing tool '").concat(toolCall.name, "':"), {
373
- input: toolCall.input,
374
- inputSize: JSON.stringify(toolCall.input).length,
375
- });
376
- _o.label = 40;
377
- case 40:
378
- _o.trys.push([40, 46, , 49]);
379
- if (!toolExecutor) {
380
- throw new Error("Tool ".concat(toolCall.name, " not found"));
381
- }
382
- return [4 /*yield*/, __await({
383
- type: "tool_call_start",
384
- toolCall: {
385
- id: toolCall.id,
386
- name: toolCall.name,
387
- input: toolCall.input,
388
- },
389
- })];
390
- case 41:
391
- // Yield tool_call_start event
392
- return [4 /*yield*/, _o.sent()];
393
- case 42:
394
- // Yield tool_call_start event
395
- _o.sent();
396
- return [4 /*yield*/, __await(toolExecutor.execute(toolCall.input, {
397
- user: input.user,
398
- permissions: input.userPermissions,
399
- conversationContext: input.conversationContext,
400
- }))];
401
- case 43:
402
- toolResult = _o.sent();
403
- formattedResult = toolExecutor.formatResultForAI(toolResult);
404
- toolResults.push({
405
- type: "tool_result",
406
- tool_use_id: toolCall.id,
407
- content: formattedResult,
408
- is_error: !toolResult.success,
409
- });
410
- return [4 /*yield*/, __await({
411
- type: "tool_call_result",
412
- toolCall: {
413
- id: toolCall.id,
414
- name: toolCall.name,
415
- input: toolCall.input,
416
- },
417
- output: toolResult.success ? toolResult.data : null,
418
- error: toolResult.success ? undefined : toolResult.error,
419
- })];
420
- case 44:
421
- // Yield tool_call_result event
422
- return [4 /*yield*/, _o.sent()];
423
- case 45:
424
- // Yield tool_call_result event
425
- _o.sent();
426
- toolCalls.push({
427
- name: toolCall.name,
428
- input: toolCall.input,
429
- output: toolResult.success ? toolResult.data : null,
430
- error: toolResult.success ? undefined : toolResult.error,
431
- });
432
- FlinkLog_1.log.debug("[Agent:".concat(this.agentName, "] Tool '").concat(toolCall.name, "' ").concat(toolResult.success ? "succeeded" : "failed", ":"), {
433
- success: toolResult.success,
434
- outputSize: toolResult.success ? JSON.stringify(toolResult.data).length : 0,
435
- outputPreview: toolResult.success
436
- ? JSON.stringify(toolResult.data).substring(0, 200) + (JSON.stringify(toolResult.data).length > 200 ? "..." : "")
437
- : toolResult.error,
438
- code: toolResult.code,
439
- });
440
- if (!toolResult.success) {
441
- FlinkLog_1.log.warn("Tool ".concat(toolCall.name, " returned error:"), toolResult.error);
442
- }
443
- return [3 /*break*/, 49];
444
- case 46:
445
- err_2 = _o.sent();
446
- // Unexpected errors (not from tool itself)
447
- toolError = err_2.message;
448
- return [4 /*yield*/, __await({
449
- type: "tool_call_result",
450
- toolCall: {
451
- id: toolCall.id,
452
- name: toolCall.name,
453
- input: toolCall.input,
454
- },
455
- output: null,
456
- error: toolError,
457
- })];
458
- case 47:
459
- // Yield tool_call_result with error
460
- return [4 /*yield*/, _o.sent()];
461
- case 48:
462
- // Yield tool_call_result with error
463
- _o.sent();
464
- toolResults.push({
465
- type: "tool_result",
466
- tool_use_id: toolCall.id,
467
- content: "Error: ".concat(err_2.message),
468
- is_error: true,
469
- });
470
- toolCalls.push({
471
- name: toolCall.name,
472
- input: toolCall.input,
473
- output: null,
474
- error: toolError,
475
- });
476
- FlinkLog_1.log.error("Tool ".concat(toolCall.name, " execution failed:"), err_2.message);
477
- return [3 /*break*/, 49];
478
- case 49:
479
- _e++;
480
- return [3 /*break*/, 39];
481
- case 50:
482
- // Add tool results to conversation
483
- messages.push({
484
- role: "user",
485
- content: toolResults,
486
- });
487
- if (!this.agentProps.onStep) return [3 /*break*/, 52];
488
- stepContext = __assign(__assign({}, execContext), { step: step, maxSteps: maxSteps, messages: __spreadArray([], messages, true) });
489
- return [4 /*yield*/, __await(this.agentProps.onStep(stepContext))];
490
- case 51:
491
- _o.sent();
492
- _o.label = 52;
493
- case 52: return [3 /*break*/, 7];
494
- case 53:
495
599
  if (step >= maxSteps && toolCalls.length > 0) {
496
600
  stoppedEarly = true;
497
601
  FlinkLog_1.log.warn("Agent ".concat(this.agentName || "unknown", " stopped early after ").concat(maxSteps, " steps"));
498
602
  }
499
- result = {
500
- message: finalMessage,
501
- toolCalls: toolCalls,
502
- stepsUsed: step,
503
- stoppedEarly: stoppedEarly,
504
- usage: __assign(__assign({ inputTokens: totalInputTokens, outputTokens: totalOutputTokens }, (totalCachedInputTokens > 0 && { cachedInputTokens: totalCachedInputTokens })), (totalCacheCreationInputTokens > 0 && { cacheCreationInputTokens: totalCacheCreationInputTokens })),
505
- providerMetadata: Object.keys(finalProviderMetadata).length > 0 ? finalProviderMetadata : undefined,
506
- };
507
- if (!this.agentProps.afterRun) return [3 /*break*/, 55];
508
- finishContext = __assign(__assign({}, execContext), { messages: __spreadArray([], messages, true), result: result });
509
- return [4 /*yield*/, __await(this.agentProps.afterRun(result, finishContext))];
510
- case 54:
511
- _o.sent();
512
- _o.label = 55;
513
- case 55: return [4 /*yield*/, __await({ type: "complete", result: result })];
514
- case 56:
603
+ result_1 = buildResult();
604
+ if (!this.agentProps.afterRun) return [3 /*break*/, 12];
605
+ finishContext = __assign(__assign({}, execContext), { messages: __spreadArray([], messages, true), result: result_1 });
606
+ return [4 /*yield*/, __await(this.agentProps.afterRun(result_1, finishContext))];
607
+ case 11:
608
+ _j.sent();
609
+ _j.label = 12;
610
+ case 12:
611
+ // Dispatch observer onFinish (success path)
612
+ this.safeDispatch("onFinish", function () {
613
+ var _a, _b;
614
+ return (_b = (_a = _this.observer) === null || _a === void 0 ? void 0 : _a.onFinish) === null || _b === void 0 ? void 0 : _b.call(_a, {
615
+ runId: runId,
616
+ agentId: agentId,
617
+ result: result_1,
618
+ messages: __spreadArray([], messages, true),
619
+ durationMs: Date.now() - runStartedAt,
620
+ context: execContext,
621
+ });
622
+ });
623
+ return [4 /*yield*/, __await({ type: "complete", result: result_1 })];
624
+ case 13:
515
625
  // Phase 1: Yield only complete event
516
626
  // Phase 2: Will yield text_delta and tool events during loop
517
- return [4 /*yield*/, _o.sent()];
518
- case 57:
627
+ return [4 /*yield*/, _j.sent()];
628
+ case 14:
519
629
  // Phase 1: Yield only complete event
520
630
  // Phase 2: Will yield text_delta and tool events during loop
521
- _o.sent();
522
- return [4 /*yield*/, __await(result)];
523
- case 58: return [2 /*return*/, _o.sent()];
631
+ _j.sent();
632
+ return [4 /*yield*/, __await(result_1)];
633
+ case 15: return [2 /*return*/, _j.sent()];
634
+ case 16:
635
+ err_2 = _j.sent();
636
+ // Dispatch observer onFinish with error before rethrowing
637
+ this.safeDispatch("onFinish", function () {
638
+ var _a, _b;
639
+ return (_b = (_a = _this.observer) === null || _a === void 0 ? void 0 : _a.onFinish) === null || _b === void 0 ? void 0 : _b.call(_a, {
640
+ runId: runId,
641
+ agentId: agentId,
642
+ result: buildResult(),
643
+ messages: __spreadArray([], messages, true),
644
+ durationMs: Date.now() - runStartedAt,
645
+ error: (err_2 === null || err_2 === void 0 ? void 0 : err_2.message) || String(err_2),
646
+ context: execContext,
647
+ });
648
+ });
649
+ throw err_2;
650
+ case 17: return [2 /*return*/];
524
651
  }
525
652
  });
526
653
  });
527
654
  };
655
+ /**
656
+ * Fire-and-forget observer dispatch: catches synchronous throws and
657
+ * rejected promises so observer failures never break agent execution.
658
+ */
659
+ AgentRunner.prototype.safeDispatch = function (eventName, invoke) {
660
+ try {
661
+ var maybePromise = invoke();
662
+ if (maybePromise && typeof maybePromise.then === "function") {
663
+ maybePromise.catch(function (err) {
664
+ observerLog.warn("AgentObserver.".concat(eventName, " threw (async):"), (err === null || err === void 0 ? void 0 : err.message) || err);
665
+ });
666
+ }
667
+ }
668
+ catch (err) {
669
+ observerLog.warn("AgentObserver.".concat(eventName, " threw (sync):"), (err === null || err === void 0 ? void 0 : err.message) || err);
670
+ }
671
+ };
528
672
  /**
529
673
  * Convert Message[] to LLM message format
530
674
  * Supports multi-turn conversations with history