@ai-setting/roy-agent-core 1.5.89 → 1.5.90
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/index.js +3 -3
- package/dist/env/event-source/index.js +8 -4
- package/dist/env/index.js +9 -9
- package/dist/env/llm/index.js +4 -2
- package/dist/env/session/index.js +3 -3
- package/dist/env/session/storage/index.js +2 -2
- package/dist/env/task/plugins/index.js +1 -1
- package/dist/env/workflow/engine/index.js +2 -2
- package/dist/env/workflow/index.js +3 -3
- package/dist/env/workflow/nodes/index.js +1 -1
- package/dist/index.js +119 -14
- package/dist/shared/@ai-setting/{roy-agent-core-r0m0at3x.js → roy-agent-core-0r4ndyn9.js} +119 -7
- package/dist/shared/@ai-setting/{roy-agent-core-fvfc7f6v.js → roy-agent-core-2c8eraxq.js} +62 -8
- package/dist/shared/@ai-setting/{roy-agent-core-h2d1s8yd.js → roy-agent-core-5ykms33a.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-fgpnv7dt.js → roy-agent-core-8zjntsbb.js} +71 -28
- package/dist/shared/@ai-setting/{roy-agent-core-vneyghpg.js → roy-agent-core-ddq5hcp5.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-qhhxx2x2.js → roy-agent-core-ds5f75pg.js} +2 -1
- package/dist/shared/@ai-setting/{roy-agent-core-3f6k060j.js → roy-agent-core-j0107ww1.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-2q7cshpm.js → roy-agent-core-m683wd1n.js} +283 -15
- package/dist/shared/@ai-setting/{roy-agent-core-qbq3jgrn.js → roy-agent-core-rkz8r2sx.js} +1 -1
- package/dist/shared/@ai-setting/{roy-agent-core-c1j7ev4e.js → roy-agent-core-txwf64pd.js} +70 -0
- package/dist/shared/@ai-setting/{roy-agent-core-m3dkyprg.js → roy-agent-core-w0kb72ve.js} +7 -2
- package/dist/shared/@ai-setting/{roy-agent-core-hc20420t.js → roy-agent-core-z240ts1r.js} +27 -3
- package/dist/shared/@ai-setting/{roy-agent-core-q7sqeax6.js → roy-agent-core-zky9jse4.js} +163 -3
- package/package.json +1 -1
- /package/dist/shared/@ai-setting/{roy-agent-core-4f3976cd.js → roy-agent-core-k5hxvaf0.js} +0 -0
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
import {
|
|
7
7
|
MemorySessionStore,
|
|
8
8
|
SQLiteSessionStore
|
|
9
|
-
} from "./roy-agent-core-
|
|
9
|
+
} from "./roy-agent-core-zky9jse4.js";
|
|
10
10
|
import {
|
|
11
11
|
envKeyToConfigKey
|
|
12
12
|
} from "./roy-agent-core-qxhq8ven.js";
|
|
@@ -66,8 +66,38 @@ init_search_query_parser();
|
|
|
66
66
|
import path from "path";
|
|
67
67
|
import { z } from "zod";
|
|
68
68
|
var logger = createLogger("session");
|
|
69
|
+
function sleep(ms) {
|
|
70
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
71
|
+
}
|
|
72
|
+
function isBusyError(err) {
|
|
73
|
+
if (err == null)
|
|
74
|
+
return false;
|
|
75
|
+
const e = err;
|
|
76
|
+
if (typeof e.code === "string") {
|
|
77
|
+
if (/^SQLITE_(BUSY|LOCKED)$/i.test(e.code))
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
if (typeof e.errno === "number" && (e.errno === 5 || e.errno === 6)) {
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
const msg = e.message ?? "";
|
|
84
|
+
return /SQLiteError:\s+(database is locked|database table is locked)/i.test(msg);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
class AddMessageLockExhaustedError extends Error {
|
|
88
|
+
kind = "lock_exhausted";
|
|
89
|
+
attempts;
|
|
90
|
+
cause;
|
|
91
|
+
constructor(attempts, cause) {
|
|
92
|
+
super(`Failed to add message after ${attempts} attempts: ${String(cause)}`);
|
|
93
|
+
this.name = "AddMessageLockExhaustedError";
|
|
94
|
+
this.attempts = attempts;
|
|
95
|
+
this.cause = cause;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
69
98
|
|
|
70
99
|
class SessionComponent extends BaseComponent {
|
|
100
|
+
static BACKOFFS_MS = [50, 100, 200];
|
|
71
101
|
name = "session";
|
|
72
102
|
version = "1.1.0";
|
|
73
103
|
config;
|
|
@@ -323,14 +353,38 @@ class SessionComponent extends BaseComponent {
|
|
|
323
353
|
async addMessage(sessionId, message) {
|
|
324
354
|
const contentPreview = typeof message.content === "string" ? message.content.substring(0, 100) : JSON.stringify(message.content).substring(0, 100);
|
|
325
355
|
logger.info(`[SessionComponent.addMessage] sessionId=${sessionId}, role=${message.role}, content="${contentPreview}"`);
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
356
|
+
return this.addMessageWithRetry(sessionId, message);
|
|
357
|
+
}
|
|
358
|
+
async addMessageWithRetry(sessionId, message) {
|
|
359
|
+
const MAX_ATTEMPTS = SessionComponent.BACKOFFS_MS.length;
|
|
360
|
+
for (let attempt = 0;attempt < MAX_ATTEMPTS; attempt++) {
|
|
361
|
+
try {
|
|
362
|
+
const messageId = await this.store?.addMessage(sessionId, message);
|
|
363
|
+
if (attempt > 0) {
|
|
364
|
+
logger.info(`[SessionComponent.addMessage] Recovered after ${attempt + 1} attempts: messageId=${messageId}`);
|
|
365
|
+
} else {
|
|
366
|
+
logger.info(`[SessionComponent.addMessage] Success: messageId=${messageId}`);
|
|
367
|
+
}
|
|
368
|
+
return messageId;
|
|
369
|
+
} catch (error) {
|
|
370
|
+
if (!isBusyError(error)) {
|
|
371
|
+
logger.error(`[SessionComponent] Failed to add message (non-busy): ${error}`);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
const isLastAttempt = attempt === MAX_ATTEMPTS - 1;
|
|
375
|
+
if (isLastAttempt) {
|
|
376
|
+
logger.error(`[SessionComponent] Failed to add message after ${MAX_ATTEMPTS} attempts (busy): ${error}`);
|
|
377
|
+
throw new AddMessageLockExhaustedError(MAX_ATTEMPTS, error);
|
|
378
|
+
}
|
|
379
|
+
const backoffMs = SessionComponent.BACKOFFS_MS[attempt];
|
|
380
|
+
logger.warn(`[SessionComponent] SQLITE_BUSY on attempt ${attempt + 1}/${MAX_ATTEMPTS}, retrying in ${backoffMs}ms: ${error}`);
|
|
381
|
+
await sleep(backoffMs);
|
|
382
|
+
}
|
|
333
383
|
}
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
async addMessages(sessionId, messages) {
|
|
387
|
+
return this.store?.addMessages(sessionId, messages) ?? [];
|
|
334
388
|
}
|
|
335
389
|
async getMessages(sessionId, options) {
|
|
336
390
|
const messages = await this.store?.getMessages(sessionId, options?.offset, options?.limit);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
withTimeout
|
|
3
|
-
} from "./roy-agent-core-
|
|
3
|
+
} from "./roy-agent-core-0r4ndyn9.js";
|
|
4
4
|
import {
|
|
5
5
|
truncateOutputInline
|
|
6
6
|
} from "./roy-agent-core-hxsbegfc.js";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
} from "./roy-agent-core-ctdhjv68.js";
|
|
17
17
|
import {
|
|
18
18
|
SessionMessageConverter
|
|
19
|
-
} from "./roy-agent-core-
|
|
19
|
+
} from "./roy-agent-core-txwf64pd.js";
|
|
20
20
|
import {
|
|
21
21
|
safeParseToolArgs
|
|
22
22
|
} from "./roy-agent-core-ce10b0ez.js";
|
|
@@ -115,23 +115,53 @@ function toLLMMessage(msg) {
|
|
|
115
115
|
toolName = toolResult?.toolName;
|
|
116
116
|
} else {
|
|
117
117
|
const toolCallParts = msg.content.filter((part) => part.type === "tool-call");
|
|
118
|
-
const
|
|
119
|
-
|
|
118
|
+
const hasMultimodalPart = msg.content.some((part) => part.type === "image" || part.type === "file");
|
|
119
|
+
if (hasMultimodalPart) {
|
|
120
|
+
const llmContentParts = [];
|
|
121
|
+
for (const part of msg.content) {
|
|
122
|
+
if (part.type === "text") {
|
|
123
|
+
llmContentParts.push({ type: "text", text: part.text || "" });
|
|
124
|
+
} else if (part.type === "image") {
|
|
125
|
+
llmContentParts.push({ type: "image", image: part.image });
|
|
126
|
+
} else if (part.type === "file") {
|
|
127
|
+
llmContentParts.push({
|
|
128
|
+
type: "file",
|
|
129
|
+
file: part.data ?? part.file,
|
|
130
|
+
mediaType: part.mediaType || "application/octet-stream"
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (msg.role === "assistant" && toolCallParts.length > 0) {
|
|
135
|
+
for (const part of toolCallParts) {
|
|
136
|
+
const argsString = typeof part.input === "string" ? part.input : JSON.stringify(part.input || {});
|
|
137
|
+
toolCalls = (toolCalls ?? []).concat([{
|
|
138
|
+
id: part.toolCallId,
|
|
139
|
+
name: part.toolName || "unknown",
|
|
140
|
+
arguments: argsString,
|
|
141
|
+
function: { name: part.toolName || "unknown", arguments: argsString }
|
|
142
|
+
}]);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
content = llmContentParts;
|
|
146
|
+
} else {
|
|
147
|
+
const contentParts = msg.content.filter((part) => part.type === "text").map((part) => part.text || "");
|
|
148
|
+
content = contentParts.join(`
|
|
120
149
|
`);
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
name: toolName2,
|
|
128
|
-
arguments: argsString,
|
|
129
|
-
function: {
|
|
150
|
+
if (msg.role === "assistant" && toolCallParts.length > 0) {
|
|
151
|
+
toolCalls = toolCallParts.map((part) => {
|
|
152
|
+
const argsString = typeof part.input === "string" ? part.input : JSON.stringify(part.input || {});
|
|
153
|
+
const toolName2 = part.toolName || "unknown";
|
|
154
|
+
return {
|
|
155
|
+
id: part.toolCallId,
|
|
130
156
|
name: toolName2,
|
|
131
|
-
arguments: argsString
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
157
|
+
arguments: argsString,
|
|
158
|
+
function: {
|
|
159
|
+
name: toolName2,
|
|
160
|
+
arguments: argsString
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
});
|
|
164
|
+
}
|
|
135
165
|
}
|
|
136
166
|
}
|
|
137
167
|
} else {
|
|
@@ -550,7 +580,8 @@ class AgentComponent extends BaseComponent {
|
|
|
550
580
|
throw new Error(`Agent not found: ${agentName}`);
|
|
551
581
|
}
|
|
552
582
|
const runId = `${agentName}:${++this.runCounter}`;
|
|
553
|
-
|
|
583
|
+
const querySummary = typeof query === "string" ? query.substring(0, 100) : query.filter((p) => p.type === "text").map((p) => p.text).join(" ").substring(0, 100) || "[multimodal query]";
|
|
584
|
+
logger.info(`Starting agent run: ${agentName} (runId=${runId})`, { query: querySummary });
|
|
554
585
|
agent.status = "running";
|
|
555
586
|
this.aborted.set(runId, false);
|
|
556
587
|
const abortController = new AbortController;
|
|
@@ -559,24 +590,25 @@ class AgentComponent extends BaseComponent {
|
|
|
559
590
|
this.doomLoopCaches.set(runId, new Map);
|
|
560
591
|
}
|
|
561
592
|
await this.resolveSystemPrompt(agent, agentName);
|
|
593
|
+
let resolvedSystemPrompt;
|
|
562
594
|
if (agent.config.systemPrompt) {
|
|
563
|
-
|
|
564
|
-
if (
|
|
595
|
+
resolvedSystemPrompt = agent.config.systemPrompt;
|
|
596
|
+
if (resolvedSystemPrompt.includes("{{workspace_dir}}")) {
|
|
565
597
|
const workspaceDir = this.env?.getComponent?.("config")?.get?.("workspace_dir") || process.cwd();
|
|
566
|
-
|
|
598
|
+
resolvedSystemPrompt = resolvedSystemPrompt.replaceAll("{{workspace_dir}}", String(workspaceDir));
|
|
567
599
|
}
|
|
568
|
-
if (
|
|
600
|
+
if (resolvedSystemPrompt.includes("{{memory}}")) {
|
|
569
601
|
try {
|
|
570
602
|
const memoryComponent = this.env?.getComponent?.("memory");
|
|
571
603
|
if (memoryComponent && typeof memoryComponent.recallMemory === "function") {
|
|
572
604
|
const memoryContent = await memoryComponent.recallMemory();
|
|
573
|
-
|
|
605
|
+
resolvedSystemPrompt = resolvedSystemPrompt.replaceAll("{{memory}}", memoryContent || "(No memory)");
|
|
574
606
|
} else {
|
|
575
|
-
|
|
607
|
+
resolvedSystemPrompt = resolvedSystemPrompt.replaceAll("{{memory}}", "(Memory component not available)");
|
|
576
608
|
}
|
|
577
609
|
} catch (err) {
|
|
578
610
|
logger.warn(`[AgentComponent._run] Failed to replace {{memory}}: ${err}`);
|
|
579
|
-
|
|
611
|
+
resolvedSystemPrompt = resolvedSystemPrompt.replaceAll("{{memory}}", "(Failed to load memory)");
|
|
580
612
|
}
|
|
581
613
|
}
|
|
582
614
|
}
|
|
@@ -597,7 +629,7 @@ class AgentComponent extends BaseComponent {
|
|
|
597
629
|
maxIterations: agent.config.maxIterations,
|
|
598
630
|
messages: [],
|
|
599
631
|
tools: this.getAvailableTools(agent, effectiveContext),
|
|
600
|
-
systemPrompt: agent.config.systemPrompt
|
|
632
|
+
systemPrompt: resolvedSystemPrompt ?? agent.config.systemPrompt ?? "You are a helpful assistant.",
|
|
601
633
|
context: effectiveContext
|
|
602
634
|
};
|
|
603
635
|
let historyMessageCount = 0;
|
|
@@ -969,6 +1001,7 @@ class AgentComponent extends BaseComponent {
|
|
|
969
1001
|
}
|
|
970
1002
|
this.aborted.delete(runId);
|
|
971
1003
|
this.abortControllers.delete(runId);
|
|
1004
|
+
this.doomLoopCaches.delete(runId);
|
|
972
1005
|
if (result.error) {
|
|
973
1006
|
this.pushEnvEvent({
|
|
974
1007
|
type: "agent.error",
|
|
@@ -1292,6 +1325,7 @@ ${additionInfo}`
|
|
|
1292
1325
|
logger.warn("SessionComponent not found, skipping session recording");
|
|
1293
1326
|
return;
|
|
1294
1327
|
}
|
|
1328
|
+
const filtered2 = [];
|
|
1295
1329
|
for (const msg of allMessages) {
|
|
1296
1330
|
if (msg.role === "system") {
|
|
1297
1331
|
continue;
|
|
@@ -1304,10 +1338,19 @@ ${additionInfo}`
|
|
|
1304
1338
|
continue;
|
|
1305
1339
|
}
|
|
1306
1340
|
}
|
|
1307
|
-
|
|
1341
|
+
filtered2.push(this.messageConverter.fromModelMessage(msg, { sessionID: sessionId }));
|
|
1308
1342
|
}
|
|
1343
|
+
if (filtered2.length === 0) {
|
|
1344
|
+
return;
|
|
1345
|
+
}
|
|
1346
|
+
await sessionComponent.addMessages(sessionId, filtered2);
|
|
1309
1347
|
} catch (err) {
|
|
1310
|
-
|
|
1348
|
+
const kind = err && typeof err === "object" && "kind" in err ? err.kind : undefined;
|
|
1349
|
+
if (kind === "lock_exhausted") {
|
|
1350
|
+
logger.error(`[recordSessionMessages] DROPPED ${filtered?.length ?? "?"} message(s) — SQLITE_BUSY retry exhausted after ${err.attempts ?? "?"} attempts. Session ${sessionId} is now inconsistent with LLM context. Original: ${err}`);
|
|
1351
|
+
} else {
|
|
1352
|
+
logger.error(`[recordSessionMessages] Failed to record session messages for ${sessionId}: ${err}`);
|
|
1353
|
+
}
|
|
1311
1354
|
}
|
|
1312
1355
|
}
|
|
1313
1356
|
isEmptyMessage(content) {
|