@bubblelab/bubble-core 0.1.197 → 0.1.199

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.
@@ -701,7 +701,14 @@ export declare class AIAgentBubble extends ServiceBubble<AIAgentParamsParsed, AI
701
701
  private shouldStopAfterTools;
702
702
  private shouldContinueToAgent;
703
703
  private rescueAttempts;
704
+ /** Current graph messages — kept in sync by executeToolsWithHooks so that
705
+ * the use-capability tool can snapshot master state before delegation. */
706
+ private _currentGraphMessages;
707
+ /** Emit a trace event via executionMeta._onTrace (if wired by the host). */
708
+ private _trace;
704
709
  private static readonly MAX_RESCUE_ATTEMPTS;
710
+ /** Max characters for a single tool result before truncation (~50k chars ≈ ~12k tokens). */
711
+ private static readonly MAX_TOOL_RESULT_CHARS;
705
712
  constructor(params?: AIAgentParams, context?: BubbleContext, instanceId?: string);
706
713
  testCredential(): Promise<boolean>;
707
714
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ai-agent.d.ts","sourceRoot":"","sources":["../../../src/bubbles/service-bubble/ai-agent.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ai-agent.d.ts","sourceRoot":"","sources":["../../../src/bubbles/service-bubble/ai-agent.ts"],"names":[],"mappings":"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"}
@@ -309,7 +309,19 @@ export class AIAgentBubble extends ServiceBubble {
309
309
  shouldStopAfterTools = false;
310
310
  shouldContinueToAgent = false;
311
311
  rescueAttempts = 0;
312
+ /** Current graph messages — kept in sync by executeToolsWithHooks so that
313
+ * the use-capability tool can snapshot master state before delegation. */
314
+ _currentGraphMessages = [];
315
+ /** Emit a trace event via executionMeta._onTrace (if wired by the host). */
316
+ _trace(source, message, data) {
317
+ const onTrace = this.context?.executionMeta?._onTrace;
318
+ if (typeof onTrace === 'function') {
319
+ onTrace(source, message, data);
320
+ }
321
+ }
312
322
  static MAX_RESCUE_ATTEMPTS = 1;
323
+ /** Max characters for a single tool result before truncation (~50k chars ≈ ~12k tokens). */
324
+ static MAX_TOOL_RESULT_CHARS = 50_000;
313
325
  constructor(params = {
314
326
  message: 'Hello, how are you?',
315
327
  systemPrompt: 'You are a helpful AI assistant',
@@ -404,24 +416,40 @@ export class AIAgentBubble extends ServiceBubble {
404
416
  await applyCapabilityPreprocessing(this.params, this.context, this.resolveCapabilityCredentials.bind(this));
405
417
  // Extract execution metadata (used for conversation history + agent memory)
406
418
  const execMeta = this.context?.executionMeta;
419
+ // Memory injection — tools, prompt, and reflection are built externally (Pro)
420
+ // and passed via executionMeta. This keeps all memory logic out of OSS.
421
+ const isCapabilityAgent = this.params.name?.startsWith('Capability Agent:');
407
422
  // Inject Slack channel context into system prompt
408
- const slackChannel = execMeta?._slackChannel;
409
- if (slackChannel) {
410
- this.params.systemPrompt = `${this.params.systemPrompt}\n**Current Slack channel:** ${slackChannel}`;
423
+ // Skip for capability agents (e.g. memory) — they only need their own prompt
424
+ if (!isCapabilityAgent) {
425
+ const slackChannel = execMeta?._slackChannel;
426
+ if (slackChannel) {
427
+ this.params.systemPrompt = `${this.params.systemPrompt}\n**Current Slack channel:** ${slackChannel}`;
428
+ }
429
+ // Inject bot identity and mention format context
430
+ const botDisplayName = execMeta?._selfBotDisplayName;
431
+ const selfBotUserId = execMeta?._selfBotUserId;
432
+ if (botDisplayName) {
433
+ let botContext = `**Your Slack identity:** ${botDisplayName}`;
434
+ if (selfBotUserId) {
435
+ botContext += ` (user ID: ${selfBotUserId})`;
436
+ }
437
+ botContext += `\nIn Slack messages, \`<@userId>\` is a mention — when you see \`<@${selfBotUserId ?? 'your_id'}>\`, that's someone addressing you.`;
438
+ botContext += `\nConversation messages are prefixed with \`[Name (userId)]\` — this tells you who sent each message. Use these names when addressing users.`;
439
+ this.params.systemPrompt = `${this.params.systemPrompt}\n${botContext}`;
440
+ }
411
441
  }
412
442
  // Auto-inject trigger conversation history if no explicit conversationHistory was provided
413
443
  // This enables Slack thread context to automatically flow into AI agents
444
+ // Skip for capability agents (e.g. memory) — they only need their own prompt
414
445
  // Check both legacy path (context.triggerConversationHistory) and new path (executionMeta)
415
- if (!this.params.conversationHistory?.length) {
446
+ if (!isCapabilityAgent && !this.params.conversationHistory?.length) {
416
447
  const convHistory = execMeta?.triggerConversationHistory ??
417
448
  this.context?.triggerConversationHistory;
418
449
  if (convHistory?.length) {
419
450
  this.params.conversationHistory = convHistory;
420
451
  }
421
452
  }
422
- // Memory injection — tools, prompt, and reflection are built externally (Pro)
423
- // and passed via executionMeta. This keeps all memory logic out of OSS.
424
- const isCapabilityAgent = this.params.name?.startsWith('Capability Agent:');
425
453
  if (!isCapabilityAgent && this.params.memoryEnabled) {
426
454
  const memoryTools = execMeta?.memoryTools;
427
455
  const memorySystemPrompt = execMeta?.memorySystemPrompt;
@@ -1040,6 +1068,22 @@ export class AIAgentBubble extends ServiceBubble {
1040
1068
  const capDef = getCapability(capabilityId);
1041
1069
  if (!capConfig || !capDef)
1042
1070
  return { error: `Capability "${capabilityId}" not found` };
1071
+ // Snapshot master agent state before delegation so that the
1072
+ // subagent's beforeToolCall hook can save both states if an
1073
+ // approval interrupt is triggered (fixes multi-cap state leak).
1074
+ const execMeta = this.context?.executionMeta;
1075
+ if (execMeta && this._currentGraphMessages.length > 0) {
1076
+ const { mapChatMessagesToStoredMessages } = await import('@langchain/core/messages');
1077
+ execMeta._masterAgentSnapshot = {
1078
+ messages: mapChatMessagesToStoredMessages(this._currentGraphMessages),
1079
+ capabilityId,
1080
+ capabilityTask: task,
1081
+ };
1082
+ this._trace('use-capability', `snapshotted master state before delegating`, {
1083
+ masterMsgCount: this._currentGraphMessages.length,
1084
+ capabilityId,
1085
+ });
1086
+ }
1043
1087
  const subAgent = new AIAgentBubble({
1044
1088
  message: task,
1045
1089
  systemPrompt: '', // capability's systemPrompt fills this via beforeAction
@@ -1049,6 +1093,16 @@ export class AIAgentBubble extends ServiceBubble {
1049
1093
  credentials: this.params.credentials,
1050
1094
  }, this.context, `capability-${capabilityId}`);
1051
1095
  const result = await subAgent.action();
1096
+ // Clean up snapshot after delegation completes
1097
+ if (execMeta) {
1098
+ delete execMeta._masterAgentSnapshot;
1099
+ }
1100
+ this._trace('use-capability', `subAgent returned`, {
1101
+ capabilityId,
1102
+ success: result.success,
1103
+ pendingApproval: !!execMeta?._pendingApproval,
1104
+ shouldStopAfterTools: this.shouldStopAfterTools,
1105
+ });
1052
1106
  if (!result.success) {
1053
1107
  return { success: false, error: result.error };
1054
1108
  }
@@ -1252,8 +1306,15 @@ export class AIAgentBubble extends ServiceBubble {
1252
1306
  const toolMessages = [];
1253
1307
  let currentMessages = [...messages];
1254
1308
  let hooksModifiedMessages = false;
1309
+ // Keep master snapshot in sync so use-capability can capture state
1310
+ this._currentGraphMessages = currentMessages;
1255
1311
  // Reset stop flag at the start of tool execution
1256
1312
  this.shouldStopAfterTools = false;
1313
+ this._trace('executeToolsWithHooks', `ENTRY`, {
1314
+ toolCallCount: toolCalls.length,
1315
+ toolCalls: toolCalls.map(tc => `${tc.name}(${tc.id?.slice(-8)})`).join(', '),
1316
+ totalMsgs: messages.length,
1317
+ });
1257
1318
  // Execute each tool call
1258
1319
  for (const toolCall of toolCalls) {
1259
1320
  const tool = tools.find((t) => t.name === toolCall.name);
@@ -1346,11 +1407,17 @@ export class AIAgentBubble extends ServiceBubble {
1346
1407
  }
1347
1408
  // Execute the tool
1348
1409
  const toolOutput = await tool.invoke(toolCall.args);
1349
- // Create tool message
1410
+ // Create tool message — cap result size to avoid blowing up LLM context
1411
+ let toolContent = typeof toolOutput === 'string'
1412
+ ? toolOutput
1413
+ : JSON.stringify(toolOutput);
1414
+ if (toolContent.length > AIAgentBubble.MAX_TOOL_RESULT_CHARS) {
1415
+ toolContent =
1416
+ toolContent.slice(0, AIAgentBubble.MAX_TOOL_RESULT_CHARS) +
1417
+ `\n\n[... truncated — result was ${toolContent.length} chars, limit is ${AIAgentBubble.MAX_TOOL_RESULT_CHARS}]`;
1418
+ }
1350
1419
  const toolMessage = new ToolMessage({
1351
- content: typeof toolOutput === 'string'
1352
- ? toolOutput
1353
- : JSON.stringify(toolOutput),
1420
+ content: toolContent,
1354
1421
  tool_call_id: toolCall.id,
1355
1422
  });
1356
1423
  toolMessages.push(toolMessage);
@@ -1431,6 +1498,17 @@ export class AIAgentBubble extends ServiceBubble {
1431
1498
  async createAgentGraph(llm, tools, systemPrompt) {
1432
1499
  // Define the agent node
1433
1500
  const agentNode = async ({ messages }) => {
1501
+ this._trace('agentNode', `LLM CALL`, {
1502
+ msgCount: messages.length,
1503
+ lastMsgType: messages[messages.length - 1]?._getType(),
1504
+ lastMsgPreview: (() => {
1505
+ const last = messages[messages.length - 1];
1506
+ if (!last)
1507
+ return '';
1508
+ const content = typeof last.content === 'string' ? last.content : JSON.stringify(last.content);
1509
+ return content.slice(0, 120);
1510
+ })(),
1511
+ });
1434
1512
  // systemPrompt is already enhanced by beforeAction() if expectedOutputSchema was provided
1435
1513
  // Use cache_control for Anthropic models to cache the system prompt across iterations
1436
1514
  const isAnthropic = llm instanceof ChatAnthropic;
@@ -1632,25 +1710,36 @@ export class AIAgentBubble extends ServiceBubble {
1632
1710
  const lastAIMessage = aiMessages[aiMessages.length - 1];
1633
1711
  // Check if the last AI message has tool calls
1634
1712
  if (lastAIMessage?.tool_calls && lastAIMessage.tool_calls.length > 0) {
1713
+ this._trace('afterLLMCheck', `→ tools`, {
1714
+ toolCalls: lastAIMessage.tool_calls.map(tc => `${tc.name}(${tc.id?.slice(-8)})`).join(', '),
1715
+ });
1635
1716
  return 'tools';
1636
1717
  }
1718
+ this._trace('afterLLMCheck', `→ __end__ (no tool calls)`);
1637
1719
  return '__end__';
1638
1720
  };
1639
1721
  // Define conditional edge after tools to check if we should stop
1640
1722
  const shouldContinueAfterTools = () => {
1723
+ const execMeta = this.context?.executionMeta;
1724
+ this._trace('shouldContinueAfterTools', `CHECK`, {
1725
+ shouldStop: this.shouldStopAfterTools,
1726
+ pendingApproval: !!execMeta?._pendingApproval,
1727
+ });
1641
1728
  // Check if the afterToolCall hook requested stopping
1642
1729
  if (this.shouldStopAfterTools) {
1730
+ this._trace('shouldContinueAfterTools', `→ __end__ (shouldStopAfterTools)`);
1643
1731
  return '__end__';
1644
1732
  }
1645
1733
  // Check for pending approval signal from sub-agent (shared via executionMeta).
1646
1734
  // In multi-capability mode the master and sub-agent share the same BubbleContext,
1647
1735
  // so a sub-agent setting _pendingApproval is visible here.
1648
- const execMeta = this.context?.executionMeta;
1649
1736
  if (execMeta?._pendingApproval) {
1737
+ this._trace('shouldContinueAfterTools', `→ __end__ (pendingApproval)`);
1650
1738
  this.shouldStopAfterTools = true;
1651
1739
  return '__end__';
1652
1740
  }
1653
1741
  // Otherwise continue back to agent
1742
+ this._trace('shouldContinueAfterTools', `→ agent (continue)`);
1654
1743
  return 'agent';
1655
1744
  };
1656
1745
  // Build the graph
@@ -1685,10 +1774,128 @@ export class AIAgentBubble extends ServiceBubble {
1685
1774
  try {
1686
1775
  // Build messages array starting with conversation history (for KV cache optimization)
1687
1776
  const initialMessages = [];
1777
+ let enrichedMessage;
1688
1778
  // Resume from saved agent state (lossless — preserves tool_calls, etc.)
1689
1779
  const resumeExecMeta = this.context?.executionMeta;
1780
+ const resumeStateV2 = resumeExecMeta?._resumeAgentStateV2;
1690
1781
  const resumeState = resumeExecMeta?._resumeAgentState;
1691
- if (resumeState && Array.isArray(resumeState) && resumeState.length > 0) {
1782
+ // Clear stale _pendingApproval ONLY when actually resuming, so that
1783
+ // non-resume executeAgent calls (e.g. personality reflection) don't
1784
+ // wipe the flag before postFlowAction reads it.
1785
+ if (resumeExecMeta && (resumeStateV2 || resumeState)) {
1786
+ delete resumeExecMeta._pendingApproval;
1787
+ }
1788
+ if (resumeStateV2 && resumeStateV2.__version === 2) {
1789
+ // V2: Multi-cap scoped resume — master and subagent states are separate.
1790
+ // Restore the master's messages, find the pending use-capability call,
1791
+ // inject the subagent's state so it resumes via the V1 path, then
1792
+ // execute the use-capability tool directly.
1793
+ this._trace('v2-resume', `START`, {
1794
+ masterMsgs: resumeStateV2.masterState.length,
1795
+ subagentMsgs: resumeStateV2.subagentState.length,
1796
+ capabilityId: resumeStateV2.capabilityId,
1797
+ task: resumeStateV2.capabilityTask?.slice(0, 80),
1798
+ });
1799
+ const { mapStoredMessagesToChatMessages } = await import('@langchain/core/messages');
1800
+ const masterRestored = mapStoredMessagesToChatMessages(resumeStateV2.masterState);
1801
+ // Collect existing tool results
1802
+ const existingToolResultIds = new Set();
1803
+ for (const msg of masterRestored) {
1804
+ if (msg._getType() === 'tool') {
1805
+ const tm = msg;
1806
+ if (tm.tool_call_id)
1807
+ existingToolResultIds.add(tm.tool_call_id);
1808
+ }
1809
+ }
1810
+ // Build tool lookup for direct execution
1811
+ const toolsByName = new Map();
1812
+ if (tools) {
1813
+ for (const t of tools)
1814
+ toolsByName.set(t.name, t);
1815
+ }
1816
+ // Inject the subagent's state so the use-capability tool's subagent
1817
+ // picks it up via the V1 resume path in its own executeAgent call.
1818
+ // IMPORTANT: Delete _resumeAgentStateV2 BEFORE tool.invoke() so the
1819
+ // subagent doesn't re-enter the V2 path (it shares executionMeta).
1820
+ if (resumeExecMeta) {
1821
+ resumeExecMeta._resumeAgentState = resumeStateV2.subagentState;
1822
+ delete resumeExecMeta._resumeAgentStateV2;
1823
+ }
1824
+ // Repair master messages: find the pending use-capability tool call
1825
+ // and execute it (which re-creates the subagent that resumes via V1).
1826
+ const repairedMessages = [];
1827
+ for (let i = 0; i < masterRestored.length; i++) {
1828
+ repairedMessages.push(masterRestored[i]);
1829
+ const msg = masterRestored[i];
1830
+ if (msg._getType() !== 'ai')
1831
+ continue;
1832
+ const aiMsg = msg;
1833
+ const pendingCalls = aiMsg.tool_calls?.filter((tc) => tc.id && !existingToolResultIds.has(tc.id));
1834
+ if (!pendingCalls?.length)
1835
+ continue;
1836
+ for (const tc of pendingCalls) {
1837
+ if (toolsByName.has(tc.name)) {
1838
+ try {
1839
+ this._trace('v2-resume', `executing tool "${tc.name}"`, {
1840
+ callId: tc.id,
1841
+ args: JSON.stringify(tc.args).slice(0, 200),
1842
+ });
1843
+ const tool = toolsByName.get(tc.name);
1844
+ // Sync _currentGraphMessages so use-capability can snapshot
1845
+ // master state for the subagent's beforeToolCall hook.
1846
+ // Without this, _masterAgentSnapshot is empty during V2 resume
1847
+ // and subsequent approvals fall to the V1 path, corrupting state.
1848
+ this._currentGraphMessages = [...repairedMessages];
1849
+ const result = await tool.invoke(tc.args);
1850
+ let content = typeof result === 'string' ? result : JSON.stringify(result);
1851
+ if (content.length > AIAgentBubble.MAX_TOOL_RESULT_CHARS) {
1852
+ content =
1853
+ content.slice(0, AIAgentBubble.MAX_TOOL_RESULT_CHARS) +
1854
+ `\n\n[... truncated — result was ${content.length} chars, limit is ${AIAgentBubble.MAX_TOOL_RESULT_CHARS}]`;
1855
+ }
1856
+ repairedMessages.push(new ToolMessage({ content, tool_call_id: tc.id }));
1857
+ }
1858
+ catch (err) {
1859
+ console.warn(`[AIAgent] V2 resume: tool execution failed for "${tc.name}":`, err);
1860
+ repairedMessages.push(new ToolMessage({
1861
+ content: `Tool execution failed: ${err instanceof Error ? err.message : String(err)}`,
1862
+ tool_call_id: tc.id,
1863
+ }));
1864
+ }
1865
+ }
1866
+ else {
1867
+ repairedMessages.push(new ToolMessage({
1868
+ content: 'This action has been approved by the user. You may now execute this tool.',
1869
+ tool_call_id: tc.id,
1870
+ }));
1871
+ }
1872
+ existingToolResultIds.add(tc.id);
1873
+ }
1874
+ }
1875
+ // Clean up remaining resume state and pre-approval flag so that
1876
+ // subsequent subagents (created by normal master loop) don't
1877
+ // accidentally pick up stale state.
1878
+ // Note: _resumeAgentStateV2 already deleted above (before tool.invoke).
1879
+ if (resumeExecMeta) {
1880
+ delete resumeExecMeta._resumeAgentState;
1881
+ delete resumeExecMeta._approvedAction;
1882
+ }
1883
+ this._trace('v2-resume', `DONE`, {
1884
+ repairedMessages: repairedMessages.length,
1885
+ types: repairedMessages.map((m) => m._getType()).join(','),
1886
+ pendingApproval: !!resumeExecMeta?._pendingApproval,
1887
+ shouldStopAfterTools: this.shouldStopAfterTools,
1888
+ });
1889
+ // If a new approval was triggered during V2 resume (subagent set _pendingApproval),
1890
+ // we should stop the master loop immediately to avoid re-executing.
1891
+ if (resumeExecMeta?._pendingApproval) {
1892
+ this._trace('v2-resume', `_pendingApproval detected — will stop master loop`);
1893
+ this.shouldStopAfterTools = true;
1894
+ }
1895
+ initialMessages.push(...repairedMessages);
1896
+ }
1897
+ else if (resumeState && Array.isArray(resumeState) && resumeState.length > 0) {
1898
+ this._trace('v1-resume', `restoring ${resumeState.length} messages (single-cap/subagent path)`);
1692
1899
  const { mapStoredMessagesToChatMessages } = await import('@langchain/core/messages');
1693
1900
  const restored = mapStoredMessagesToChatMessages(resumeState);
1694
1901
  // Collect existing tool_call_ids that already have ToolMessage responses
@@ -1740,7 +1947,12 @@ export class AIAgentBubble extends ServiceBubble {
1740
1947
  console.log(`[AIAgent] Resume: executing approved tool "${tc.name}" directly`);
1741
1948
  const tool = toolsByName.get(tc.name);
1742
1949
  const result = await tool.invoke(tc.args);
1743
- const content = typeof result === 'string' ? result : JSON.stringify(result);
1950
+ let content = typeof result === 'string' ? result : JSON.stringify(result);
1951
+ if (content.length > AIAgentBubble.MAX_TOOL_RESULT_CHARS) {
1952
+ content =
1953
+ content.slice(0, AIAgentBubble.MAX_TOOL_RESULT_CHARS) +
1954
+ `\n\n[... truncated — result was ${content.length} chars, limit is ${AIAgentBubble.MAX_TOOL_RESULT_CHARS}]`;
1955
+ }
1744
1956
  repairedMessages.push(new ToolMessage({ content, tool_call_id: tc.id }));
1745
1957
  }
1746
1958
  catch (err) {
@@ -1772,7 +1984,8 @@ export class AIAgentBubble extends ServiceBubble {
1772
1984
  else if (conversationHistory && conversationHistory.length > 0) {
1773
1985
  // Normal path: lossy ConversationMessage[] → BaseMessage[]
1774
1986
  // This enables KV cache optimization by keeping previous turns as separate messages
1775
- // Pop the trigger (last entry) — it will be re-appended as the raw humanMessage
1987
+ // Pop the trigger (last entry) — its enriched content replaces the raw message below
1988
+ const lastHistoryMsg = conversationHistory[conversationHistory.length - 1];
1776
1989
  for (const historyMsg of conversationHistory.slice(0, -1)) {
1777
1990
  switch (historyMsg.role) {
1778
1991
  case 'user':
@@ -1793,13 +2006,20 @@ export class AIAgentBubble extends ServiceBubble {
1793
2006
  break;
1794
2007
  }
1795
2008
  }
2009
+ // Use the enriched content from the last conversation history entry
2010
+ // (includes user name, timezone) instead of the raw trigger message
2011
+ if (lastHistoryMsg.role === 'user') {
2012
+ enrichedMessage = lastHistoryMsg.content;
2013
+ }
1796
2014
  }
1797
2015
  // Create the current human message with text and optional images
2016
+ // Prefer enriched message (with user name/timezone) over raw trigger text
2017
+ const triggerMessage = enrichedMessage ?? message;
1798
2018
  let humanMessage;
1799
2019
  if (images && images.length > 0) {
1800
2020
  console.log('[AIAgent] Creating multimodal message with', images.length, 'images');
1801
2021
  // Create multimodal content array
1802
- const content = [{ type: 'text', text: message }];
2022
+ const content = [{ type: 'text', text: triggerMessage }];
1803
2023
  // Add images to content
1804
2024
  for (const image of images) {
1805
2025
  let imageUrl;
@@ -1843,16 +2063,26 @@ export class AIAgentBubble extends ServiceBubble {
1843
2063
  }
1844
2064
  else {
1845
2065
  // Text-only message
1846
- humanMessage = new HumanMessage(message);
2066
+ humanMessage = new HumanMessage(triggerMessage);
1847
2067
  }
1848
2068
  // In the resume flow the trigger message is already part of the saved
1849
2069
  // state (it was the HumanMessage that started the original execution).
1850
2070
  // Re-appending it causes the LLM to see the same request twice, which
1851
2071
  // triggers a duplicate tool call. Skip it when resuming.
1852
- if (!resumeState) {
2072
+ if (!resumeState && !resumeStateV2) {
1853
2073
  initialMessages.push(humanMessage);
1854
2074
  }
2075
+ this._trace('agent-loop', `STARTING graph.invoke`, {
2076
+ initialMsgCount: initialMessages.length,
2077
+ initialMsgTypes: initialMessages.map((m) => m._getType()).join(','),
2078
+ shouldStopAfterTools: this.shouldStopAfterTools,
2079
+ maxIterations,
2080
+ });
1855
2081
  const result = await graph.invoke({ messages: initialMessages }, { recursionLimit: maxIterations });
2082
+ this._trace('agent-loop', `graph.invoke COMPLETED`, {
2083
+ totalMessages: result.messages.length,
2084
+ pendingApproval: !!this.context?.executionMeta?._pendingApproval,
2085
+ });
1856
2086
  console.log('[AIAgent] Graph execution completed');
1857
2087
  console.log('[AIAgent] Total messages:', result.messages.length);
1858
2088
  iterations = result.messages.length;