@ai-setting/roy-agent-core 1.7.65 → 1.7.67

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.
Files changed (64) hide show
  1. package/dist/env/agent/agent-component.d.ts +56 -3
  2. package/dist/env/agent/agent-component.js +2 -2
  3. package/dist/env/agent/index.js +2 -2
  4. package/dist/env/agent/types.d.ts +28 -0
  5. package/dist/env/environment.d.ts +13 -0
  6. package/dist/env/event-source/command-card-action.d.ts +105 -0
  7. package/dist/env/event-source/command-cards.d.ts +72 -0
  8. package/dist/env/event-source/command-registry.d.ts +181 -0
  9. package/dist/env/event-source/command-types.d.ts +8 -0
  10. package/dist/env/event-source/event-source-handlers.d.ts +66 -0
  11. package/dist/env/event-source/event-source-handlers.js +7 -4
  12. package/dist/env/event-source/fallback-model-command.d.ts +80 -0
  13. package/dist/env/event-source/index.d.ts +7 -0
  14. package/dist/env/event-source/index.js +48 -7
  15. package/dist/env/event-source/timer-handler.d.ts +93 -1
  16. package/dist/env/index.js +15 -14
  17. package/dist/env/llm/index.js +1 -1
  18. package/dist/env/prompt/index.js +3 -2
  19. package/dist/env/prompt/prompts-index.d.ts +3 -8
  20. package/dist/env/task/delegate/delegate-tool.d.ts +58 -2
  21. package/dist/env/task/delegate/delegate-tool.js +5 -2
  22. package/dist/env/task/delegate/index.js +3 -2
  23. package/dist/env/task/index.js +9 -8
  24. package/dist/env/task/mcp/index.js +3 -2
  25. package/dist/env/task/plugins/__e2e__/laya-completion-e2e.d.ts +16 -0
  26. package/dist/env/task/plugins/index.js +4 -3
  27. package/dist/env/task/plugins/laya-completion-plugin.d.ts +133 -0
  28. package/dist/env/task/plugins/laya-port.d.ts +23 -0
  29. package/dist/env/task/storage/index.js +2 -2
  30. package/dist/env/task/storage/migrations/003_add_process_description.d.ts +1 -1
  31. package/dist/env/task/storage/migrations/log-migration.d.ts +49 -3
  32. package/dist/env/task/task-component.d.ts +43 -0
  33. package/dist/env/task/tools/completion-copy.d.ts +27 -0
  34. package/dist/env/task/tools/index.js +2 -1
  35. package/dist/env/task/tools/operation/create-tool.d.ts +1 -1
  36. package/dist/env/task/tools/operation/index.js +1 -1
  37. package/dist/env/task/tools/operation/operation-types.d.ts +10 -8
  38. package/dist/env/task/types.d.ts +3 -3
  39. package/dist/env/tool/built-in/index.js +2 -2
  40. package/dist/env/tool/built-in/query-background-process-tool.d.ts +10 -0
  41. package/dist/env/tool/index.js +3 -3
  42. package/dist/env/tool/types.d.ts +6 -0
  43. package/dist/index.js +60 -19
  44. package/dist/shared/@ai-setting/{roy-agent-core-rjzdj0xb.js → roy-agent-core-02j24hrg.js} +2 -0
  45. package/dist/shared/@ai-setting/{roy-agent-core-hmdcz3g9.js → roy-agent-core-1k83dq3a.js} +16 -6
  46. package/dist/shared/@ai-setting/{roy-agent-core-e42v9bcq.js → roy-agent-core-1kxf910n.js} +1 -1
  47. package/dist/shared/@ai-setting/{roy-agent-core-amkqnyzy.js → roy-agent-core-58804s3j.js} +10 -0
  48. package/dist/shared/@ai-setting/roy-agent-core-6m4bw8jy.js +6 -0
  49. package/dist/shared/@ai-setting/roy-agent-core-8zas6w5q.js +1083 -0
  50. package/dist/shared/@ai-setting/{roy-agent-core-9bs6xrav.js → roy-agent-core-abqhkbn3.js} +6 -3
  51. package/dist/shared/@ai-setting/{roy-agent-core-f6c0nadn.js → roy-agent-core-b7jbqfsy.js} +25 -11
  52. package/dist/shared/@ai-setting/{roy-agent-core-hjejpcg5.js → roy-agent-core-dnjm17sa.js} +51 -9
  53. package/dist/shared/@ai-setting/{roy-agent-core-t0ktaevq.js → roy-agent-core-h5vmff8w.js} +60 -4
  54. package/dist/shared/@ai-setting/{roy-agent-core-xhrrgfdy.js → roy-agent-core-hfr6bzts.js} +168 -52
  55. package/dist/shared/@ai-setting/{roy-agent-core-18am1h07.js → roy-agent-core-k4ps1hxp.js} +1085 -46
  56. package/dist/shared/@ai-setting/{roy-agent-core-jz8dsypm.js → roy-agent-core-kpg25s2q.js} +1 -1
  57. package/dist/shared/@ai-setting/{roy-agent-core-6masakz4.js → roy-agent-core-ma35jyd9.js} +19 -8
  58. package/dist/shared/@ai-setting/{roy-agent-core-gxzxq1sf.js → roy-agent-core-ntq0gz7q.js} +1 -1
  59. package/dist/shared/@ai-setting/{roy-agent-core-rn57psp0.js → roy-agent-core-p5cz9m8v.js} +3 -3
  60. package/dist/shared/@ai-setting/{roy-agent-core-w07ymg29.js → roy-agent-core-wksgtqf9.js} +1 -1
  61. package/package.json +1 -1
  62. package/dist/shared/@ai-setting/roy-agent-core-6z412atw.js +0 -654
  63. /package/dist/shared/@ai-setting/{roy-agent-core-5enxfga2.js → roy-agent-core-b4x6x4k2.js} +0 -0
  64. /package/dist/shared/@ai-setting/{roy-agent-core-es467wsz.js → roy-agent-core-dt104qa1.js} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  isToolUnavailableError,
