@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.
- package/dist/env/agent/agent-component.d.ts +56 -3
- package/dist/env/agent/agent-component.js +2 -2
- package/dist/env/agent/index.js +2 -2
- package/dist/env/agent/types.d.ts +28 -0
- package/dist/env/environment.d.ts +13 -0
- package/dist/env/event-source/command-card-action.d.ts +105 -0
- package/dist/env/event-source/command-cards.d.ts +72 -0
- package/dist/env/event-source/command-registry.d.ts +181 -0
- package/dist/env/event-source/command-types.d.ts +8 -0
- package/dist/env/event-source/event-source-handlers.d.ts +66 -0
- package/dist/env/event-source/event-source-handlers.js +7 -4
- package/dist/env/event-source/fallback-model-command.d.ts +80 -0
- package/dist/env/event-source/index.d.ts +7 -0
- package/dist/env/event-source/index.js +48 -7
- package/dist/env/event-source/timer-handler.d.ts +93 -1
- package/dist/env/index.js +15 -14
- package/dist/env/llm/index.js +1 -1
- package/dist/env/prompt/index.js +3 -2
- package/dist/env/prompt/prompts-index.d.ts +3 -8
- package/dist/env/task/delegate/delegate-tool.d.ts +58 -2
- package/dist/env/task/delegate/delegate-tool.js +5 -2
- package/dist/env/task/delegate/index.js +3 -2
- package/dist/env/task/index.js +9 -8
- package/dist/env/task/mcp/index.js +3 -2
- package/dist/env/task/plugins/__e2e__/laya-completion-e2e.d.ts +16 -0
- package/dist/env/task/plugins/index.js +4 -3
- package/dist/env/task/plugins/laya-completion-plugin.d.ts +133 -0
- package/dist/env/task/plugins/laya-port.d.ts +23 -0
- package/dist/env/task/storage/index.js +2 -2
- package/dist/env/task/storage/migrations/003_add_process_description.d.ts +1 -1
- package/dist/env/task/storage/migrations/log-migration.d.ts +49 -3
- package/dist/env/task/task-component.d.ts +43 -0
- package/dist/env/task/tools/completion-copy.d.ts +27 -0
- package/dist/env/task/tools/index.js +2 -1
- package/dist/env/task/tools/operation/create-tool.d.ts +1 -1
- package/dist/env/task/tools/operation/index.js +1 -1
- package/dist/env/task/tools/operation/operation-types.d.ts +10 -8
- package/dist/env/task/types.d.ts +3 -3
- package/dist/env/tool/built-in/index.js +2 -2
- package/dist/env/tool/built-in/query-background-process-tool.d.ts +10 -0
- package/dist/env/tool/index.js +3 -3
- package/dist/env/tool/types.d.ts +6 -0
- package/dist/index.js +60 -19
- package/dist/shared/@ai-setting/{roy-agent-core-rjzdj0xb.js → roy-agent-core-02j24hrg.js} +2 -0
- package/dist/shared/@ai-setting/{roy-agent-core-hmdcz3g9.js → roy-agent-core-1k83dq3a.js} +16 -6
- package/dist/shared/@ai-setting/{roy-agent-core-e42v9bcq.js → roy-agent-core-1kxf910n.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-amkqnyzy.js → roy-agent-core-58804s3j.js} +10 -0
- package/dist/shared/@ai-setting/roy-agent-core-6m4bw8jy.js +6 -0
- package/dist/shared/@ai-setting/roy-agent-core-8zas6w5q.js +1083 -0
- package/dist/shared/@ai-setting/{roy-agent-core-9bs6xrav.js → roy-agent-core-abqhkbn3.js} +6 -3
- package/dist/shared/@ai-setting/{roy-agent-core-f6c0nadn.js → roy-agent-core-b7jbqfsy.js} +25 -11
- package/dist/shared/@ai-setting/{roy-agent-core-hjejpcg5.js → roy-agent-core-dnjm17sa.js} +51 -9
- package/dist/shared/@ai-setting/{roy-agent-core-t0ktaevq.js → roy-agent-core-h5vmff8w.js} +60 -4
- package/dist/shared/@ai-setting/{roy-agent-core-xhrrgfdy.js → roy-agent-core-hfr6bzts.js} +168 -52
- package/dist/shared/@ai-setting/{roy-agent-core-18am1h07.js → roy-agent-core-k4ps1hxp.js} +1085 -46
- package/dist/shared/@ai-setting/{roy-agent-core-jz8dsypm.js → roy-agent-core-kpg25s2q.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-6masakz4.js → roy-agent-core-ma35jyd9.js} +19 -8
- package/dist/shared/@ai-setting/{roy-agent-core-gxzxq1sf.js → roy-agent-core-ntq0gz7q.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-rn57psp0.js → roy-agent-core-p5cz9m8v.js} +3 -3
- package/dist/shared/@ai-setting/{roy-agent-core-w07ymg29.js → roy-agent-core-wksgtqf9.js} +1 -1
- package/package.json +1 -1
- package/dist/shared/@ai-setting/roy-agent-core-6z412atw.js +0 -654
- /package/dist/shared/@ai-setting/{roy-agent-core-5enxfga2.js → roy-agent-core-b4x6x4k2.js} +0 -0
- /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-
|
|
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
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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(
|
|
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
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
fallbackModel
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
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
|
-
|
|
1847
|
+
resolveFallbackModels(explicitList, explicitSingle) {
|
|
1766
1848
|
const readConfig = (key) => {
|
|
1767
|
-
const
|
|
1768
|
-
if (typeof
|
|
1849
|
+
const raw = this.configComponent?.get?.(key);
|
|
1850
|
+
if (typeof raw !== "string")
|
|
1769
1851
|
return;
|
|
1770
|
-
const trimmed =
|
|
1852
|
+
const trimmed = raw.trim();
|
|
1771
1853
|
return trimmed ? trimmed : undefined;
|
|
1772
1854
|
};
|
|
1773
|
-
const
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
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
|
|
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) {
|