3
3
  truncateOutputInline
4
- } from "./roy-agent-core-es467wsz.js";
4
+ } from "./roy-agent-core-dt104qa1.js";
5
5
  import {
6
6
  AgentRegistry
7
7
  } from "./roy-agent-core-07fvy74y.js";
@@ -68,6 +68,8 @@ import {
68
68
 
69
69
  // src/env/agent/agent-component.ts
70
70
  init_logger();
71
+ import fs from "fs/promises";
72
+ import path from "path";
71
73
  import { z } from "zod";
72
74
 
73
75
  // src/env/task/plugins/max-iteration-reminder-plugin.ts
@@ -600,6 +602,7 @@ class AgentComponent extends BaseComponent {
600
602
  doomLoopCaches = new Map;
601
603
  fallbackState = new Map;
602
604
  configComponent;
605
+ skipAbortRunningTasksOnStop = false;
603
606
  configWatcher;
604
607
  messageConverter = new SessionMessageConverter;
605
608
  _constructorConfig;
@@ -622,6 +625,7 @@ class AgentComponent extends BaseComponent {
622
625
  throw new Error("ConfigComponent is required for AgentComponent initialization");
623
626
  }
624
627
  this.configComponent = options.configComponent;
628
+ this.skipAbortRunningTasksOnStop = options.skipAbortRunningTasksOnStop === true;
625
629
  await this.registerConfig(options);
626
630
  await this.initRegistry(options.configComponent);
627
631
  this.setStatus("running");
@@ -794,13 +798,19 @@ class AgentComponent extends BaseComponent {
794
798
  }
795
799
  async onStop() {
796
800
  logger2.info("[AgentComponent] Stopping and cleaning up resources...");
797
- for (const [name, agent] of this.agents) {
798
- if (agent.status === "running" || agent.status === "idle") {
799
- this.abort(name);
800
- logger2.debug(`[AgentComponent] Aborted agent: ${name}`);
801
+ const skipAbort = this.skipAbortRunningTasksOnStop === true;
802
+ if (!skipAbort) {
803
+ for (const [name, agent] of this.agents) {
804
+ if (agent.status === "running" || agent.status === "idle") {
805
+ this.abort(name);
806
+ logger2.debug(`[AgentComponent] Aborted agent: ${name}`);
807
+ }
801
808
  }
809
+ } else {
810
+ logger2.info("[AgentComponent] skipAbortRunningTasksOnStop=true — keeping running agent runs alive");
802
811
  }
803
812
  this.abortControllers.clear();
813
+ this.aborted.clear();
804
814
  this.doomLoopCaches.clear();
805
815
  if (this.configWatcher) {
806
816
  this.configWatcher();
@@ -1125,6 +1135,7 @@ class AgentComponent extends BaseComponent {
1125
1135
  }
1126
1136
  let iteration = 0;
1127
1137
  let finalText;
1138
+ let persistedMessageCount = historyMessageCount;
1128
1139
  while (iteration < agent.config.maxIterations) {
1129
1140
  if (hookCtx._stopped) {
1130
1141
  break;
@@ -1337,6 +1348,17 @@ class AgentComponent extends BaseComponent {
1337
1348
  this.flushPendingFakeUserMessage(hookCtx, pendingFakeUserMessage, iteration);
1338
1349
  }
1339
1350
  await this.executePluginHooks(agent, "agent:on.iteration", hookCtx);
1351
+ if (effectiveContext.persistSession !== false) {
1352
+ const iterNewMessages = hookCtx.messages.slice(persistedMessageCount);
1353
+ if (iterNewMessages.length > 0) {
1354
+ const persisted = await this.recordSessionMessages(effectiveContext.sessionId, iterNewMessages);
1355
+ if (persisted) {
1356
+ persistedMessageCount = hookCtx.messages.length;
1357
+ } else if (effectiveContext.sessionId) {
1358
+ logger2.warn(`[agent.component.run] Iteration ${iteration} session persist failed — ` + `keeping ${iterNewMessages.length} message(s) for the post-loop retry.`);
1359
+ }
1360
+ }
1361
+ }
1340
1362
  }
1341
1363
  } catch (error) {
1342
1364
  logger2.error(`Iteration ${iteration} error`, { error });
@@ -1467,9 +1489,12 @@ class AgentComponent extends BaseComponent {
1467
1489
  if (iteration >= agent.config.maxIterations && !result.finalText) {
1468
1490
  result.finalText = "Maximum iterations reached.";
1469
1491
  }
1470
- const newMessages = hookCtx.messages.slice(historyMessageCount);
1492
+ const newMessages = hookCtx.messages.slice(persistedMessageCount);
1471
1493
  if (effectiveContext.persistSession !== false) {
1472
- await this.recordSessionMessages(effectiveContext.sessionId, newMessages);
1494
+ const finalPersisted = await this.recordSessionMessages(effectiveContext.sessionId, newMessages);
1495
+ if (!finalPersisted && newMessages.length > 0 && effectiveContext.sessionId) {
1496
+ logger2.error(`[agent.component.run] Final session persist FAILED — ${newMessages.length} message(s) were not written to session ${effectiveContext.sessionId}. Session history is now incomplete relative to the LLM context.`);
1497
+ }
1473
1498
  } else {
1474
1499
  logger2.debug(`Skipping session message recording (persistSession=false, sessionId=${effectiveContext.sessionId})`);
1475
1500
  }
@@ -1588,12 +1613,18 @@ class AgentComponent extends BaseComponent {
1588
1613
  const session = await sessionComponent.get(sessionId);
1589
1614
  const existingSnapshot = session?.metadata?.cacheSnapshot;
1590
1615
  if (existingSnapshot && typeof existingSnapshot === "object" && existingSnapshot.systemPrompt) {
1591
- logger2.debug(`[AgentComponent._run] Reusing cacheSnapshot for session ${sessionId} (snapshotAt=${existingSnapshot.snapshotAt})`);
1592
- return {
1593
- snapshot: existingSnapshot,
1594
- systemPromptOverride: existingSnapshot.systemPrompt
1595
- };
1616
+ const stale = await this._isMemorySnapshotStale(existingSnapshot);
1617
+ if (stale) {
1618
+ logger2.info(`[AgentComponent._run] cacheSnapshot for session ${sessionId} is stale (${stale}); recreating`);
1619
+ } else {
1620
+ logger2.debug(`[AgentComponent._run] Reusing cacheSnapshot for session ${sessionId} (snapshotAt=${existingSnapshot.snapshotAt})`);
1621
+ return {
1622
+ snapshot: existingSnapshot,
1623
+ systemPromptOverride: existingSnapshot.systemPrompt
1624
+ };
1625
+ }
1596
1626
  }
1627
+ const memoryStat = await this._collectMemoryStat();
1597
1628
  let resolvedSystemPrompt = initialSystemPrompt;
1598
1629
  if (resolvedSystemPrompt && resolvedSystemPrompt.includes("{{memory}}")) {
1599
1630
  try {
@@ -1612,7 +1643,8 @@ class AgentComponent extends BaseComponent {
1612
1643
  const snapshot = {
1613
1644
  systemPrompt: resolvedSystemPrompt ?? agentConfigSystemPrompt ?? "",
1614
1645
  additionInfo: effectiveContext.additionInfo || "",
1615
- snapshotAt: Date.now()
1646
+ snapshotAt: Date.now(),
1647
+ memoryStat
1616
1648
  };
1617
1649
  try {
1618
1650
  await sessionComponent.update(sessionId, {
@@ -1631,6 +1663,46 @@ class AgentComponent extends BaseComponent {
1631
1663
  return { snapshot: null, systemPromptOverride: undefined };
1632
1664
  }
1633
1665
  }
1666
+ async _isMemorySnapshotStale(snapshot) {
1667
+ const stat = snapshot.memoryStat;
1668
+ if (!stat || typeof stat !== "object") {
1669
+ return "no-memoryStat (legacy snapshot)";
1670
+ }
1671
+ const current = await this._collectMemoryStat();
1672
+ if (current.globalMtime !== stat.globalMtime) {
1673
+ return `global memory.md mtime changed (${stat.globalMtime} -> ${current.globalMtime})`;
1674
+ }
1675
+ if (current.projectMtime !== stat.projectMtime) {
1676
+ return `project memory.md mtime changed (${stat.projectMtime} -> ${current.projectMtime})`;
1677
+ }
1678
+ return null;
1679
+ }
1680
+ async _collectMemoryStat() {
1681
+ const empty = { globalMtime: 0, projectMtime: 0 };
1682
+ try {
1683
+ const memoryComponent = this.env?.getComponent?.("memory");
1684
+ if (!memoryComponent?.getMemoryPaths || !memoryComponent.getMemoryFile) {
1685
+ return empty;
1686
+ }
1687
+ const memoryFile = memoryComponent.getMemoryFile();
1688
+ const paths = memoryComponent.getMemoryPaths();
1689
+ const result = { globalMtime: 0, projectMtime: 0 };
1690
+ for (const p of paths) {
1691
+ const filePath = path.join(p.path, memoryFile);
1692
+ try {
1693
+ const st = await fs.stat(filePath);
1694
+ if (p.type === "global") {
1695
+ result.globalMtime = st.mtimeMs;
1696
+ } else if (p.type === "project") {
1697
+ result.projectMtime = st.mtimeMs;
1698
+ }
1699
+ } catch {}
1700
+ }
1701
+ return result;
1702
+ } catch {
1703
+ return empty;
1704
+ }
1705
+ }
1634
1706
  async _fallbackReplaceMemory(systemPrompt) {
1635
1707
  if (!systemPrompt.includes("{{memory}}"))
1636
1708
  return systemPrompt;
@@ -1688,8 +1760,9 @@ class AgentComponent extends BaseComponent {
1688
1760
  logger2.debug(`[invokeLLM] Calling LLMComponent.invoke with ${convertedMessages.length} messages`);
1689
1761
  const runKey = ctx._runId ?? ctx.context.sessionId ?? "default-run";
1690
1762
  const sticky = this.fallbackState.get(runKey);
1691
- const configuredFallback = this.resolveFallbackModel(ctx.context.fallbackModel);
1763
+ const configuredFallbacks = this.resolveFallbackModels(ctx.context.fallbackModels, ctx.context.fallbackModel);
1692
1764
  const activeModel = sticky?.activeModel ?? ctx.context.model;
1765
+ const pendingFallbacks = sticky ? sticky.remaining : configuredFallbacks.filter((m) => !AgentComponent.sameModel(m, activeModel));
1693
1766
  const invokeWithModel = (model, signal) => llm.invoke({
1694
1767
  messages: convertedMessages,
1695
1768
  tools: ctx.tools.map((t) => ({
@@ -1730,30 +1803,39 @@ class AgentComponent extends BaseComponent {
1730
1803
  if (ctx.context.abort?.aborted) {
1731
1804
  throw error;
1732
1805
  }
1733
- const alreadyDowngraded = sticky?.fallbackModel !== undefined;
1734
- const canFallback = !alreadyDowngraded && !!configuredFallback && !AgentComponent.sameModel(configuredFallback, activeModel) && isFallbackEligibleError(error, true);
1735
- if (!canFallback) {
1806
+ if (pendingFallbacks.length === 0 || !isFallbackEligibleError(error, true)) {
1736
1807
  throw error;
1737
1808
  }
1738
- logger2.warn(`[invokeLLM] primary model "${activeModel ?? "(default)"}" failed with a fallback-eligible error; downgrading to fallback model "${configuredFallback}" for run ${runKey}`);
1739
- this.fallbackState.set(runKey, {
1740
- activeModel: configuredFallback,
1741
- fallbackModel: configuredFallback
1742
- });
1743
- const fallbackAttempt = startAttempt(configuredFallback, "LLM invocation timeout after 300s (fallback)");
1744
- try {
1745
- const result = await fallbackAttempt.promise;
1746
- logger2.info(`[invokeLLM] fallback model "${configuredFallback}" succeeded for run ${runKey}`);
1747
- return this.normalizeLLMOutput(result);
1748
- } catch (fallbackError) {
1749
- fallbackAttempt.cancel();
1750
- if (fallbackError instanceof ContextError) {
1751
- logger2.warn(`[invokeLLM] fallback model "${configuredFallback}" hit a context limit; re-throwing ContextError so the compaction pipeline can handle it`);
1752
- throw fallbackError;
1809
+ for (let i = 0;i < pendingFallbacks.length; i++) {
1810
+ const fallbackModel = pendingFallbacks[i];
1811
+ const remaining = pendingFallbacks.slice(i + 1);
1812
+ logger2.warn(`[invokeLLM] model "${activeModel ?? "(default)"}" failed with a fallback-eligible error; downgrading to fallback model "${fallbackModel}" (${i + 1}/${pendingFallbacks.length}) for run ${runKey}`);
1813
+ this.fallbackState.set(runKey, {
1814
+ activeModel: fallbackModel,
1815
+ remaining
1816
+ });
1817
+ const fallbackAttempt = startAttempt(fallbackModel, "LLM invocation timeout after 300s (fallback)");
1818
+ try {
1819
+ const result = await fallbackAttempt.promise;
1820
+ logger2.info(`[invokeLLM] fallback model "${fallbackModel}" succeeded for run ${runKey}`);
1821
+ return this.normalizeLLMOutput(result);
1822
+ } catch (fallbackError) {
1823
+ fallbackAttempt.cancel();
1824
+ if (fallbackError instanceof ContextError) {
1825
+ logger2.warn(`[invokeLLM] fallback model "${fallbackModel}" hit a context limit; re-throwing ContextError so the compaction pipeline can handle it`);
1826
+ throw fallbackError;
1827
+ }
1828
+ if (ctx.context.abort?.aborted) {
1829
+ throw error;
1830
+ }
1831
+ logger2.error(`[invokeLLM] fallback model "${fallbackModel}" also failed; ` + (remaining.length > 0 ? `trying next fallback model "${remaining[0]}"` : `no more fallback models left; re-throwing the ORIGINAL primary error`), fallbackError);
1832
+ if (remaining.length === 0) {
1833
+ this.fallbackState.delete(runKey);
1834
+ throw error;
1835
+ }
1753
1836
  }
1754
- logger2.error(`[invokeLLM] fallback model "${configuredFallback}" also failed; re-throwing the ORIGINAL primary error`, fallbackError);
1755
- throw error;
1756
1837
  }
1838
+ throw error;
1757
1839
  }
1758
1840
  }
1759
1841
  logger2.warn("[invokeLLM] No LLMComponent available, using mock");
@@ -1762,24 +1844,51 @@ class AgentComponent extends BaseComponent {
1762
1844
  finishReason: "stop"
1763
1845
  };
1764
1846
  }
1765
- resolveFallbackModel(explicit) {
1847
+ resolveFallbackModels(explicitList, explicitSingle) {
1766
1848
  const readConfig = (key) => {
1767
- const raw2 = this.configComponent?.get?.(key);
1768
- if (typeof raw2 !== "string")
1849
+ const raw = this.configComponent?.get?.(key);
1850
+ if (typeof raw !== "string")
1769
1851
  return;
1770
- const trimmed = raw2.trim();
1852
+ const trimmed = raw.trim();
1771
1853
  return trimmed ? trimmed : undefined;
1772
1854
  };
1773
- const raw = explicit?.trim() || readConfig("llm.fallbackModel");
1774
- if (!raw)
1775
- return;
1776
- const parsed = parseFallbackModel(raw);
1777
- if (!parsed?.modelId)
1778
- return;
1779
- if (parsed.providerId)
1780
- return `${parsed.providerId}/${parsed.modelId}`;
1781
- const provider = readConfig("llm.fallbackProvider");
1782
- return provider ? `${provider}/${parsed.modelId}` : parsed.modelId;
1855
+ const normalize = (raw) => {
1856
+ const trimmed = raw.trim();
1857
+ if (!trimmed)
1858
+ return;
1859
+ const parsed = parseFallbackModel(trimmed);
1860
+ if (!parsed?.modelId)
1861
+ return;
1862
+ if (parsed.providerId)
1863
+ return `${parsed.providerId}/${parsed.modelId}`;
1864
+ const provider = readConfig("llm.fallbackProvider");
1865
+ return provider ? `${provider}/${parsed.modelId}` : parsed.modelId;
1866
+ };
1867
+ if (Array.isArray(explicitList)) {
1868
+ const normalized = AgentComponent.dedupeModels(explicitList.map((m) => typeof m === "string" ? normalize(m) : undefined).filter((m) => !!m));
1869
+ return normalized;
1870
+ }
1871
+ if (explicitSingle?.trim()) {
1872
+ const normalized = normalize(explicitSingle);
1873
+ return normalized ? [normalized] : [];
1874
+ }
1875
+ const configuredList = this.configComponent?.get?.("llm.fallbackModels");
1876
+ const configuredItems = Array.isArray(configuredList) ? configuredList : typeof configuredList === "string" ? configuredList.split(",") : [];
1877
+ if (configuredItems.length > 0) {
1878
+ const normalized = AgentComponent.dedupeModels(configuredItems.map((m) => typeof m === "string" ? normalize(m) : undefined).filter((m) => !!m));
1879
+ if (normalized.length > 0)
1880
+ return normalized;
1881
+ }
1882
+ const legacy = readConfig("llm.fallbackModel");
1883
+ if (legacy) {
1884
+ const normalized = normalize(legacy);
1885
+ if (normalized)
1886
+ return [normalized];
1887
+ }
1888
+ return [];
1889
+ }
1890
+ static dedupeModels(models) {
1891
+ return Array.from(new Set(models));
1783
1892
  }
1784
1893
  static sameModel(a, b) {
1785
1894
  const norm = (value) => {
@@ -1857,13 +1966,18 @@ class AgentComponent extends BaseComponent {
1857
1966
  },
1858
1967
  sessionId: toolEventSessionId
1859
1968
  });
1860
- const effectiveRunModel = this.fallbackState.get(ctx._runId ?? ctx.context.sessionId ?? "default-run")?.activeModel ?? ctx.context.model;
1969
+ const runKey = ctx._runId ?? ctx.context.sessionId ?? "default-run";
1970
+ const runFallbackState = this.fallbackState.get(runKey);
1971
+ const effectiveRunModel = runFallbackState?.activeModel ?? ctx.context.model;
1972
+ const effectiveFallbackModels = runFallbackState ? runFallbackState.remaining : this.resolveFallbackModels(ctx.context.fallbackModels, ctx.context.fallbackModel);
1973
+ const fallbackExplicitlySet = Array.isArray(ctx.context.fallbackModels) || ctx.context.fallbackModel !== undefined;
1861
1974
  const toolContext = {
1862
1975
  session_id: ctx.context.sessionId,
1863
1976
  message_id: ctx.context.messageId,
1864
1977
  abort: ctx.context.abort,
1865
1978
  model: effectiveRunModel,
1866
1979
  fallbackModel: ctx.context.fallbackModel,
1980
+ ...effectiveFallbackModels.length > 0 ? { fallbackModels: effectiveFallbackModels } : fallbackExplicitlySet ? { fallbackModels: [] } : {},
1867
1981
  workdir: ctx.context.metadata?.workdir,
1868
1982
  metadata: ctx.context.metadata
1869
1983
  };
@@ -2011,14 +2125,14 @@ class AgentComponent extends BaseComponent {
2011
2125
  }
2012
2126
  async recordSessionMessages(sessionId, allMessages = []) {
2013
2127
  if (!sessionId) {
2014
- return;
2128
+ return false;
2015
2129
  }
2016
2130
  let filtered;
2017
2131
  try {
2018
2132
  const sessionComponent = this.env.getComponent("session");
2019
2133
  if (!sessionComponent) {
2020
2134
  logger2.warn("SessionComponent not found, skipping session recording");
2021
- return;
2135
+ return false;
2022
2136
  }
2023
2137
  filtered = [];
2024
2138
  for (const msg of allMessages) {
@@ -2036,9 +2150,10 @@ class AgentComponent extends BaseComponent {
2036
2150
  filtered.push(this.messageConverter.fromModelMessage(msg, { sessionID: sessionId }));
2037
2151
  }
2038
2152
  if (filtered.length === 0) {
2039
- return;
2153
+ return true;
2040
2154
  }
2041
2155
  await sessionComponent.addMessages(sessionId, filtered);
2156
+ return true;
2042
2157
  } catch (err) {
2043
2158
  const kind = err && typeof err === "object" && "kind" in err ? err.kind : undefined;
2044
2159
  if (kind === "lock_exhausted") {
@@ -2046,6 +2161,7 @@ class AgentComponent extends BaseComponent {
2046
2161
  } else {
2047
2162
  logger2.error(`[recordSessionMessages] Failed to record session messages for ${sessionId}: ${err}`);
2048
2163
  }
2164
+ return false;
2049
2165
  }
2050
2166
  }
2051
2167
  isEmptyMessage(content) {