@markus-global/cli 0.4.22 → 0.4.24
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/commands/auth.js +1 -1
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +9 -1
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +6 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/model.js +3 -3
- package/dist/commands/model.js.map +1 -1
- package/dist/commands/start.d.ts.map +1 -1
- package/dist/commands/start.js +35 -4
- package/dist/commands/start.js.map +1 -1
- package/dist/markus.mjs +1289 -418
- package/dist/web-ui/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/web-ui/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/web-ui/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/web-ui/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/web-ui/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/web-ui/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/web-ui/assets/index-CJqOXq2-.js +343 -0
- package/dist/web-ui/assets/index-vdyam0yR.css +1 -0
- package/dist/web-ui/index.html +2 -2
- package/package.json +1 -1
- package/templates/roles/org-manager/HEARTBEAT.md +8 -0
- package/templates/roles/secretary/HEARTBEAT.md +8 -0
- package/templates/skills/agent-building/SKILL.md +14 -5
- package/templates/skills/team-building/SKILL.md +22 -5
- package/dist/web-ui/assets/index-DEkXd9d7.css +0 -1
- package/dist/web-ui/assets/index-HAWGXtTM.js +0 -66
package/dist/markus.mjs
CHANGED
|
@@ -4061,8 +4061,9 @@ var init_models = __esm({
|
|
|
4061
4061
|
id: "deepseek",
|
|
4062
4062
|
label: "DeepSeek",
|
|
4063
4063
|
envKey: "DEEPSEEK_API_KEY",
|
|
4064
|
-
|
|
4065
|
-
|
|
4064
|
+
baseUrl: "https://api.deepseek.com",
|
|
4065
|
+
defaultModel: "deepseek-v4-flash",
|
|
4066
|
+
models: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-chat", "deepseek-reasoner"]
|
|
4066
4067
|
}
|
|
4067
4068
|
];
|
|
4068
4069
|
}
|
|
@@ -8324,8 +8325,16 @@ var init_tool_selector = __esm({
|
|
|
8324
8325
|
result.push({ name: tool.name, description: tool.description, inputSchema: tool.inputSchema });
|
|
8325
8326
|
}
|
|
8326
8327
|
}
|
|
8328
|
+
const seen = new Set(result.map((t) => t.name));
|
|
8327
8329
|
result.push(this.buildDiscoverTool(opts.allTools, selected, opts.skillCatalog));
|
|
8328
|
-
|
|
8330
|
+
seen.add("discover_tools");
|
|
8331
|
+
const pushUnique = (tool) => {
|
|
8332
|
+
if (!seen.has(tool.name)) {
|
|
8333
|
+
seen.add(tool.name);
|
|
8334
|
+
result.push(tool);
|
|
8335
|
+
}
|
|
8336
|
+
};
|
|
8337
|
+
pushUnique({
|
|
8329
8338
|
name: "notify_user",
|
|
8330
8339
|
description: "Send a message to the user. The message appears in the agent chat and as a notification. Write a comprehensive body \u2014 the user sees the full content and may reply. Use for status updates, reports, alerts, and findings.",
|
|
8331
8340
|
inputSchema: {
|
|
@@ -8339,7 +8348,7 @@ var init_tool_selector = __esm({
|
|
|
8339
8348
|
required: ["title", "body"]
|
|
8340
8349
|
}
|
|
8341
8350
|
});
|
|
8342
|
-
|
|
8351
|
+
pushUnique({
|
|
8343
8352
|
name: "request_user_approval",
|
|
8344
8353
|
description: "Request a decision or approval from the user. The tool BLOCKS until the user responds. Use when you need human approval, a choice between options, or any user decision/input. Default options: Approve / Reject (reject requires a reason). You can provide custom options and optionally allow freeform text input.",
|
|
8345
8354
|
inputSchema: {
|
|
@@ -8367,7 +8376,7 @@ var init_tool_selector = __esm({
|
|
|
8367
8376
|
required: ["title", "description"]
|
|
8368
8377
|
}
|
|
8369
8378
|
});
|
|
8370
|
-
|
|
8379
|
+
pushUnique({
|
|
8371
8380
|
name: "recall_activity",
|
|
8372
8381
|
description: 'Query your own execution history. Use "list" to see recent activities, or "get" with an activity_id to see detailed tool call logs for a specific activity.',
|
|
8373
8382
|
inputSchema: {
|
|
@@ -8668,7 +8677,7 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8668
8677
|
}
|
|
8669
8678
|
}
|
|
8670
8679
|
const finalCommand = injectGitCommitMeta(command, agentMeta);
|
|
8671
|
-
return new Promise((
|
|
8680
|
+
return new Promise((resolve20) => {
|
|
8672
8681
|
const child = spawn("sh", ["-c", finalCommand], {
|
|
8673
8682
|
cwd: effectiveCwd ?? void 0,
|
|
8674
8683
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -8723,7 +8732,7 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8723
8732
|
flushOutput();
|
|
8724
8733
|
}
|
|
8725
8734
|
if (killed) {
|
|
8726
|
-
|
|
8735
|
+
resolve20(JSON.stringify({
|
|
8727
8736
|
status: "error",
|
|
8728
8737
|
error: `Command timed out after ${timeoutMs}ms`,
|
|
8729
8738
|
exitCode: code,
|
|
@@ -8731,7 +8740,7 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8731
8740
|
stderr: stderr.slice(0, 4e3)
|
|
8732
8741
|
}));
|
|
8733
8742
|
} else if (code !== 0) {
|
|
8734
|
-
|
|
8743
|
+
resolve20(JSON.stringify({
|
|
8735
8744
|
status: "error",
|
|
8736
8745
|
error: stderr.trim() || `Process exited with code ${code}`,
|
|
8737
8746
|
exitCode: code,
|
|
@@ -8739,7 +8748,7 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8739
8748
|
stderr: stderr.slice(0, 4e3)
|
|
8740
8749
|
}));
|
|
8741
8750
|
} else {
|
|
8742
|
-
|
|
8751
|
+
resolve20(JSON.stringify({
|
|
8743
8752
|
status: "success",
|
|
8744
8753
|
stdout: stdout.trim() || void 0,
|
|
8745
8754
|
stderr: stderr.trim() || void 0
|
|
@@ -8752,7 +8761,7 @@ function createShellTool(security, workspacePath, agentMeta, policy, onCommandAp
|
|
|
8752
8761
|
clearTimeout(flushTimer);
|
|
8753
8762
|
flushOutput();
|
|
8754
8763
|
}
|
|
8755
|
-
|
|
8764
|
+
resolve20(JSON.stringify({
|
|
8756
8765
|
status: "error",
|
|
8757
8766
|
error: err.message,
|
|
8758
8767
|
stdout: stdout.slice(0, 4e3),
|
|
@@ -14852,8 +14861,8 @@ var init_custom_element_registry = __esm({
|
|
|
14852
14861
|
} : (element) => element.localName === localName;
|
|
14853
14862
|
registry.set(localName, { Class, check: check2 });
|
|
14854
14863
|
if (waiting.has(localName)) {
|
|
14855
|
-
for (const
|
|
14856
|
-
|
|
14864
|
+
for (const resolve20 of waiting.get(localName))
|
|
14865
|
+
resolve20(Class);
|
|
14857
14866
|
waiting.delete(localName);
|
|
14858
14867
|
}
|
|
14859
14868
|
ownerDocument.querySelectorAll(
|
|
@@ -14893,13 +14902,13 @@ var init_custom_element_registry = __esm({
|
|
|
14893
14902
|
*/
|
|
14894
14903
|
whenDefined(localName) {
|
|
14895
14904
|
const { registry, waiting } = this;
|
|
14896
|
-
return new Promise((
|
|
14905
|
+
return new Promise((resolve20) => {
|
|
14897
14906
|
if (registry.has(localName))
|
|
14898
|
-
|
|
14907
|
+
resolve20(registry.get(localName).Class);
|
|
14899
14908
|
else {
|
|
14900
14909
|
if (!waiting.has(localName))
|
|
14901
14910
|
waiting.set(localName, []);
|
|
14902
|
-
waiting.get(localName).push(
|
|
14911
|
+
waiting.get(localName).push(resolve20);
|
|
14903
14912
|
}
|
|
14904
14913
|
});
|
|
14905
14914
|
}
|
|
@@ -41155,13 +41164,41 @@ var init_web_fetch = __esm({
|
|
|
41155
41164
|
});
|
|
41156
41165
|
|
|
41157
41166
|
// ../core/dist/tools/web-search.js
|
|
41167
|
+
async function resolveProxyDispatcher() {
|
|
41168
|
+
if (_dispatcher !== false)
|
|
41169
|
+
return _dispatcher || void 0;
|
|
41170
|
+
const proxyUrl = process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"];
|
|
41171
|
+
if (!proxyUrl) {
|
|
41172
|
+
_dispatcher = void 0;
|
|
41173
|
+
return void 0;
|
|
41174
|
+
}
|
|
41175
|
+
try {
|
|
41176
|
+
const load = new Function("id", "return import(id)");
|
|
41177
|
+
const { ProxyAgent } = await load("undici");
|
|
41178
|
+
_dispatcher = new ProxyAgent(proxyUrl);
|
|
41179
|
+
} catch {
|
|
41180
|
+
_dispatcher = void 0;
|
|
41181
|
+
}
|
|
41182
|
+
return _dispatcher || void 0;
|
|
41183
|
+
}
|
|
41184
|
+
async function proxyFetch(url, init) {
|
|
41185
|
+
const dispatcher = await resolveProxyDispatcher();
|
|
41186
|
+
const signal = init?.signal ?? AbortSignal.timeout(SEARCH_TIMEOUT_MS);
|
|
41187
|
+
const opts = { ...init, signal };
|
|
41188
|
+
if (dispatcher)
|
|
41189
|
+
opts["dispatcher"] = dispatcher;
|
|
41190
|
+
return fetch(url, opts);
|
|
41191
|
+
}
|
|
41192
|
+
function hasProxy() {
|
|
41193
|
+
return !!(process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"]);
|
|
41194
|
+
}
|
|
41158
41195
|
async function searchSerper(query2, maxResults) {
|
|
41159
41196
|
const apiKey = process.env["SERPER_API_KEY"];
|
|
41160
41197
|
if (!apiKey)
|
|
41161
41198
|
throw new Error("SERPER_API_KEY not configured");
|
|
41162
41199
|
let res;
|
|
41163
41200
|
try {
|
|
41164
|
-
res = await
|
|
41201
|
+
res = await proxyFetch("https://google.serper.dev/search", {
|
|
41165
41202
|
method: "POST",
|
|
41166
41203
|
headers: {
|
|
41167
41204
|
"X-API-KEY": apiKey,
|
|
@@ -41189,7 +41226,7 @@ async function searchBrave(query2, maxResults) {
|
|
|
41189
41226
|
const params = new URLSearchParams({ q: query2, count: String(maxResults) });
|
|
41190
41227
|
let res;
|
|
41191
41228
|
try {
|
|
41192
|
-
res = await
|
|
41229
|
+
res = await proxyFetch(`https://api.search.brave.com/res/v1/web/search?${params}`, {
|
|
41193
41230
|
headers: {
|
|
41194
41231
|
"Accept": "application/json",
|
|
41195
41232
|
"Accept-Encoding": "gzip",
|
|
@@ -41209,23 +41246,28 @@ async function searchBrave(query2, maxResults) {
|
|
|
41209
41246
|
date: r.page_age
|
|
41210
41247
|
}));
|
|
41211
41248
|
}
|
|
41212
|
-
async function
|
|
41249
|
+
async function searchDuckDuckGo(query2, maxResults) {
|
|
41213
41250
|
const encoded = encodeURIComponent(query2);
|
|
41214
|
-
let
|
|
41215
|
-
|
|
41216
|
-
|
|
41217
|
-
|
|
41218
|
-
"User-Agent":
|
|
41251
|
+
let lastError;
|
|
41252
|
+
for (const base of DDG_ENDPOINTS) {
|
|
41253
|
+
try {
|
|
41254
|
+
const res = await proxyFetch(`${base}?q=${encoded}`, {
|
|
41255
|
+
headers: { "User-Agent": DDG_UA }
|
|
41256
|
+
});
|
|
41257
|
+
if (!res.ok) {
|
|
41258
|
+
lastError = new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41259
|
+
continue;
|
|
41219
41260
|
}
|
|
41220
|
-
|
|
41221
|
-
|
|
41222
|
-
|
|
41223
|
-
|
|
41224
|
-
|
|
41225
|
-
|
|
41261
|
+
const html = await res.text();
|
|
41262
|
+
const results = base.includes("lite") ? parseDDGLite(html, maxResults) : parseDDGHtml(html, maxResults);
|
|
41263
|
+
if (results.length > 0)
|
|
41264
|
+
return results;
|
|
41265
|
+
lastError = new Error(`Parsed 0 results from ${base}`);
|
|
41266
|
+
} catch (err) {
|
|
41267
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
41268
|
+
}
|
|
41226
41269
|
}
|
|
41227
|
-
|
|
41228
|
-
return parseDDGLite(html, maxResults);
|
|
41270
|
+
throw new Error(`Network error: ${lastError?.message ?? "all DuckDuckGo endpoints failed"}`);
|
|
41229
41271
|
}
|
|
41230
41272
|
function parseDDGLite(html, max) {
|
|
41231
41273
|
const results = [];
|
|
@@ -41264,21 +41306,7 @@ function parseDDGLite(html, max) {
|
|
|
41264
41306
|
}
|
|
41265
41307
|
return results;
|
|
41266
41308
|
}
|
|
41267
|
-
|
|
41268
|
-
const encoded = encodeURIComponent(query2);
|
|
41269
|
-
let res;
|
|
41270
|
-
try {
|
|
41271
|
-
res = await fetch(`https://html.duckduckgo.com/html/?q=${encoded}`, {
|
|
41272
|
-
headers: {
|
|
41273
|
-
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
|
|
41274
|
-
}
|
|
41275
|
-
});
|
|
41276
|
-
} catch (err) {
|
|
41277
|
-
throw new Error(`Network error: ${err instanceof Error ? err.message : String(err)}`);
|
|
41278
|
-
}
|
|
41279
|
-
if (!res.ok)
|
|
41280
|
-
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
41281
|
-
const html = await res.text();
|
|
41309
|
+
function parseDDGHtml(html, maxResults) {
|
|
41282
41310
|
const results = [];
|
|
41283
41311
|
const linkRegex = /<a[^>]+class="result__a"[^>]*href="([^"]*)"[^>]*>([\s\S]*?)<\/a>/g;
|
|
41284
41312
|
const snippetRegex = /<a[^>]+class="result__snippet"[^>]*>([\s\S]*?)<\/a>/g;
|
|
@@ -41306,10 +41334,12 @@ async function searchDuckDuckGoHtml(query2, maxResults) {
|
|
|
41306
41334
|
function stripHtml(html) {
|
|
41307
41335
|
return html.replace(/<[^>]*>/g, "").replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, '"').replace(/'/g, "'").replace(/'/g, "'").replace(/ /g, " ").replace(/\s+/g, " ").trim();
|
|
41308
41336
|
}
|
|
41309
|
-
var WebSearchTool;
|
|
41337
|
+
var SEARCH_TIMEOUT_MS, _dispatcher, WebSearchTool, DDG_UA, DDG_ENDPOINTS;
|
|
41310
41338
|
var init_web_search = __esm({
|
|
41311
41339
|
"../core/dist/tools/web-search.js"() {
|
|
41312
41340
|
"use strict";
|
|
41341
|
+
SEARCH_TIMEOUT_MS = 15e3;
|
|
41342
|
+
_dispatcher = false;
|
|
41313
41343
|
WebSearchTool = {
|
|
41314
41344
|
name: "web_search",
|
|
41315
41345
|
description: "Search the web for real-time information. Returns search result titles, snippets, and URLs. Use this when you need up-to-date information that might not be in your training data.",
|
|
@@ -41333,7 +41363,7 @@ var init_web_search = __esm({
|
|
|
41333
41363
|
const backends = [
|
|
41334
41364
|
{ name: "Serper", fn: searchSerper },
|
|
41335
41365
|
{ name: "Brave", fn: searchBrave },
|
|
41336
|
-
{ name: "DuckDuckGo", fn:
|
|
41366
|
+
{ name: "DuckDuckGo", fn: searchDuckDuckGo }
|
|
41337
41367
|
];
|
|
41338
41368
|
const errors = [];
|
|
41339
41369
|
for (const { name, fn } of backends) {
|
|
@@ -41348,13 +41378,27 @@ var init_web_search = __esm({
|
|
|
41348
41378
|
errors.push({ backend: name, error: message });
|
|
41349
41379
|
}
|
|
41350
41380
|
}
|
|
41381
|
+
const hasNetworkErr = errors.some((e) => e.error.includes("Network error") || e.error.includes("timed out"));
|
|
41382
|
+
const hints = [];
|
|
41383
|
+
if (hasNetworkErr && !hasProxy()) {
|
|
41384
|
+
hints.push("All network requests failed and no HTTP proxy is configured. If you are behind a firewall or in a restricted network, set HTTPS_PROXY (e.g. export HTTPS_PROXY=http://127.0.0.1:7890).");
|
|
41385
|
+
}
|
|
41386
|
+
if (hasNetworkErr && hasProxy()) {
|
|
41387
|
+
hints.push(`HTTP proxy is configured (${process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"]}), but network requests still failed. Verify the proxy is reachable and allows outbound HTTPS.`);
|
|
41388
|
+
}
|
|
41351
41389
|
return JSON.stringify({
|
|
41352
41390
|
status: "error",
|
|
41353
41391
|
error: "All search backends failed.",
|
|
41354
|
-
details: errors
|
|
41392
|
+
details: errors,
|
|
41393
|
+
...hints.length > 0 ? { hints } : {}
|
|
41355
41394
|
});
|
|
41356
41395
|
}
|
|
41357
41396
|
};
|
|
41397
|
+
DDG_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
|
|
41398
|
+
DDG_ENDPOINTS = [
|
|
41399
|
+
"https://lite.duckduckgo.com/lite/",
|
|
41400
|
+
"https://html.duckduckgo.com/html/"
|
|
41401
|
+
];
|
|
41358
41402
|
}
|
|
41359
41403
|
});
|
|
41360
41404
|
|
|
@@ -41766,7 +41810,7 @@ var init_search = __esm({
|
|
|
41766
41810
|
|
|
41767
41811
|
// ../core/dist/tools/patch.js
|
|
41768
41812
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync8, existsSync as existsSync13, unlinkSync } from "node:fs";
|
|
41769
|
-
import { dirname as dirname4
|
|
41813
|
+
import { dirname as dirname4 } from "node:path";
|
|
41770
41814
|
function createPatchTool(security, workspacePath, policy) {
|
|
41771
41815
|
const guard = security ?? defaultSecurityGuard;
|
|
41772
41816
|
return {
|
|
@@ -41817,7 +41861,7 @@ function createPatchTool(security, workspacePath, policy) {
|
|
|
41817
41861
|
if (!patches || !Array.isArray(patches) || patches.length === 0) {
|
|
41818
41862
|
return JSON.stringify({ status: "error", error: "patches array is required and must not be empty" });
|
|
41819
41863
|
}
|
|
41820
|
-
const
|
|
41864
|
+
const resolvedPaths = [];
|
|
41821
41865
|
const results = [];
|
|
41822
41866
|
for (const patch of patches) {
|
|
41823
41867
|
const { resolved: filePath, access } = resolveAndCheckAccess(patch.file, workspacePath, policy);
|
|
@@ -41858,6 +41902,7 @@ function createPatchTool(security, workspacePath, policy) {
|
|
|
41858
41902
|
if (patch.action === "create" && !patch.content && patch.content !== "") {
|
|
41859
41903
|
return JSON.stringify({ status: "error", error: `create action requires content for ${patch.file}` });
|
|
41860
41904
|
}
|
|
41905
|
+
resolvedPaths.push(filePath);
|
|
41861
41906
|
}
|
|
41862
41907
|
if (dryRun) {
|
|
41863
41908
|
return JSON.stringify({
|
|
@@ -41866,8 +41911,9 @@ function createPatchTool(security, workspacePath, policy) {
|
|
|
41866
41911
|
patchCount: patches.length
|
|
41867
41912
|
});
|
|
41868
41913
|
}
|
|
41869
|
-
for (
|
|
41870
|
-
const
|
|
41914
|
+
for (let i = 0; i < patches.length; i++) {
|
|
41915
|
+
const patch = patches[i];
|
|
41916
|
+
const filePath = resolvedPaths[i];
|
|
41871
41917
|
switch (patch.action) {
|
|
41872
41918
|
case "edit": {
|
|
41873
41919
|
let content = readFileSync9(filePath, "utf-8");
|
|
@@ -41923,7 +41969,7 @@ var init_patch = __esm({
|
|
|
41923
41969
|
|
|
41924
41970
|
// ../core/dist/tools/process-manager.js
|
|
41925
41971
|
import { spawn as spawn2 } from "node:child_process";
|
|
41926
|
-
import { resolve as
|
|
41972
|
+
import { resolve as resolve7 } from "node:path";
|
|
41927
41973
|
function onBackgroundCompletion(cb) {
|
|
41928
41974
|
completionListeners.push(cb);
|
|
41929
41975
|
return () => {
|
|
@@ -41985,8 +42031,8 @@ function createBackgroundExecTool(workspacePath) {
|
|
|
41985
42031
|
const cwd = args["cwd"];
|
|
41986
42032
|
const timeoutSec = args["timeout_seconds"] ?? 300;
|
|
41987
42033
|
const basePath = workspacePath ?? process.cwd();
|
|
41988
|
-
const effectiveCwd = cwd ?
|
|
41989
|
-
if (workspacePath && !effectiveCwd.startsWith(
|
|
42034
|
+
const effectiveCwd = cwd ? resolve7(basePath, cwd) : basePath;
|
|
42035
|
+
if (workspacePath && !effectiveCwd.startsWith(resolve7(workspacePath))) {
|
|
41990
42036
|
return JSON.stringify({ status: "denied", error: "Working directory must be within workspace" });
|
|
41991
42037
|
}
|
|
41992
42038
|
const id = `bg_${++sessionCounter}_${Date.now()}`;
|
|
@@ -42250,7 +42296,7 @@ async function llmCallWithRetry(fn, label) {
|
|
|
42250
42296
|
error: String(err).slice(0, SUBAGENT_ERROR_PREVIEW_CHARS),
|
|
42251
42297
|
delay
|
|
42252
42298
|
});
|
|
42253
|
-
await new Promise((
|
|
42299
|
+
await new Promise((resolve20) => setTimeout(resolve20, delay));
|
|
42254
42300
|
}
|
|
42255
42301
|
}
|
|
42256
42302
|
throw lastErr;
|
|
@@ -42323,7 +42369,7 @@ async function runSubagentLoop(ctx, task, opts) {
|
|
|
42323
42369
|
metadata: { iteration: iterations, finishReason: response.finishReason }
|
|
42324
42370
|
});
|
|
42325
42371
|
if (response.finishReason === "max_tokens" && !response.toolCalls?.length) {
|
|
42326
|
-
messages.push({ role: "assistant", content: response.content });
|
|
42372
|
+
messages.push({ role: "assistant", content: response.content, reasoningContent: response.reasoningContent });
|
|
42327
42373
|
logEntries.push({ ts: (/* @__PURE__ */ new Date()).toISOString(), role: "assistant", content: response.content });
|
|
42328
42374
|
messages.push({
|
|
42329
42375
|
role: "user",
|
|
@@ -42333,7 +42379,8 @@ async function runSubagentLoop(ctx, task, opts) {
|
|
|
42333
42379
|
messages.push({
|
|
42334
42380
|
role: "assistant",
|
|
42335
42381
|
content: response.content,
|
|
42336
|
-
toolCalls: response.toolCalls
|
|
42382
|
+
toolCalls: response.toolCalls,
|
|
42383
|
+
reasoningContent: response.reasoningContent
|
|
42337
42384
|
});
|
|
42338
42385
|
logEntries.push({
|
|
42339
42386
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -42838,9 +42885,9 @@ ${typeLabel}${item.payload.content}`;
|
|
|
42838
42885
|
*/
|
|
42839
42886
|
wakeIdleLoop() {
|
|
42840
42887
|
if (this.idleResolve) {
|
|
42841
|
-
const
|
|
42888
|
+
const resolve20 = this.idleResolve;
|
|
42842
42889
|
this.idleResolve = void 0;
|
|
42843
|
-
|
|
42890
|
+
resolve20();
|
|
42844
42891
|
}
|
|
42845
42892
|
}
|
|
42846
42893
|
/**
|
|
@@ -42865,8 +42912,8 @@ ${typeLabel}${item.payload.content}`;
|
|
|
42865
42912
|
const item = this.dequeue();
|
|
42866
42913
|
if (item)
|
|
42867
42914
|
return item;
|
|
42868
|
-
await new Promise((
|
|
42869
|
-
this.idleResolve =
|
|
42915
|
+
await new Promise((resolve20) => {
|
|
42916
|
+
this.idleResolve = resolve20;
|
|
42870
42917
|
});
|
|
42871
42918
|
const afterWake = this.dequeue();
|
|
42872
42919
|
if (!afterWake) {
|
|
@@ -42917,6 +42964,18 @@ ${typeLabel}${item.payload.content}`;
|
|
|
42917
42964
|
this.persistence?.updateStatus(item.id, "deferred", { deferredUntil: until });
|
|
42918
42965
|
return item;
|
|
42919
42966
|
}
|
|
42967
|
+
/**
|
|
42968
|
+
* Defer an item that has already been dequeued (not in the queue).
|
|
42969
|
+
* Used when processing is interrupted (preempted) and the item should
|
|
42970
|
+
* be resumed later. Only updates persistence — does NOT re-insert
|
|
42971
|
+
* into the in-memory queue (resurfaceDue handles that on the next idle cycle).
|
|
42972
|
+
*/
|
|
42973
|
+
deferDequeued(item, until) {
|
|
42974
|
+
item.status = "deferred";
|
|
42975
|
+
item.deferredUntil = until;
|
|
42976
|
+
item.startedAt = void 0;
|
|
42977
|
+
this.persistence?.updateStatus(item.id, "deferred", { deferredUntil: until });
|
|
42978
|
+
}
|
|
42920
42979
|
/**
|
|
42921
42980
|
* Mark an item as merged into another item.
|
|
42922
42981
|
*/
|
|
@@ -43158,7 +43217,7 @@ function detectAbnormalCompletion(reply, item) {
|
|
|
43158
43217
|
const registry = MAILBOX_TYPE_REGISTRY[item.sourceType];
|
|
43159
43218
|
if (!registry?.invokesLLM)
|
|
43160
43219
|
return void 0;
|
|
43161
|
-
if (reply === "[preempted]")
|
|
43220
|
+
if (reply === "[preempted]" || reply === "[cancelled]")
|
|
43162
43221
|
return void 0;
|
|
43163
43222
|
const isUserFacing = item.sourceType === "human_chat" || item.sourceType === "a2a_message";
|
|
43164
43223
|
if (isUserFacing)
|
|
@@ -43195,6 +43254,8 @@ var init_attention = __esm({
|
|
|
43195
43254
|
triageToolHandlers;
|
|
43196
43255
|
triageChatFn;
|
|
43197
43256
|
lastTriageResult;
|
|
43257
|
+
/** Tracks whether the last yield-point decision was 'cancel' vs 'preempt'. */
|
|
43258
|
+
lastYieldDecision;
|
|
43198
43259
|
unsubscribeNewItem;
|
|
43199
43260
|
decisions = [];
|
|
43200
43261
|
watchdogTimer;
|
|
@@ -43391,6 +43452,7 @@ var init_attention = __esm({
|
|
|
43391
43452
|
this.interruptSignal = false;
|
|
43392
43453
|
this.pendingInterruptItem = void 0;
|
|
43393
43454
|
this.criticalInterruptResolve = void 0;
|
|
43455
|
+
this.lastYieldDecision = void 0;
|
|
43394
43456
|
this.processingStartedAt = Date.now();
|
|
43395
43457
|
this.delegate?.onFocusChanged(item);
|
|
43396
43458
|
let reply = void 0;
|
|
@@ -43398,7 +43460,7 @@ var init_attention = __esm({
|
|
|
43398
43460
|
try {
|
|
43399
43461
|
const processing = this.delegate?.processMailboxItem(item);
|
|
43400
43462
|
const backstopMs = this.waitingForHumanApproval ? APPROVAL_WAIT_TIMEOUT_MS : MAILBOX_PROCESSING_TIMEOUT_MS;
|
|
43401
|
-
const backstop = new Promise((
|
|
43463
|
+
const backstop = new Promise((resolve20) => setTimeout(() => resolve20(void 0), backstopMs));
|
|
43402
43464
|
const result = await Promise.race([
|
|
43403
43465
|
processing?.then((r) => ({ done: true, reply: r })),
|
|
43404
43466
|
backstop.then(() => ({ done: false, reply: void 0 }))
|
|
@@ -43425,6 +43487,27 @@ var init_attention = __esm({
|
|
|
43425
43487
|
this.processingStartedAt = void 0;
|
|
43426
43488
|
if (timedOut) {
|
|
43427
43489
|
this.mailbox.requeue(item);
|
|
43490
|
+
} else if (reply === "[cancelled]" || this.lastYieldDecision === "cancel") {
|
|
43491
|
+
log14.info("Item cancelled \u2014 dropping permanently", {
|
|
43492
|
+
agentId: this.agentId,
|
|
43493
|
+
itemId: item.id,
|
|
43494
|
+
type: item.sourceType
|
|
43495
|
+
});
|
|
43496
|
+
this.mailbox.complete(item.id);
|
|
43497
|
+
} else if (reply === "[preempted]" || this.lastYieldDecision === "preempt") {
|
|
43498
|
+
log14.info("Item preempted (paused) \u2014 deferring for later resumption", {
|
|
43499
|
+
agentId: this.agentId,
|
|
43500
|
+
itemId: item.id,
|
|
43501
|
+
type: item.sourceType
|
|
43502
|
+
});
|
|
43503
|
+
this.mailbox.deferDequeued(item);
|
|
43504
|
+
} else if (!this.running) {
|
|
43505
|
+
log14.info("Agent stopped during processing \u2014 requeueing item", {
|
|
43506
|
+
agentId: this.agentId,
|
|
43507
|
+
itemId: item.id,
|
|
43508
|
+
type: item.sourceType
|
|
43509
|
+
});
|
|
43510
|
+
this.mailbox.requeue(item);
|
|
43428
43511
|
} else {
|
|
43429
43512
|
const abnormalReason = detectAbnormalCompletion(reply, item);
|
|
43430
43513
|
const retries = item.retryCount ?? 0;
|
|
@@ -43483,8 +43566,8 @@ var init_attention = __esm({
|
|
|
43483
43566
|
* The promise is single-use; call again to get a fresh one.
|
|
43484
43567
|
*/
|
|
43485
43568
|
waitForPreemptionSignal() {
|
|
43486
|
-
return new Promise((
|
|
43487
|
-
this.criticalInterruptResolve =
|
|
43569
|
+
return new Promise((resolve20) => {
|
|
43570
|
+
this.criticalInterruptResolve = resolve20;
|
|
43488
43571
|
});
|
|
43489
43572
|
}
|
|
43490
43573
|
/**
|
|
@@ -43500,7 +43583,8 @@ var init_attention = __esm({
|
|
|
43500
43583
|
*
|
|
43501
43584
|
* Returns the decision type so the caller knows what to do:
|
|
43502
43585
|
* - 'continue' → keep working on current task
|
|
43503
|
-
* - 'preempt' → caller should save state and return;
|
|
43586
|
+
* - 'preempt' → caller should save state and return '[preempted]'; item is deferred for later resumption
|
|
43587
|
+
* - 'cancel' → caller should abort and return '[cancelled]'; item is permanently dropped
|
|
43504
43588
|
* - 'merge' → item was absorbed into current work (caller may inject into session)
|
|
43505
43589
|
*/
|
|
43506
43590
|
async checkYieldPoint() {
|
|
@@ -43533,8 +43617,13 @@ var init_attention = __esm({
|
|
|
43533
43617
|
return { decision: "defer", item: newItem, reasoning };
|
|
43534
43618
|
}
|
|
43535
43619
|
if (decisionType === "preempt") {
|
|
43620
|
+
this.lastYieldDecision = "preempt";
|
|
43536
43621
|
return { decision: "preempt", item: newItem, reasoning };
|
|
43537
43622
|
}
|
|
43623
|
+
if (decisionType === "cancel") {
|
|
43624
|
+
this.lastYieldDecision = "cancel";
|
|
43625
|
+
return { decision: "cancel", item: newItem, reasoning };
|
|
43626
|
+
}
|
|
43538
43627
|
return { decision: "continue", reasoning };
|
|
43539
43628
|
}
|
|
43540
43629
|
/**
|
|
@@ -43617,7 +43706,7 @@ var init_attention = __esm({
|
|
|
43617
43706
|
try {
|
|
43618
43707
|
const prompt = this.buildJudgePrompt(currentItem, newItem);
|
|
43619
43708
|
const llmDecision = await this.llmJudge(prompt);
|
|
43620
|
-
const validDecisions = ["continue", "preempt", "merge", "defer"];
|
|
43709
|
+
const validDecisions = ["continue", "preempt", "cancel", "merge", "defer"];
|
|
43621
43710
|
if (validDecisions.includes(llmDecision))
|
|
43622
43711
|
return llmDecision;
|
|
43623
43712
|
} catch (err) {
|
|
@@ -43632,17 +43721,29 @@ var init_attention = __esm({
|
|
|
43632
43721
|
const recentDecs = this.decisions.slice(-5).map((d) => `- ${d.decisionType}: ${d.reasoning}`).join("\n");
|
|
43633
43722
|
const queuedItems = this.mailbox.getQueuedItems();
|
|
43634
43723
|
const queueSection = queuedItems.length > 0 ? queuedItems.map((i) => ` - [${i.sourceType}] p${i.priority}: "${i.payload.summary}"`).join("\n") : " (empty)";
|
|
43724
|
+
const currentContent = currentItem.payload.content?.slice(0, 500) ?? "";
|
|
43725
|
+
const newContent = newItem.payload.content?.slice(0, 800) ?? "";
|
|
43635
43726
|
return [
|
|
43636
|
-
"You are deciding
|
|
43637
|
-
"
|
|
43727
|
+
"You are deciding whether to INTERRUPT your current work to handle a new incoming message.",
|
|
43728
|
+
"",
|
|
43729
|
+
"RULES (in priority order):",
|
|
43730
|
+
"1. Human messages (human_chat) ALWAYS preempt non-human work \u2014 users are top priority.",
|
|
43731
|
+
'2. If the new message explicitly CANCELS or REVOKES the current work (e.g. "cancel that task",',
|
|
43732
|
+
` "don't publish this anymore", "delete the draft"), choose cancel \u2014 current work is permanently abandoned.`,
|
|
43733
|
+
'3. If the new message asks to PAUSE or DELAY current work (e.g. "hold off for now",',
|
|
43734
|
+
' "wait before deploying", "pause that"), choose preempt \u2014 current work is saved and can be resumed later.',
|
|
43735
|
+
"4. If the new message is about the SAME task/topic as current work and adds info, consider merge.",
|
|
43736
|
+
"5. If the new message is lower priority and unrelated, continue current work.",
|
|
43638
43737
|
"",
|
|
43639
43738
|
`CURRENT FOCUS: [${currentItem.sourceType}] priority=${currentItem.priority}`,
|
|
43640
|
-
` "${currentItem.payload.summary}"`,
|
|
43739
|
+
` Summary: "${currentItem.payload.summary}"`,
|
|
43641
43740
|
` Task: ${currentItem.payload.taskId ?? "none"}`,
|
|
43741
|
+
currentContent ? ` Content preview: ${currentContent}` : "",
|
|
43642
43742
|
"",
|
|
43643
43743
|
`NEW ITEM: [${newItem.sourceType}] priority=${newItem.priority}`,
|
|
43644
|
-
` "${newItem.payload.summary}"`,
|
|
43744
|
+
` Summary: "${newItem.payload.summary}"`,
|
|
43645
43745
|
` Task: ${newItem.payload.taskId ?? "none"}`,
|
|
43746
|
+
newContent ? ` Content: ${newContent}` : "",
|
|
43646
43747
|
"",
|
|
43647
43748
|
`FULL QUEUE (${this.mailbox.depth} items):`,
|
|
43648
43749
|
queueSection,
|
|
@@ -43650,7 +43751,14 @@ var init_attention = __esm({
|
|
|
43650
43751
|
"RECENT DECISIONS:",
|
|
43651
43752
|
recentDecs || "(none)",
|
|
43652
43753
|
"",
|
|
43653
|
-
"
|
|
43754
|
+
"DECISIONS:",
|
|
43755
|
+
"- preempt: PAUSE current work (session saved for later resumption) and handle the new item",
|
|
43756
|
+
"- cancel: PERMANENTLY STOP current work (session dropped, will NOT be resumed) and handle the new item",
|
|
43757
|
+
"- merge: Inject new item into current session as additional context (no interruption)",
|
|
43758
|
+
"- defer: Put the new item aside for later (no interruption)",
|
|
43759
|
+
"- continue: Ignore the new item for now, keep working",
|
|
43760
|
+
"",
|
|
43761
|
+
"Choose exactly one: continue | preempt | cancel | merge | defer",
|
|
43654
43762
|
"Reply with ONLY the decision word, nothing else."
|
|
43655
43763
|
].join("\n");
|
|
43656
43764
|
}
|
|
@@ -43706,7 +43814,7 @@ var init_attention = __esm({
|
|
|
43706
43814
|
raw = response.content;
|
|
43707
43815
|
break;
|
|
43708
43816
|
}
|
|
43709
|
-
messages.push({ role: "assistant", content: response.content, toolCalls: response.toolCalls });
|
|
43817
|
+
messages.push({ role: "assistant", content: response.content, toolCalls: response.toolCalls, reasoningContent: response.reasoningContent });
|
|
43710
43818
|
for (const tc of response.toolCalls) {
|
|
43711
43819
|
const handler4 = this.triageToolHandlers.get(tc.name);
|
|
43712
43820
|
let result;
|
|
@@ -44206,7 +44314,7 @@ var init_task_queue = __esm({
|
|
|
44206
44314
|
*/
|
|
44207
44315
|
async waitForAll() {
|
|
44208
44316
|
while (this.runningTasks.size > 0 || this.queue.length > 0) {
|
|
44209
|
-
await new Promise((
|
|
44317
|
+
await new Promise((resolve20) => setTimeout(resolve20, 100));
|
|
44210
44318
|
}
|
|
44211
44319
|
}
|
|
44212
44320
|
};
|
|
@@ -44333,12 +44441,12 @@ var init_task_executor = __esm({
|
|
|
44333
44441
|
* 等待任务完成
|
|
44334
44442
|
*/
|
|
44335
44443
|
async waitForTaskCompletion(taskId2) {
|
|
44336
|
-
return new Promise((
|
|
44444
|
+
return new Promise((resolve20) => {
|
|
44337
44445
|
const checkInterval = setInterval(() => {
|
|
44338
44446
|
const task = this.taskQueue.getTaskStatus(taskId2);
|
|
44339
44447
|
if (task && task.status !== TaskStatus.PENDING && task.status !== TaskStatus.RUNNING) {
|
|
44340
44448
|
clearInterval(checkInterval);
|
|
44341
|
-
|
|
44449
|
+
resolve20(task);
|
|
44342
44450
|
}
|
|
44343
44451
|
}, 100);
|
|
44344
44452
|
});
|
|
@@ -44842,24 +44950,24 @@ function extensionForMime(mime) {
|
|
|
44842
44950
|
async function checkMarkitdown() {
|
|
44843
44951
|
if (markitdownAvailable !== null)
|
|
44844
44952
|
return markitdownAvailable;
|
|
44845
|
-
return new Promise((
|
|
44953
|
+
return new Promise((resolve20) => {
|
|
44846
44954
|
execFile2("markitdown", ["--help"], { timeout: 5e3 }, (err) => {
|
|
44847
44955
|
markitdownAvailable = !err;
|
|
44848
44956
|
if (!markitdownAvailable) {
|
|
44849
44957
|
log16.info('markitdown CLI not found; file-to-text conversion will be limited. Install with: pip install "markitdown[all]"');
|
|
44850
44958
|
}
|
|
44851
|
-
|
|
44959
|
+
resolve20(markitdownAvailable);
|
|
44852
44960
|
});
|
|
44853
44961
|
});
|
|
44854
44962
|
}
|
|
44855
44963
|
async function convertWithMarkitdown(filePath) {
|
|
44856
|
-
return new Promise((
|
|
44964
|
+
return new Promise((resolve20, reject) => {
|
|
44857
44965
|
execFile2("markitdown", [filePath], { timeout: 3e4, maxBuffer: 10 * 1024 * 1024 }, (err, stdout, stderr) => {
|
|
44858
44966
|
if (err) {
|
|
44859
44967
|
reject(new Error(`markitdown failed: ${stderr || err.message}`));
|
|
44860
44968
|
return;
|
|
44861
44969
|
}
|
|
44862
|
-
|
|
44970
|
+
resolve20(stdout);
|
|
44863
44971
|
});
|
|
44864
44972
|
});
|
|
44865
44973
|
}
|
|
@@ -45272,6 +45380,7 @@ ${notification.stdoutTail}`);
|
|
|
45272
45380
|
log17.info(`Agent started: ${this.config.name}`);
|
|
45273
45381
|
}
|
|
45274
45382
|
async stop() {
|
|
45383
|
+
this.cancelActiveStream();
|
|
45275
45384
|
this.attentionController.stop();
|
|
45276
45385
|
this.heartbeat.stop();
|
|
45277
45386
|
this._bgCompletionUnsub?.();
|
|
@@ -45317,14 +45426,14 @@ ${notification.stdoutTail}`);
|
|
|
45317
45426
|
toolEventCollector: options?.toolEventCollector
|
|
45318
45427
|
}
|
|
45319
45428
|
};
|
|
45320
|
-
return new Promise((
|
|
45429
|
+
return new Promise((resolve20, reject) => {
|
|
45321
45430
|
this.mailbox.enqueue(sourceType, payload, {
|
|
45322
45431
|
priority: options?.priority,
|
|
45323
45432
|
metadata: {
|
|
45324
45433
|
senderId,
|
|
45325
45434
|
senderName: senderInfo?.name,
|
|
45326
45435
|
senderRole: senderInfo?.role,
|
|
45327
|
-
responsePromise: { resolve:
|
|
45436
|
+
responsePromise: { resolve: resolve20, reject }
|
|
45328
45437
|
}
|
|
45329
45438
|
});
|
|
45330
45439
|
});
|
|
@@ -45346,14 +45455,14 @@ ${notification.stdoutTail}`);
|
|
|
45346
45455
|
cancelToken
|
|
45347
45456
|
}
|
|
45348
45457
|
};
|
|
45349
|
-
return new Promise((
|
|
45458
|
+
return new Promise((resolve20, reject) => {
|
|
45350
45459
|
this.mailbox.enqueue("human_chat", payload, {
|
|
45351
45460
|
priority: 0,
|
|
45352
45461
|
metadata: {
|
|
45353
45462
|
senderId,
|
|
45354
45463
|
senderName: senderInfo?.name,
|
|
45355
45464
|
senderRole: senderInfo?.role,
|
|
45356
|
-
responsePromise: { resolve:
|
|
45465
|
+
responsePromise: { resolve: resolve20, reject }
|
|
45357
45466
|
}
|
|
45358
45467
|
});
|
|
45359
45468
|
});
|
|
@@ -45381,12 +45490,12 @@ ${notification.stdoutTail}`);
|
|
|
45381
45490
|
executionRound
|
|
45382
45491
|
}
|
|
45383
45492
|
};
|
|
45384
|
-
return new Promise((
|
|
45493
|
+
return new Promise((resolve20, reject) => {
|
|
45385
45494
|
this.mailbox.enqueue("task_status_update", payload, {
|
|
45386
45495
|
priority: 1,
|
|
45387
45496
|
metadata: {
|
|
45388
45497
|
taskId: taskId2,
|
|
45389
|
-
responsePromise: { resolve:
|
|
45498
|
+
responsePromise: { resolve: resolve20, reject }
|
|
45390
45499
|
}
|
|
45391
45500
|
});
|
|
45392
45501
|
});
|
|
@@ -45404,13 +45513,13 @@ ${notification.stdoutTail}`);
|
|
|
45404
45513
|
onLog
|
|
45405
45514
|
}
|
|
45406
45515
|
};
|
|
45407
|
-
return new Promise((
|
|
45516
|
+
return new Promise((resolve20, reject) => {
|
|
45408
45517
|
this.mailbox.enqueue("session_reply", payload, {
|
|
45409
45518
|
metadata: {
|
|
45410
45519
|
senderId,
|
|
45411
45520
|
senderName: senderInfo?.name,
|
|
45412
45521
|
senderRole: senderInfo?.role,
|
|
45413
|
-
responsePromise: { resolve:
|
|
45522
|
+
responsePromise: { resolve: resolve20, reject }
|
|
45414
45523
|
}
|
|
45415
45524
|
});
|
|
45416
45525
|
});
|
|
@@ -45473,7 +45582,7 @@ ${notification.stdoutTail}`);
|
|
|
45473
45582
|
}
|
|
45474
45583
|
},
|
|
45475
45584
|
evaluateInterrupt: async (currentItem, newItem) => {
|
|
45476
|
-
return this.attentionController.
|
|
45585
|
+
return this.attentionController.evaluateWithLLMFallback(currentItem, newItem);
|
|
45477
45586
|
},
|
|
45478
45587
|
getTriageContext: async () => {
|
|
45479
45588
|
const messages = this.currentSessionId ? this.memory.getRecentMessages(this.currentSessionId, TRIAGE_CONTEXT_MESSAGES_MAX * 2).filter((m) => m.role === "user" || m.role === "assistant").slice(-TRIAGE_CONTEXT_MESSAGES_MAX).map((m) => ({ role: m.role, content: typeof m.content === "string" ? m.content.slice(0, TRIAGE_CONTEXT_MSG_CHARS) : String(m.content).slice(0, TRIAGE_CONTEXT_MSG_CHARS) })) : [];
|
|
@@ -45569,7 +45678,7 @@ ${notification.stdoutTail}`);
|
|
|
45569
45678
|
case "requirement_update": {
|
|
45570
45679
|
if (extra.actionRequired) {
|
|
45571
45680
|
const reqId = item.payload.requirementId ?? "unknown";
|
|
45572
|
-
const reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `
|
|
45681
|
+
const reply = await this.handleMessage(item.payload.content + markerSuffix, item.metadata?.senderId, senderInfo, buildHandleOpts({ sessionId: `requirement_${reqId}_${ts}`, scenario: "requirement_action" }));
|
|
45573
45682
|
resolveResponse(reply);
|
|
45574
45683
|
return reply;
|
|
45575
45684
|
}
|
|
@@ -45803,6 +45912,7 @@ ${notification.stdoutTail}`);
|
|
|
45803
45912
|
if (this.state.status === "offline")
|
|
45804
45913
|
return;
|
|
45805
45914
|
this.pauseReason = reason;
|
|
45915
|
+
this.cancelActiveStream();
|
|
45806
45916
|
this.heartbeat.stop();
|
|
45807
45917
|
this.attentionController.stop();
|
|
45808
45918
|
if (this.memoryConsolidationTimer) {
|
|
@@ -46633,10 +46743,11 @@ ${report}`);
|
|
|
46633
46743
|
if (!this.state.currentActivity) {
|
|
46634
46744
|
let actType = "chat";
|
|
46635
46745
|
let actLabel;
|
|
46746
|
+
const peerName = senderInfo?.name || senderId || void 0;
|
|
46636
46747
|
switch (scenario) {
|
|
46637
46748
|
case "a2a":
|
|
46638
46749
|
actType = "a2a";
|
|
46639
|
-
actLabel = `Chat from ${
|
|
46750
|
+
actLabel = peerName ? `Chat from ${peerName}` : "Agent Message";
|
|
46640
46751
|
break;
|
|
46641
46752
|
case "heartbeat":
|
|
46642
46753
|
actType = "internal";
|
|
@@ -46644,14 +46755,14 @@ ${report}`);
|
|
|
46644
46755
|
break;
|
|
46645
46756
|
case "comment_response":
|
|
46646
46757
|
actType = "chat";
|
|
46647
|
-
actLabel = `Comment reply to ${
|
|
46758
|
+
actLabel = peerName ? `Comment reply to ${peerName}` : "Comment Reply";
|
|
46648
46759
|
break;
|
|
46649
46760
|
case "review":
|
|
46650
46761
|
actType = "internal";
|
|
46651
|
-
actLabel = `Reviewing task from ${
|
|
46762
|
+
actLabel = peerName ? `Reviewing task from ${peerName}` : "Task Review";
|
|
46652
46763
|
break;
|
|
46653
46764
|
default:
|
|
46654
|
-
actLabel = `Chat with ${
|
|
46765
|
+
actLabel = peerName ? `Chat with ${peerName}` : "Human Chat";
|
|
46655
46766
|
break;
|
|
46656
46767
|
}
|
|
46657
46768
|
chatActivityId = this.startActivity(actType, actLabel);
|
|
@@ -46792,7 +46903,7 @@ ${block}
|
|
|
46792
46903
|
break;
|
|
46793
46904
|
}
|
|
46794
46905
|
if (response.finishReason === "max_tokens" && !response.toolCalls?.length) {
|
|
46795
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content });
|
|
46906
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content, reasoningContent: response.reasoningContent });
|
|
46796
46907
|
const contMsg = {
|
|
46797
46908
|
role: "user",
|
|
46798
46909
|
content: "[Continue from where you left off. Do not repeat what you already said.]"
|
|
@@ -46802,7 +46913,8 @@ ${block}
|
|
|
46802
46913
|
this.memory.appendMessage(sessionId, {
|
|
46803
46914
|
role: "assistant",
|
|
46804
46915
|
content: response.content,
|
|
46805
|
-
toolCalls: response.toolCalls
|
|
46916
|
+
toolCalls: response.toolCalls,
|
|
46917
|
+
reasoningContent: response.reasoningContent
|
|
46806
46918
|
});
|
|
46807
46919
|
const currentActId = this.state.currentActivity?.id;
|
|
46808
46920
|
const toolResults = await Promise.all(response.toolCalls.map(async (tc) => {
|
|
@@ -46894,13 +47006,14 @@ ${block}
|
|
|
46894
47006
|
}
|
|
46895
47007
|
}
|
|
46896
47008
|
const chatYield = await this.checkAttentionYieldPoint();
|
|
46897
|
-
if (chatYield.decision === "preempt" && isPreemptable) {
|
|
46898
|
-
|
|
47009
|
+
if ((chatYield.decision === "preempt" || chatYield.decision === "cancel") && isPreemptable) {
|
|
47010
|
+
const marker = chatYield.decision === "cancel" ? "[cancelled]" : "[preempted]";
|
|
47011
|
+
log17.info(`handleMessage ${chatYield.decision} by higher-priority item`, {
|
|
46899
47012
|
agentId: this.id,
|
|
46900
47013
|
scenario,
|
|
46901
47014
|
preemptedBy: chatYield.item?.sourceType
|
|
46902
47015
|
});
|
|
46903
|
-
return
|
|
47016
|
+
return marker;
|
|
46904
47017
|
}
|
|
46905
47018
|
if (chatYield.decision === "merge" && chatYield.item) {
|
|
46906
47019
|
const mergeMsg = `[LIVE UPDATE] ${chatYield.item.payload.summary}
|
|
@@ -46943,10 +47056,10 @@ ${chatYield.item.payload.content}`;
|
|
|
46943
47056
|
const outputCheck = await this.guardrails.checkOutput(displayReply, { agentId: this.id });
|
|
46944
47057
|
if (!outputCheck.passed) {
|
|
46945
47058
|
const filtered = `[Response filtered: ${outputCheck.reason}]`;
|
|
46946
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: filtered });
|
|
47059
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: filtered, reasoningContent: response.reasoningContent });
|
|
46947
47060
|
return filtered;
|
|
46948
47061
|
}
|
|
46949
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: displayReply });
|
|
47062
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: displayReply, reasoningContent: response.reasoningContent });
|
|
46950
47063
|
if (!isLightweight && displayReply.length > 50 && senderId) {
|
|
46951
47064
|
this.memory.writeDailyLog(this.id, `[Chat with ${senderInfo?.name ?? senderId}] Q: ${userMessage.slice(0, 150)}... A: ${displayReply.slice(0, 300)}`);
|
|
46952
47065
|
}
|
|
@@ -47081,6 +47194,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47081
47194
|
this.checkDailyTokenBudget();
|
|
47082
47195
|
const llmStart = Date.now();
|
|
47083
47196
|
let response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM call");
|
|
47197
|
+
streamMarkerDelta.flush();
|
|
47084
47198
|
const tokensThisCall = response.usage.inputTokens + response.usage.outputTokens;
|
|
47085
47199
|
this.updateTokensUsed(tokensThisCall);
|
|
47086
47200
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -47118,7 +47232,8 @@ ${chatYield.item.payload.content}`;
|
|
|
47118
47232
|
if (response.finishReason === "max_tokens" && !response.toolCalls?.length) {
|
|
47119
47233
|
this.memory.appendMessage(this.currentSessionId, {
|
|
47120
47234
|
role: "assistant",
|
|
47121
|
-
content: response.content
|
|
47235
|
+
content: response.content,
|
|
47236
|
+
reasoningContent: response.reasoningContent
|
|
47122
47237
|
});
|
|
47123
47238
|
this.memory.appendMessage(this.currentSessionId, {
|
|
47124
47239
|
role: "user",
|
|
@@ -47128,7 +47243,8 @@ ${chatYield.item.payload.content}`;
|
|
|
47128
47243
|
this.memory.appendMessage(this.currentSessionId, {
|
|
47129
47244
|
role: "assistant",
|
|
47130
47245
|
content: response.content,
|
|
47131
|
-
toolCalls: response.toolCalls
|
|
47246
|
+
toolCalls: response.toolCalls,
|
|
47247
|
+
reasoningContent: response.reasoningContent
|
|
47132
47248
|
});
|
|
47133
47249
|
const subagentProgressCb = (event) => {
|
|
47134
47250
|
onEvent({
|
|
@@ -47231,6 +47347,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47231
47347
|
}
|
|
47232
47348
|
const llmStart2 = Date.now();
|
|
47233
47349
|
response = await this.withNetworkRetry(() => this.llmRouter.chatStream({ messages: updatedMessages, tools: llmTools.length > 0 ? llmTools : void 0, metadata: this.getLLMMetadata(this.currentSessionId), compaction: useCompaction }, wrappedOnEvent, this.getEffectiveProvider(), abortController.signal), "Stream LLM continuation");
|
|
47350
|
+
streamMarkerDelta.flush();
|
|
47234
47351
|
const tokens2 = response.usage.inputTokens + response.usage.outputTokens;
|
|
47235
47352
|
this.updateTokensUsed(tokens2);
|
|
47236
47353
|
this.calibrateTokenCounter(response.usage.inputTokens);
|
|
@@ -47249,10 +47366,10 @@ ${chatYield.item.payload.content}`;
|
|
|
47249
47366
|
const outputCheck = await this.guardrails.checkOutput(displayReply, { agentId: this.id });
|
|
47250
47367
|
if (!outputCheck.passed) {
|
|
47251
47368
|
const filtered = `[Response filtered: ${outputCheck.reason}]`;
|
|
47252
|
-
this.memory.appendMessage(this.currentSessionId, { role: "assistant", content: filtered });
|
|
47369
|
+
this.memory.appendMessage(this.currentSessionId, { role: "assistant", content: filtered, reasoningContent: response.reasoningContent });
|
|
47253
47370
|
return filtered;
|
|
47254
47371
|
}
|
|
47255
|
-
this.memory.appendMessage(this.currentSessionId, { role: "assistant", content: displayReply });
|
|
47372
|
+
this.memory.appendMessage(this.currentSessionId, { role: "assistant", content: displayReply, reasoningContent: response.reasoningContent });
|
|
47256
47373
|
if (streamChatActivityId && thinkingBuffer.trim()) {
|
|
47257
47374
|
this.emitActivityLog(streamChatActivityId, "text", thinkingBuffer, { isThinking: true });
|
|
47258
47375
|
}
|
|
@@ -47535,7 +47652,7 @@ ${chatYield.item.payload.content}`;
|
|
|
47535
47652
|
}
|
|
47536
47653
|
flushText();
|
|
47537
47654
|
if (response.finishReason === "max_tokens" && !response.toolCalls?.length) {
|
|
47538
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content });
|
|
47655
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content, reasoningContent: response.reasoningContent });
|
|
47539
47656
|
this.memory.appendMessage(sessionId, {
|
|
47540
47657
|
role: "user",
|
|
47541
47658
|
content: "[Continue from where you left off. Do not repeat what you already said.]"
|
|
@@ -47544,7 +47661,8 @@ ${chatYield.item.payload.content}`;
|
|
|
47544
47661
|
this.memory.appendMessage(sessionId, {
|
|
47545
47662
|
role: "assistant",
|
|
47546
47663
|
content: response.content,
|
|
47547
|
-
toolCalls: response.toolCalls
|
|
47664
|
+
toolCalls: response.toolCalls,
|
|
47665
|
+
reasoningContent: response.reasoningContent
|
|
47548
47666
|
});
|
|
47549
47667
|
let interruptedDuringTools = false;
|
|
47550
47668
|
for (const tc of response.toolCalls) {
|
|
@@ -47637,14 +47755,16 @@ ${chatYield.item.payload.content}`;
|
|
|
47637
47755
|
}
|
|
47638
47756
|
this.flushPendingInjections(sessionId);
|
|
47639
47757
|
const yieldResult = await this.checkAttentionYieldPoint();
|
|
47640
|
-
if (yieldResult.decision === "preempt") {
|
|
47641
|
-
|
|
47758
|
+
if (yieldResult.decision === "preempt" || yieldResult.decision === "cancel") {
|
|
47759
|
+
const statusLabel = yieldResult.decision === "cancel" ? "cancelled" : "preempted";
|
|
47760
|
+
emit("status", statusLabel, {
|
|
47642
47761
|
reason: yieldResult.reasoning,
|
|
47643
47762
|
preemptedBy: yieldResult.item?.sourceType
|
|
47644
47763
|
});
|
|
47645
|
-
log17.info(
|
|
47764
|
+
log17.info(`Task ${statusLabel} by higher-priority mailbox item`, {
|
|
47646
47765
|
taskId: taskId2,
|
|
47647
47766
|
agentId: this.id,
|
|
47767
|
+
decision: yieldResult.decision,
|
|
47648
47768
|
preemptedBy: yieldResult.item?.sourceType,
|
|
47649
47769
|
reasoning: yieldResult.reasoning?.slice(0, 120)
|
|
47650
47770
|
});
|
|
@@ -47729,7 +47849,7 @@ ${yieldResult.item.payload.content}`
|
|
|
47729
47849
|
if (!didSubmitReview && !cancelToken?.cancelled) {
|
|
47730
47850
|
log17.warn("Task execution ending without task_submit_review \u2014 injecting final reminder", { taskId: taskId2, agentId: this.id });
|
|
47731
47851
|
flushText();
|
|
47732
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content });
|
|
47852
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content, reasoningContent: response.reasoningContent });
|
|
47733
47853
|
this.memory.appendMessage(sessionId, {
|
|
47734
47854
|
role: "user",
|
|
47735
47855
|
content: [
|
|
@@ -47774,7 +47894,8 @@ ${yieldResult.item.payload.content}`
|
|
|
47774
47894
|
this.memory.appendMessage(sessionId, {
|
|
47775
47895
|
role: "assistant",
|
|
47776
47896
|
content: response.content,
|
|
47777
|
-
toolCalls: response.toolCalls
|
|
47897
|
+
toolCalls: response.toolCalls,
|
|
47898
|
+
reasoningContent: response.reasoningContent
|
|
47778
47899
|
});
|
|
47779
47900
|
for (const tc of response.toolCalls) {
|
|
47780
47901
|
if (cancelToken?.cancelled)
|
|
@@ -47806,12 +47927,12 @@ ${yieldResult.item.payload.content}`
|
|
|
47806
47927
|
} else {
|
|
47807
47928
|
flushText();
|
|
47808
47929
|
const finalReply = stripCompletionMarker(sanitizeLLMReply(response.content));
|
|
47809
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: finalReply });
|
|
47930
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: finalReply, reasoningContent: response.reasoningContent });
|
|
47810
47931
|
}
|
|
47811
47932
|
} else {
|
|
47812
47933
|
flushText();
|
|
47813
47934
|
const finalReply = stripCompletionMarker(sanitizeLLMReply(response.content));
|
|
47814
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: finalReply });
|
|
47935
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: finalReply, reasoningContent: response.reasoningContent });
|
|
47815
47936
|
}
|
|
47816
47937
|
emit("status", "execution_finished", {});
|
|
47817
47938
|
this.metricsCollector.recordTaskCompletion(taskId2, "completed", Date.now() - taskStartMs);
|
|
@@ -47950,7 +48071,7 @@ ${yieldResult.item.payload.content}`
|
|
|
47950
48071
|
break;
|
|
47951
48072
|
flushText();
|
|
47952
48073
|
if (response.finishReason === "max_tokens" && !response.toolCalls?.length) {
|
|
47953
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content });
|
|
48074
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: response.content, reasoningContent: response.reasoningContent });
|
|
47954
48075
|
this.memory.appendMessage(sessionId, {
|
|
47955
48076
|
role: "user",
|
|
47956
48077
|
content: "[Continue from where you left off. Do not repeat what you already said.]"
|
|
@@ -47959,7 +48080,8 @@ ${yieldResult.item.payload.content}`
|
|
|
47959
48080
|
this.memory.appendMessage(sessionId, {
|
|
47960
48081
|
role: "assistant",
|
|
47961
48082
|
content: response.content,
|
|
47962
|
-
toolCalls: response.toolCalls
|
|
48083
|
+
toolCalls: response.toolCalls,
|
|
48084
|
+
reasoningContent: response.reasoningContent
|
|
47963
48085
|
});
|
|
47964
48086
|
for (const tc of response.toolCalls) {
|
|
47965
48087
|
if (this.attentionController.hasInterruptPending()) {
|
|
@@ -48013,7 +48135,7 @@ ${yieldResult.item.payload.content}`
|
|
|
48013
48135
|
flushText();
|
|
48014
48136
|
const rawReply = sanitizeLLMReply(response.content);
|
|
48015
48137
|
const displayReply = stripCompletionMarker(rawReply);
|
|
48016
|
-
this.memory.appendMessage(sessionId, { role: "assistant", content: displayReply });
|
|
48138
|
+
this.memory.appendMessage(sessionId, { role: "assistant", content: displayReply, reasoningContent: response.reasoningContent });
|
|
48017
48139
|
return rawReply;
|
|
48018
48140
|
} catch (error) {
|
|
48019
48141
|
if (textBuffer.trim()) {
|
|
@@ -48533,7 +48655,7 @@ ${escalationReason}`;
|
|
|
48533
48655
|
error: String(error).slice(0, 200),
|
|
48534
48656
|
delay
|
|
48535
48657
|
});
|
|
48536
|
-
await new Promise((
|
|
48658
|
+
await new Promise((resolve20) => setTimeout(resolve20, delay));
|
|
48537
48659
|
}
|
|
48538
48660
|
}
|
|
48539
48661
|
throw lastError;
|
|
@@ -48809,7 +48931,7 @@ ${todayLog.slice(0, HEARTBEAT_DAILY_LOG_CHARS)}
|
|
|
48809
48931
|
agentId: this.id,
|
|
48810
48932
|
error: String(error).slice(0, 200)
|
|
48811
48933
|
});
|
|
48812
|
-
await new Promise((
|
|
48934
|
+
await new Promise((resolve20) => setTimeout(resolve20, delay));
|
|
48813
48935
|
}
|
|
48814
48936
|
}
|
|
48815
48937
|
}
|
|
@@ -49103,7 +49225,7 @@ ${promo.content}` : promo.content;
|
|
|
49103
49225
|
|
|
49104
49226
|
// ../core/dist/role-loader.js
|
|
49105
49227
|
import { readFileSync as readFileSync11, existsSync as existsSync16, readdirSync as readdirSync3 } from "node:fs";
|
|
49106
|
-
import { join as join11, resolve as
|
|
49228
|
+
import { join as join11, resolve as resolve8 } from "node:path";
|
|
49107
49229
|
var RoleLoader;
|
|
49108
49230
|
var init_role_loader = __esm({
|
|
49109
49231
|
"../core/dist/role-loader.js"() {
|
|
@@ -49112,7 +49234,7 @@ var init_role_loader = __esm({
|
|
|
49112
49234
|
RoleLoader = class {
|
|
49113
49235
|
templateDirs;
|
|
49114
49236
|
constructor(templateDirs) {
|
|
49115
|
-
this.templateDirs = templateDirs ?? [
|
|
49237
|
+
this.templateDirs = templateDirs ?? [resolve8(process.cwd(), "templates", "roles")];
|
|
49116
49238
|
}
|
|
49117
49239
|
getTemplateDirs() {
|
|
49118
49240
|
return this.templateDirs;
|
|
@@ -49452,7 +49574,7 @@ var init_mcp_client = __esm({
|
|
|
49452
49574
|
}
|
|
49453
49575
|
}
|
|
49454
49576
|
sendRequest(proc, method, params) {
|
|
49455
|
-
return new Promise((
|
|
49577
|
+
return new Promise((resolve20, reject) => {
|
|
49456
49578
|
const id = ++this.requestId;
|
|
49457
49579
|
const message = JSON.stringify({ jsonrpc: "2.0", id, method, params }) + "\n";
|
|
49458
49580
|
const timeoutMs = method === "tools/call" ? 12e4 : 3e4;
|
|
@@ -49460,7 +49582,7 @@ var init_mcp_client = __esm({
|
|
|
49460
49582
|
this.pendingRequests.delete(id);
|
|
49461
49583
|
reject(new Error(`MCP request timeout for ${method} (id=${id}, ${timeoutMs}ms)`));
|
|
49462
49584
|
}, timeoutMs);
|
|
49463
|
-
this.pendingRequests.set(id, { resolve:
|
|
49585
|
+
this.pendingRequests.set(id, { resolve: resolve20, reject, method, timer, proc });
|
|
49464
49586
|
proc.stdin?.write(message);
|
|
49465
49587
|
});
|
|
49466
49588
|
}
|
|
@@ -50359,6 +50481,67 @@ function createA2ATools(ctx) {
|
|
|
50359
50481
|
return JSON.stringify({ status: "error", error: String(err) });
|
|
50360
50482
|
}
|
|
50361
50483
|
}
|
|
50484
|
+
}] : [],
|
|
50485
|
+
...ctx.getChannelMessages ? [{
|
|
50486
|
+
name: "recall_context",
|
|
50487
|
+
description: [
|
|
50488
|
+
"Recall historical context you may need to respond effectively.",
|
|
50489
|
+
"Use this BEFORE responding when the provided context is insufficient.",
|
|
50490
|
+
"",
|
|
50491
|
+
"Supported scopes:",
|
|
50492
|
+
'\u2022 "channel" \u2014 Read chat messages from a group chat or DM channel. Requires channel_key.',
|
|
50493
|
+
" Use when you joined a discussion late, were @mentioned, or need to understand prior conversation.",
|
|
50494
|
+
"",
|
|
50495
|
+
"For other context types, use these existing tools instead:",
|
|
50496
|
+
"\u2022 task_get \u2014 Full task details including all comments (scope=task context)",
|
|
50497
|
+
"\u2022 requirement_get \u2014 Full requirement details including all comments (scope=requirement context)",
|
|
50498
|
+
"\u2022 recall_activity \u2014 Your own execution history, activity logs, and past work (scope=your activities)",
|
|
50499
|
+
"\u2022 memory_search \u2014 Your saved memories and notes (scope=personal knowledge)"
|
|
50500
|
+
].join("\n"),
|
|
50501
|
+
inputSchema: {
|
|
50502
|
+
type: "object",
|
|
50503
|
+
properties: {
|
|
50504
|
+
scope: {
|
|
50505
|
+
type: "string",
|
|
50506
|
+
enum: ["channel"],
|
|
50507
|
+
description: 'Type of context to recall. Currently: "channel" for chat/group messages.'
|
|
50508
|
+
},
|
|
50509
|
+
channel_key: {
|
|
50510
|
+
type: "string",
|
|
50511
|
+
description: 'Required when scope="channel". The channel key (e.g., "group:<teamId>" for team chats, "dm:<id1>_<id2>" for DMs).'
|
|
50512
|
+
},
|
|
50513
|
+
limit: { type: "number", description: "Number of items to fetch (default 30, max 50)." },
|
|
50514
|
+
before: { type: "string", description: "ISO timestamp \u2014 fetch items older than this for pagination. Omit for most recent." }
|
|
50515
|
+
},
|
|
50516
|
+
required: ["scope"]
|
|
50517
|
+
},
|
|
50518
|
+
async execute(args) {
|
|
50519
|
+
const scope = args["scope"];
|
|
50520
|
+
if (scope === "channel") {
|
|
50521
|
+
const channelKey = args["channel_key"];
|
|
50522
|
+
if (!channelKey) {
|
|
50523
|
+
return JSON.stringify({ status: "error", error: 'channel_key is required when scope="channel"' });
|
|
50524
|
+
}
|
|
50525
|
+
const limit = Math.min(args["limit"] ?? 30, 50);
|
|
50526
|
+
const before2 = args["before"];
|
|
50527
|
+
try {
|
|
50528
|
+
const result = await ctx.getChannelMessages(channelKey, limit, before2);
|
|
50529
|
+
const formatted = result.messages.map((m) => `[${m.createdAt}] ${m.senderType === "agent" ? `[agent] ${m.senderName}` : `[human] ${m.senderName}`}: ${m.text.slice(0, 500)}`);
|
|
50530
|
+
return JSON.stringify({
|
|
50531
|
+
messages: formatted,
|
|
50532
|
+
count: result.messages.length,
|
|
50533
|
+
hasMore: result.hasMore,
|
|
50534
|
+
oldestTimestamp: result.messages[0]?.createdAt
|
|
50535
|
+
});
|
|
50536
|
+
} catch (err) {
|
|
50537
|
+
return JSON.stringify({ status: "error", error: String(err) });
|
|
50538
|
+
}
|
|
50539
|
+
}
|
|
50540
|
+
return JSON.stringify({
|
|
50541
|
+
status: "error",
|
|
50542
|
+
error: `Unknown scope: "${scope}". Use "channel" for chat messages, or use task_get / requirement_get / recall_activity for other context.`
|
|
50543
|
+
});
|
|
50544
|
+
}
|
|
50362
50545
|
}] : []
|
|
50363
50546
|
];
|
|
50364
50547
|
}
|
|
@@ -52220,11 +52403,11 @@ function createSettingsTools(ctx) {
|
|
|
52220
52403
|
},
|
|
52221
52404
|
base_url: {
|
|
52222
52405
|
type: "string",
|
|
52223
|
-
description: 'Optional base URL for the API (e.g. "https://api.deepseek.com
|
|
52406
|
+
description: 'Optional base URL for the API (e.g. "https://api.deepseek.com")'
|
|
52224
52407
|
},
|
|
52225
52408
|
model: {
|
|
52226
52409
|
type: "string",
|
|
52227
|
-
description: 'Default model ID (e.g. "deepseek-
|
|
52410
|
+
description: 'Default model ID (e.g. "deepseek-v4-flash")'
|
|
52228
52411
|
}
|
|
52229
52412
|
},
|
|
52230
52413
|
required: ["name", "model"]
|
|
@@ -52349,7 +52532,7 @@ function createSettingsTools(ctx) {
|
|
|
52349
52532
|
},
|
|
52350
52533
|
id: {
|
|
52351
52534
|
type: "string",
|
|
52352
|
-
description: 'Model ID (e.g. "deepseek-
|
|
52535
|
+
description: 'Model ID (e.g. "deepseek-v4-flash")'
|
|
52353
52536
|
},
|
|
52354
52537
|
name: {
|
|
52355
52538
|
type: "string",
|
|
@@ -52875,7 +53058,7 @@ var init_dist3 = __esm({
|
|
|
52875
53058
|
|
|
52876
53059
|
// ../core/dist/agent-manager.js
|
|
52877
53060
|
import { join as join13 } from "node:path";
|
|
52878
|
-
import { mkdirSync as mkdirSync12, readFileSync as readFileSync13, existsSync as existsSync18, copyFileSync, rmSync, readdirSync as readdirSync4 } from "node:fs";
|
|
53061
|
+
import { mkdirSync as mkdirSync12, readFileSync as readFileSync13, existsSync as existsSync18, copyFileSync, rmSync, readdirSync as readdirSync4, writeFileSync as writeFileSync11 } from "node:fs";
|
|
52879
53062
|
import { homedir as homedir6 } from "node:os";
|
|
52880
53063
|
function resolveCurrentTaskId(agentObj, ts, agentId2) {
|
|
52881
53064
|
const activeTasks = agentObj?.getActiveTasks?.() ?? [];
|
|
@@ -53271,6 +53454,17 @@ You are ${request.name}.`,
|
|
|
53271
53454
|
}
|
|
53272
53455
|
}
|
|
53273
53456
|
}
|
|
53457
|
+
const heartbeatPath = join13(agentRoleDir, "HEARTBEAT.md");
|
|
53458
|
+
if (!existsSync18(heartbeatPath)) {
|
|
53459
|
+
writeFileSync11(heartbeatPath, [
|
|
53460
|
+
"# Heartbeat Checklist",
|
|
53461
|
+
"",
|
|
53462
|
+
"- [ ] Check mailbox for new messages and respond to urgent items",
|
|
53463
|
+
"- [ ] Review assigned tasks \u2014 update progress, unblock if possible",
|
|
53464
|
+
"- [ ] Check team announcements for new information",
|
|
53465
|
+
"- [ ] Scan recent channel messages for anything requiring attention"
|
|
53466
|
+
].join("\n"), "utf-8");
|
|
53467
|
+
}
|
|
53274
53468
|
const config = {
|
|
53275
53469
|
id,
|
|
53276
53470
|
name: request.name,
|
|
@@ -53436,7 +53630,8 @@ You are ${request.name}.`,
|
|
|
53436
53630
|
...this.groupChatHandlers ? {
|
|
53437
53631
|
sendGroupMessage: this.groupChatHandlers.sendGroupMessage,
|
|
53438
53632
|
createGroupChat: (name, memberIds) => this.groupChatHandlers.createGroupChat(name, id, config.name, memberIds),
|
|
53439
|
-
listGroupChats: this.groupChatHandlers.listGroupChats
|
|
53633
|
+
listGroupChats: this.groupChatHandlers.listGroupChats,
|
|
53634
|
+
getChannelMessages: this.groupChatHandlers.getChannelMessages
|
|
53440
53635
|
} : {}
|
|
53441
53636
|
};
|
|
53442
53637
|
for (const tool of createA2ATools(a2aContext))
|
|
@@ -54009,7 +54204,8 @@ You are ${row.name}.`,
|
|
|
54009
54204
|
...this.groupChatHandlers ? {
|
|
54010
54205
|
sendGroupMessage: this.groupChatHandlers.sendGroupMessage,
|
|
54011
54206
|
createGroupChat: (name, memberIds) => this.groupChatHandlers.createGroupChat(name, id, config.name, memberIds),
|
|
54012
|
-
listGroupChats: this.groupChatHandlers.listGroupChats
|
|
54207
|
+
listGroupChats: this.groupChatHandlers.listGroupChats,
|
|
54208
|
+
getChannelMessages: this.groupChatHandlers.getChannelMessages
|
|
54013
54209
|
} : {}
|
|
54014
54210
|
};
|
|
54015
54211
|
for (const tool of createA2ATools(a2aCtx))
|
|
@@ -55299,7 +55495,7 @@ var init_openai = __esm({
|
|
|
55299
55495
|
};
|
|
55300
55496
|
}
|
|
55301
55497
|
if (m.toolCalls?.length) {
|
|
55302
|
-
|
|
55498
|
+
const msg = {
|
|
55303
55499
|
role: "assistant",
|
|
55304
55500
|
content: getTextContent(m.content) || null,
|
|
55305
55501
|
tool_calls: m.toolCalls.map((tc) => ({
|
|
@@ -55308,6 +55504,17 @@ var init_openai = __esm({
|
|
|
55308
55504
|
function: { name: tc.name, arguments: JSON.stringify(tc.arguments) }
|
|
55309
55505
|
}))
|
|
55310
55506
|
};
|
|
55507
|
+
if (m.reasoningContent)
|
|
55508
|
+
msg.reasoning_content = m.reasoningContent;
|
|
55509
|
+
return msg;
|
|
55510
|
+
}
|
|
55511
|
+
if (m.role === "assistant" && m.reasoningContent) {
|
|
55512
|
+
const msg = {
|
|
55513
|
+
role: "assistant",
|
|
55514
|
+
content: typeof m.content === "string" ? m.content : getTextContent(m.content),
|
|
55515
|
+
reasoning_content: m.reasoningContent
|
|
55516
|
+
};
|
|
55517
|
+
return msg;
|
|
55311
55518
|
}
|
|
55312
55519
|
if (Array.isArray(m.content)) {
|
|
55313
55520
|
return {
|
|
@@ -55319,14 +55526,22 @@ var init_openai = __esm({
|
|
|
55319
55526
|
});
|
|
55320
55527
|
}
|
|
55321
55528
|
convertTools(tools) {
|
|
55322
|
-
|
|
55323
|
-
|
|
55324
|
-
|
|
55325
|
-
|
|
55326
|
-
|
|
55327
|
-
|
|
55328
|
-
|
|
55329
|
-
|
|
55529
|
+
const seen = /* @__PURE__ */ new Set();
|
|
55530
|
+
const unique = [];
|
|
55531
|
+
for (const t of tools) {
|
|
55532
|
+
if (seen.has(t.name))
|
|
55533
|
+
continue;
|
|
55534
|
+
seen.add(t.name);
|
|
55535
|
+
unique.push({
|
|
55536
|
+
type: "function",
|
|
55537
|
+
function: {
|
|
55538
|
+
name: t.name,
|
|
55539
|
+
description: t.description,
|
|
55540
|
+
parameters: t.inputSchema
|
|
55541
|
+
}
|
|
55542
|
+
});
|
|
55543
|
+
}
|
|
55544
|
+
return unique;
|
|
55330
55545
|
}
|
|
55331
55546
|
async chatStream(request, onEvent, signal) {
|
|
55332
55547
|
const messages = this.convertMessages(request.messages);
|
|
@@ -55373,6 +55588,7 @@ var init_openai = __esm({
|
|
|
55373
55588
|
throw new Error(`OpenAI API error ${res.status}: ${errText}`);
|
|
55374
55589
|
}
|
|
55375
55590
|
let content = "";
|
|
55591
|
+
let reasoningContent = "";
|
|
55376
55592
|
const toolCalls = /* @__PURE__ */ new Map();
|
|
55377
55593
|
let finishReason = "end_turn";
|
|
55378
55594
|
let promptTokens = 0;
|
|
@@ -55398,9 +55614,10 @@ var init_openai = __esm({
|
|
|
55398
55614
|
try {
|
|
55399
55615
|
const chunk = JSON.parse(trimmed.slice(6));
|
|
55400
55616
|
const choice = chunk.choices?.[0];
|
|
55401
|
-
const
|
|
55402
|
-
if (
|
|
55403
|
-
|
|
55617
|
+
const deltaReasoning = choice?.delta?.reasoning_content ?? choice?.delta?.reasoning_details ?? choice?.delta?.thinking;
|
|
55618
|
+
if (deltaReasoning) {
|
|
55619
|
+
reasoningContent += deltaReasoning;
|
|
55620
|
+
onEvent({ type: "thinking_delta", thinking: deltaReasoning });
|
|
55404
55621
|
}
|
|
55405
55622
|
if (choice?.delta?.content) {
|
|
55406
55623
|
content += choice.delta.content;
|
|
@@ -55451,12 +55668,15 @@ var init_openai = __esm({
|
|
|
55451
55668
|
});
|
|
55452
55669
|
const usage = { inputTokens: promptTokens, outputTokens: completionTokens };
|
|
55453
55670
|
onEvent({ type: "message_end", usage, finishReason });
|
|
55454
|
-
|
|
55671
|
+
const streamResult = {
|
|
55455
55672
|
content,
|
|
55456
55673
|
toolCalls: resultToolCalls.length ? resultToolCalls : void 0,
|
|
55457
55674
|
usage,
|
|
55458
55675
|
finishReason
|
|
55459
55676
|
};
|
|
55677
|
+
if (reasoningContent)
|
|
55678
|
+
streamResult.reasoningContent = reasoningContent;
|
|
55679
|
+
return streamResult;
|
|
55460
55680
|
}
|
|
55461
55681
|
convertResponse(data) {
|
|
55462
55682
|
const choice = data.choices[0];
|
|
@@ -55473,7 +55693,7 @@ var init_openai = __esm({
|
|
|
55473
55693
|
tool_calls: "tool_use",
|
|
55474
55694
|
length: "max_tokens"
|
|
55475
55695
|
};
|
|
55476
|
-
|
|
55696
|
+
const result = {
|
|
55477
55697
|
content: typeof msg.content === "string" ? msg.content : "",
|
|
55478
55698
|
toolCalls: toolCalls?.length ? toolCalls : void 0,
|
|
55479
55699
|
usage: {
|
|
@@ -55482,6 +55702,9 @@ var init_openai = __esm({
|
|
|
55482
55702
|
},
|
|
55483
55703
|
finishReason: finishMap[choice.finish_reason] ?? "end_turn"
|
|
55484
55704
|
};
|
|
55705
|
+
if (msg.reasoning_content)
|
|
55706
|
+
result.reasoningContent = msg.reasoning_content;
|
|
55707
|
+
return result;
|
|
55485
55708
|
}
|
|
55486
55709
|
};
|
|
55487
55710
|
}
|
|
@@ -55946,7 +56169,7 @@ var init_ollama = __esm({
|
|
|
55946
56169
|
});
|
|
55947
56170
|
|
|
55948
56171
|
// ../core/dist/llm/auth-profiles.js
|
|
55949
|
-
import { readFileSync as readFileSync14, writeFileSync as
|
|
56172
|
+
import { readFileSync as readFileSync14, writeFileSync as writeFileSync12, mkdirSync as mkdirSync13, existsSync as existsSync19, unlinkSync as unlinkSync2 } from "node:fs";
|
|
55950
56173
|
import { join as join14 } from "node:path";
|
|
55951
56174
|
import { homedir as homedir7 } from "node:os";
|
|
55952
56175
|
var log34, AuthProfileStore;
|
|
@@ -55977,7 +56200,7 @@ var init_auth_profiles = __esm({
|
|
|
55977
56200
|
}
|
|
55978
56201
|
}
|
|
55979
56202
|
write(data) {
|
|
55980
|
-
|
|
56203
|
+
writeFileSync12(this.filePath, JSON.stringify(data, null, 2) + "\n", { mode: 384 });
|
|
55981
56204
|
}
|
|
55982
56205
|
/**
|
|
55983
56206
|
* Acquire a simple filesystem lock for atomic profile updates (token refresh).
|
|
@@ -55986,7 +56209,7 @@ var init_auth_profiles = __esm({
|
|
|
55986
56209
|
acquireLock() {
|
|
55987
56210
|
const lockContent = `${process.pid}-${Date.now()}`;
|
|
55988
56211
|
try {
|
|
55989
|
-
|
|
56212
|
+
writeFileSync12(this.lockPath, lockContent, { flag: "wx" });
|
|
55990
56213
|
return () => {
|
|
55991
56214
|
try {
|
|
55992
56215
|
unlinkSync2(this.lockPath);
|
|
@@ -55998,7 +56221,7 @@ var init_auth_profiles = __esm({
|
|
|
55998
56221
|
const existing = readFileSync14(this.lockPath, "utf-8");
|
|
55999
56222
|
const ts = Number(existing.split("-").pop());
|
|
56000
56223
|
if (Date.now() - ts > 3e4) {
|
|
56001
|
-
|
|
56224
|
+
writeFileSync12(this.lockPath, lockContent, { mode: 384 });
|
|
56002
56225
|
return () => {
|
|
56003
56226
|
try {
|
|
56004
56227
|
unlinkSync2(this.lockPath);
|
|
@@ -56215,7 +56438,7 @@ var init_oauth_manager = __esm({
|
|
|
56215
56438
|
const state = randomBytes2(16).toString("hex");
|
|
56216
56439
|
const port = config.callbackPort ?? 1455;
|
|
56217
56440
|
const redirectUri = `http://localhost:${port}/auth/callback`;
|
|
56218
|
-
const promise = new Promise((
|
|
56441
|
+
const promise = new Promise((resolve20, reject) => {
|
|
56219
56442
|
const pending = {
|
|
56220
56443
|
provider,
|
|
56221
56444
|
state,
|
|
@@ -56224,7 +56447,7 @@ var init_oauth_manager = __esm({
|
|
|
56224
56447
|
redirectUri,
|
|
56225
56448
|
resolve: (tokens) => {
|
|
56226
56449
|
const profile = this.profileStore.createOAuthProfile(provider, tokens, `${provider} (${tokens.accountId ?? "OAuth"})`);
|
|
56227
|
-
|
|
56450
|
+
resolve20(profile);
|
|
56228
56451
|
},
|
|
56229
56452
|
reject
|
|
56230
56453
|
};
|
|
@@ -56580,7 +56803,7 @@ var init_router = __esm({
|
|
|
56580
56803
|
*/
|
|
56581
56804
|
static isNonRetryableError(error) {
|
|
56582
56805
|
const msg = error instanceof Error ? error.message : String(error);
|
|
56583
|
-
return /\b(402|403
|
|
56806
|
+
return /\b(401|402|403)\b/.test(msg) || /insufficient balance/i.test(msg) || /not available in your region/i.test(msg) || /invalid.*api.*key/i.test(msg) || /authentication/i.test(msg) || /\b400\b.*invalid_request_error/i.test(msg) || /reasoning_content.*must be passed back/i.test(msg);
|
|
56584
56807
|
}
|
|
56585
56808
|
/** Detect rate-limit (429) errors which should use a shorter circuit breaker cooldown. */
|
|
56586
56809
|
static isRateLimitError(error) {
|
|
@@ -56793,14 +57016,25 @@ var init_router = __esm({
|
|
|
56793
57016
|
return "simple";
|
|
56794
57017
|
}
|
|
56795
57018
|
selectProvider(request, explicit) {
|
|
56796
|
-
if (explicit)
|
|
57019
|
+
if (explicit && this.isAvailable(explicit))
|
|
56797
57020
|
return explicit;
|
|
57021
|
+
if (explicit && this.disabledProviders.has(explicit)) {
|
|
57022
|
+
log36.warn(`Explicit provider ${explicit} is disabled \u2014 falling through to auto-select`);
|
|
57023
|
+
}
|
|
56798
57024
|
if (!this.autoSelect || this.providerTiers.length === 0) {
|
|
56799
57025
|
if (this.isAvailable(this.defaultProvider) && this.providers.has(this.defaultProvider)) {
|
|
56800
57026
|
return this.defaultProvider;
|
|
56801
57027
|
}
|
|
56802
57028
|
const healthy2 = [...this.providers.keys()].find((n) => this.isAvailable(n));
|
|
56803
|
-
|
|
57029
|
+
if (healthy2)
|
|
57030
|
+
return healthy2;
|
|
57031
|
+
const enabledAny2 = [...this.providers.keys()].find((n) => !this.disabledProviders.has(n));
|
|
57032
|
+
if (enabledAny2) {
|
|
57033
|
+
log36.warn(`All providers degraded \u2014 using enabled provider ${enabledAny2} as last resort`);
|
|
57034
|
+
return enabledAny2;
|
|
57035
|
+
}
|
|
57036
|
+
log36.warn("All providers disabled or degraded \u2014 using default as last resort");
|
|
57037
|
+
return this.defaultProvider;
|
|
56804
57038
|
}
|
|
56805
57039
|
const complexity = _LLMRouter.assessComplexity(request);
|
|
56806
57040
|
const match = this.providerTiers.find((t) => t.complexity.includes(complexity) && this.providers.has(t.name) && this.isAvailable(t.name));
|
|
@@ -56813,7 +57047,12 @@ var init_router = __esm({
|
|
|
56813
57047
|
log36.warn(`All tiered providers degraded for complexity=${complexity}, falling back to: ${healthy}`);
|
|
56814
57048
|
return healthy;
|
|
56815
57049
|
}
|
|
56816
|
-
|
|
57050
|
+
const enabledAny = [...this.providers.keys()].find((n) => !this.disabledProviders.has(n));
|
|
57051
|
+
if (enabledAny) {
|
|
57052
|
+
log36.warn(`All providers degraded \u2014 using enabled provider ${enabledAny} as last resort`);
|
|
57053
|
+
return enabledAny;
|
|
57054
|
+
}
|
|
57055
|
+
log36.warn("All providers disabled or degraded \u2014 using default as last resort");
|
|
56817
57056
|
return this.defaultProvider;
|
|
56818
57057
|
}
|
|
56819
57058
|
getFallbacks(primary) {
|
|
@@ -57102,7 +57341,7 @@ var init_router = __esm({
|
|
|
57102
57341
|
for (const [name, p] of this.providers.entries()) {
|
|
57103
57342
|
providers[name] = { model: p.model, configured: true };
|
|
57104
57343
|
}
|
|
57105
|
-
for (const name of ["anthropic", "openai", "openai-codex", "google", "ollama", "minimax", "siliconflow", "openrouter", "zai"]) {
|
|
57344
|
+
for (const name of ["anthropic", "openai", "openai-codex", "google", "ollama", "minimax", "siliconflow", "openrouter", "zai", "deepseek"]) {
|
|
57106
57345
|
if (!providers[name]) {
|
|
57107
57346
|
providers[name] = { model: "", configured: false };
|
|
57108
57347
|
}
|
|
@@ -57134,7 +57373,7 @@ var init_router = __esm({
|
|
|
57134
57373
|
oauthAccountId: oauthProfile?.oauth?.accountId
|
|
57135
57374
|
};
|
|
57136
57375
|
}
|
|
57137
|
-
for (const name of ["anthropic", "openai", "openai-codex", "google", "ollama", "minimax", "siliconflow", "openrouter", "zai"]) {
|
|
57376
|
+
for (const name of ["anthropic", "openai", "openai-codex", "google", "ollama", "minimax", "siliconflow", "openrouter", "zai", "deepseek"]) {
|
|
57138
57377
|
if (!providers[name]) {
|
|
57139
57378
|
const oauthProfile = this._profileStore?.getDefaultProfile(name);
|
|
57140
57379
|
const builtinModels = BUILTIN_MODEL_CATALOG.filter((m) => m.provider === name);
|
|
@@ -57189,6 +57428,13 @@ var init_router = __esm({
|
|
|
57189
57428
|
this.disabledProviders.delete(providerName);
|
|
57190
57429
|
} else {
|
|
57191
57430
|
this.disabledProviders.add(providerName);
|
|
57431
|
+
if (this.defaultProvider === providerName) {
|
|
57432
|
+
const replacement = [...this.providers.keys()].find((n) => !this.disabledProviders.has(n));
|
|
57433
|
+
if (replacement) {
|
|
57434
|
+
log36.info(`Default provider ${providerName} disabled \u2014 switching default to ${replacement}`);
|
|
57435
|
+
this.defaultProvider = replacement;
|
|
57436
|
+
}
|
|
57437
|
+
}
|
|
57192
57438
|
}
|
|
57193
57439
|
log36.info(`Provider ${providerName} ${enabled ? "enabled" : "disabled"}`);
|
|
57194
57440
|
}
|
|
@@ -57301,7 +57547,8 @@ var init_router = __esm({
|
|
|
57301
57547
|
siliconflow: "SiliconFlow",
|
|
57302
57548
|
minimax: "MiniMax",
|
|
57303
57549
|
openrouter: "OpenRouter",
|
|
57304
|
-
zai: "ZAI"
|
|
57550
|
+
zai: "ZAI",
|
|
57551
|
+
deepseek: "DeepSeek"
|
|
57305
57552
|
};
|
|
57306
57553
|
BUILTIN_MODEL_CATALOG = [
|
|
57307
57554
|
// Anthropic — https://docs.anthropic.com/claude/reference/input-and-output-sizes
|
|
@@ -57325,7 +57572,12 @@ var init_router = __esm({
|
|
|
57325
57572
|
{ id: "xiaomi/mimo-v2-pro", name: "MiMo-V2-Pro", provider: "openrouter", contextWindow: 1048576, maxOutputTokens: 131072, cost: { input: 1, output: 3, cacheRead: 0.2 }, reasoning: true, inputTypes: ["text"] },
|
|
57326
57573
|
{ id: "anthropic/claude-opus-4-6", name: "Claude Opus 4.6 (via OpenRouter)", provider: "openrouter", contextWindow: 1e6, maxOutputTokens: 128e3, cost: { input: 5, output: 25, cacheRead: 0.5, cacheWrite: 6.25 }, reasoning: true, inputTypes: ["text", "image"] },
|
|
57327
57574
|
{ id: "openai/gpt-5.4", name: "GPT-5.4 (via OpenRouter)", provider: "openrouter", contextWindow: 11e5, maxOutputTokens: 128e3, cost: { input: 2.5, output: 15, cacheRead: 0.25 }, reasoning: true, inputTypes: ["text", "image"] },
|
|
57328
|
-
{ id: "google/gemini-3-1-pro", name: "Gemini 3.1 Pro (via OpenRouter)", provider: "openrouter", contextWindow: 1e6, maxOutputTokens: 65536, cost: { input: 2, output: 12 }, reasoning: true, inputTypes: ["text", "image"] }
|
|
57575
|
+
{ id: "google/gemini-3-1-pro", name: "Gemini 3.1 Pro (via OpenRouter)", provider: "openrouter", contextWindow: 1e6, maxOutputTokens: 65536, cost: { input: 2, output: 12 }, reasoning: true, inputTypes: ["text", "image"] },
|
|
57576
|
+
// DeepSeek — https://api-docs.deepseek.com/
|
|
57577
|
+
{ id: "deepseek-v4-flash", name: "DeepSeek-V4-Flash", provider: "deepseek", contextWindow: 1e6, maxOutputTokens: 384e3, cost: { input: 0.14, output: 0.28, cacheRead: 0.028 }, reasoning: true, inputTypes: ["text"] },
|
|
57578
|
+
{ id: "deepseek-v4-pro", name: "DeepSeek-V4-Pro", provider: "deepseek", contextWindow: 1e6, maxOutputTokens: 384e3, cost: { input: 1.67, output: 3.33, cacheRead: 0.14 }, reasoning: true, inputTypes: ["text"] },
|
|
57579
|
+
{ id: "deepseek-chat", name: "DeepSeek-Chat (legacy)", provider: "deepseek", contextWindow: 65536, maxOutputTokens: 8192, cost: { input: 0.14, output: 0.28, cacheRead: 0.028 }, reasoning: false, inputTypes: ["text"] },
|
|
57580
|
+
{ id: "deepseek-reasoner", name: "DeepSeek-Reasoner (legacy)", provider: "deepseek", contextWindow: 65536, maxOutputTokens: 8192, cost: { input: 0.55, output: 2.19, cacheRead: 0.14 }, reasoning: true, inputTypes: ["text"] }
|
|
57329
57581
|
];
|
|
57330
57582
|
}
|
|
57331
57583
|
});
|
|
@@ -58186,7 +58438,7 @@ var init_registry = __esm({
|
|
|
58186
58438
|
|
|
58187
58439
|
// ../core/dist/skills/loader.js
|
|
58188
58440
|
import { readFileSync as readFileSync15, readdirSync as readdirSync5, existsSync as existsSync20 } from "node:fs";
|
|
58189
|
-
import { join as join16, resolve as
|
|
58441
|
+
import { join as join16, resolve as resolve9 } from "node:path";
|
|
58190
58442
|
function resolveMcpServerPaths(servers, skillDir) {
|
|
58191
58443
|
if (!servers)
|
|
58192
58444
|
return void 0;
|
|
@@ -59152,7 +59404,7 @@ var init_composition = __esm({
|
|
|
59152
59404
|
|
|
59153
59405
|
// ../core/dist/workflow/team-template.js
|
|
59154
59406
|
import { readdirSync as readdirSync7, readFileSync as readFileSync17, existsSync as existsSync22 } from "node:fs";
|
|
59155
|
-
import { join as join18, resolve as
|
|
59407
|
+
import { join as join18, resolve as resolve10, dirname as dirname5 } from "node:path";
|
|
59156
59408
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
59157
59409
|
function loadTeamTemplateFromDir(dirPath) {
|
|
59158
59410
|
const fsHelper = { existsSync: existsSync22, readFileSync: (p, _enc) => readFileSync17(p, "utf-8"), join: join18 };
|
|
@@ -59193,16 +59445,16 @@ function createDefaultTeamTemplates() {
|
|
|
59193
59445
|
const thisFile = fileURLToPath3(import.meta.url);
|
|
59194
59446
|
const thisDir = dirname5(thisFile);
|
|
59195
59447
|
const candidates = [
|
|
59196
|
-
|
|
59448
|
+
resolve10(thisDir, "..", "templates", "teams"),
|
|
59197
59449
|
// npm global: dist/ → ../templates/teams
|
|
59198
|
-
|
|
59450
|
+
resolve10(thisDir, "..", "..", "..", "..", "templates", "teams"),
|
|
59199
59451
|
// monorepo: packages/core/dist/workflow/ → root
|
|
59200
|
-
|
|
59452
|
+
resolve10(process.cwd(), "templates", "teams")
|
|
59201
59453
|
// cwd fallback
|
|
59202
59454
|
];
|
|
59203
59455
|
templatesDir = candidates.find((d) => existsSync22(d)) ?? candidates[candidates.length - 1];
|
|
59204
59456
|
} catch {
|
|
59205
|
-
templatesDir =
|
|
59457
|
+
templatesDir = resolve10(process.cwd(), "templates", "teams");
|
|
59206
59458
|
}
|
|
59207
59459
|
if (!existsSync22(templatesDir)) {
|
|
59208
59460
|
log47.warn(`Team templates directory not found: ${templatesDir}`);
|
|
@@ -59348,7 +59600,7 @@ var init_dist4 = __esm({
|
|
|
59348
59600
|
});
|
|
59349
59601
|
|
|
59350
59602
|
// ../org-manager/dist/org-service.js
|
|
59351
|
-
import { mkdirSync as mkdirSync15, writeFileSync as
|
|
59603
|
+
import { mkdirSync as mkdirSync15, writeFileSync as writeFileSync13, existsSync as existsSync23, rmSync as rmSync2 } from "node:fs";
|
|
59352
59604
|
import { join as join19 } from "node:path";
|
|
59353
59605
|
import { homedir as homedir10 } from "node:os";
|
|
59354
59606
|
var log50, OrganizationService;
|
|
@@ -59482,15 +59734,15 @@ var init_org_service = __esm({
|
|
|
59482
59734
|
mkdirSync15(dir, { recursive: true });
|
|
59483
59735
|
const annPath = join19(dir, "ANNOUNCEMENT.md");
|
|
59484
59736
|
if (announcements) {
|
|
59485
|
-
|
|
59737
|
+
writeFileSync13(annPath, announcements, "utf-8");
|
|
59486
59738
|
} else if (!existsSync23(annPath)) {
|
|
59487
|
-
|
|
59739
|
+
writeFileSync13(annPath, "", "utf-8");
|
|
59488
59740
|
}
|
|
59489
59741
|
const normsPath = join19(dir, "NORMS.md");
|
|
59490
59742
|
if (norms) {
|
|
59491
|
-
|
|
59743
|
+
writeFileSync13(normsPath, norms, "utf-8");
|
|
59492
59744
|
} else if (!existsSync23(normsPath)) {
|
|
59493
|
-
|
|
59745
|
+
writeFileSync13(normsPath, "", "utf-8");
|
|
59494
59746
|
}
|
|
59495
59747
|
}
|
|
59496
59748
|
async createTeam(orgId2, name, description) {
|
|
@@ -60226,8 +60478,8 @@ var init_org_service = __esm({
|
|
|
60226
60478
|
});
|
|
60227
60479
|
|
|
60228
60480
|
// ../org-manager/dist/task-service.js
|
|
60229
|
-
import { mkdirSync as mkdirSync16, writeFileSync as
|
|
60230
|
-
import { join as join20, resolve as
|
|
60481
|
+
import { mkdirSync as mkdirSync16, writeFileSync as writeFileSync14, readFileSync as readFileSync18, existsSync as existsSync24, cpSync } from "node:fs";
|
|
60482
|
+
import { join as join20, resolve as resolve11 } from "node:path";
|
|
60231
60483
|
import { homedir as homedir11 } from "node:os";
|
|
60232
60484
|
function formatLocalTimestamp(d = /* @__PURE__ */ new Date()) {
|
|
60233
60485
|
const pad = (n) => String(n).padStart(2, "0");
|
|
@@ -60579,7 +60831,7 @@ var init_task_service = __esm({
|
|
|
60579
60831
|
mkdirSync16(join20(dir, "knowledge"), { recursive: true });
|
|
60580
60832
|
const userMdPath = join20(dir, "USER.md");
|
|
60581
60833
|
if (!existsSync24(userMdPath)) {
|
|
60582
|
-
|
|
60834
|
+
writeFileSync14(userMdPath, [
|
|
60583
60835
|
"# About the Owner",
|
|
60584
60836
|
"",
|
|
60585
60837
|
"- Name:",
|
|
@@ -60628,6 +60880,10 @@ var init_task_service = __esm({
|
|
|
60628
60880
|
const lower = errorContent.toLowerCase();
|
|
60629
60881
|
return lower.includes("econnreset") || lower.includes("econnrefused") || lower.includes("etimedout") || lower.includes("fetch failed") || lower.includes("aborterror") || lower.includes("aborted") || lower.includes("socket hang up") || lower.includes("network");
|
|
60630
60882
|
}
|
|
60883
|
+
static isNonRetryableError(errorContent) {
|
|
60884
|
+
const lower = errorContent.toLowerCase();
|
|
60885
|
+
return lower.includes("invalid_request_error") && /\b400\b/.test(errorContent) || lower.includes("reasoning_content") || lower.includes("invalid api key") || lower.includes("insufficient balance") || /\b(401|402|403)\b/.test(errorContent) && !lower.includes("rate");
|
|
60886
|
+
}
|
|
60631
60887
|
shouldRetryTask(taskId2, errorContent, retryAttempt, cancelled) {
|
|
60632
60888
|
if (cancelled)
|
|
60633
60889
|
return { shouldRetry: false, reason: "cancelled" };
|
|
@@ -60638,6 +60894,9 @@ var init_task_service = __esm({
|
|
|
60638
60894
|
if (retryAttempt >= _TaskService.MAX_IN_PROGRESS_RETRIES) {
|
|
60639
60895
|
return { shouldRetry: false, reason: `exceeded max retries (${_TaskService.MAX_IN_PROGRESS_RETRIES})` };
|
|
60640
60896
|
}
|
|
60897
|
+
if (_TaskService.isNonRetryableError(errorContent)) {
|
|
60898
|
+
return { shouldRetry: false, reason: "non-retryable error (auth/billing/request)" };
|
|
60899
|
+
}
|
|
60641
60900
|
const normalizedError = errorContent.replace(/\d{4}-\d{2}-\d{2}T[\d:.]+Z?/g, "").trim().slice(0, 200);
|
|
60642
60901
|
const tracker = this.taskRetryErrors.get(taskId2);
|
|
60643
60902
|
if (tracker && tracker.lastError === normalizedError) {
|
|
@@ -61607,7 +61866,7 @@ ${c.content}`;
|
|
|
61607
61866
|
});
|
|
61608
61867
|
if (this.hitlService && request.createdBy && request.createdBy !== "default") {
|
|
61609
61868
|
this.hitlService.notify({
|
|
61610
|
-
targetUserId: "
|
|
61869
|
+
targetUserId: "all",
|
|
61611
61870
|
type: "task_created",
|
|
61612
61871
|
title: `Task created: ${task.title}`,
|
|
61613
61872
|
body: `Agent created task "${task.title}"`,
|
|
@@ -61874,7 +62133,7 @@ Action: ${guidance}` : ""
|
|
|
61874
62133
|
const notifType = to === "completed" ? "task_completed" : to === "review" ? "task_review" : "task_failed";
|
|
61875
62134
|
const priority = to === "failed" ? "high" : "normal";
|
|
61876
62135
|
this.hitlService.notify({
|
|
61877
|
-
targetUserId: "
|
|
62136
|
+
targetUserId: "all",
|
|
61878
62137
|
type: notifType,
|
|
61879
62138
|
title: to === "review" ? `Task ready for review: ${task.title}` : to === "completed" ? `Task completed: ${task.title}` : `Task failed: ${task.title}`,
|
|
61880
62139
|
body: `Task "${task.title}" status changed to ${to}`,
|
|
@@ -62645,10 +62904,11 @@ Action: ${guidance}` : ""
|
|
|
62645
62904
|
testResults: d.testResults
|
|
62646
62905
|
}))
|
|
62647
62906
|
};
|
|
62648
|
-
|
|
62907
|
+
writeFileSync14(join20(taskSharedDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
62649
62908
|
for (const d of deliverables) {
|
|
62909
|
+
let src;
|
|
62650
62910
|
if (d.type === "file" && d.reference) {
|
|
62651
|
-
|
|
62911
|
+
src = resolve11(d.reference);
|
|
62652
62912
|
if (existsSync24(src)) {
|
|
62653
62913
|
try {
|
|
62654
62914
|
const destName = src.split("/").pop() ?? "deliverable";
|
|
@@ -62658,9 +62918,10 @@ Action: ${guidance}` : ""
|
|
|
62658
62918
|
}
|
|
62659
62919
|
}
|
|
62660
62920
|
}
|
|
62661
|
-
if (d.type === "file" && d.summary && !existsSync24(
|
|
62662
|
-
const
|
|
62663
|
-
|
|
62921
|
+
if (d.type === "file" && d.summary && src && !existsSync24(src)) {
|
|
62922
|
+
const baseName = d.reference.split("/").pop() ?? "deliverable";
|
|
62923
|
+
const safeName = baseName.replace(/[^a-zA-Z0-9_\u4e00-\u9fff.-]/g, "_").slice(0, 80);
|
|
62924
|
+
writeFileSync14(join20(taskSharedDir, `${safeName}.md`), d.summary);
|
|
62664
62925
|
}
|
|
62665
62926
|
}
|
|
62666
62927
|
log51.info("Deliverables published to shared workspace", { taskId: task.id, dir: taskSharedDir });
|
|
@@ -63486,7 +63747,7 @@ ${task.description}`;
|
|
|
63486
63747
|
|
|
63487
63748
|
// ../org-manager/dist/builder-service.js
|
|
63488
63749
|
import { join as join21 } from "node:path";
|
|
63489
|
-
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync25, writeFileSync as
|
|
63750
|
+
import { readdirSync as readdirSync8, readFileSync as readFileSync19, existsSync as existsSync25, writeFileSync as writeFileSync15, mkdirSync as mkdirSync17, copyFileSync as copyFileSync2, statSync as statSync4, cpSync as cpSync2 } from "node:fs";
|
|
63490
63751
|
import { homedir as homedir12 } from "node:os";
|
|
63491
63752
|
var log52, FS_HELPER, BuilderService;
|
|
63492
63753
|
var init_builder_service = __esm({
|
|
@@ -63592,7 +63853,7 @@ var init_builder_service = __esm({
|
|
|
63592
63853
|
copyFileSync2(srcFile, join21(agentRoleDir, fname));
|
|
63593
63854
|
}
|
|
63594
63855
|
}
|
|
63595
|
-
|
|
63856
|
+
writeFileSync15(join21(agentRoleDir, ".role-origin.json"), JSON.stringify({ customRole: true, source: "builder-artifact", artifact: artifactName, artifactType: "agent" }));
|
|
63596
63857
|
agent.reloadRole();
|
|
63597
63858
|
await agentManager.startAgent(agent.id);
|
|
63598
63859
|
return {
|
|
@@ -63654,7 +63915,7 @@ var init_builder_service = __esm({
|
|
|
63654
63915
|
}
|
|
63655
63916
|
}
|
|
63656
63917
|
}
|
|
63657
|
-
|
|
63918
|
+
writeFileSync15(join21(agentRoleDir, ".role-origin.json"), JSON.stringify({ customRole: true, source: "builder-artifact", artifact: artifactName, artifactType: "team" }));
|
|
63658
63919
|
agent.reloadRole();
|
|
63659
63920
|
if (memberRole === "manager") {
|
|
63660
63921
|
await this.orgService.updateTeam(team.id, { managerId: agent.id, managerType: "agent" });
|
|
@@ -64369,23 +64630,6 @@ var init_sse_handler = __esm({
|
|
|
64369
64630
|
this.sseBuffer.sendProgress(this.processedTokens, this.totalTokens, `\u5DE5\u5177\u6267\u884C\u5B8C\u6210: ${event.tool}`);
|
|
64370
64631
|
}
|
|
64371
64632
|
} else if (event.type === "message_end") {
|
|
64372
|
-
const now2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
64373
|
-
let turnThinking;
|
|
64374
|
-
if (this.thinkingBuf) {
|
|
64375
|
-
this.sseBuffer.send({ type: "thinking_commit", thinking: this.thinkingBuf, createdAt: now2 });
|
|
64376
|
-
turnThinking = this.thinkingBuf;
|
|
64377
|
-
this.thinkingBuf = "";
|
|
64378
|
-
}
|
|
64379
|
-
if (this.textBuf) {
|
|
64380
|
-
this.sseBuffer.send({ type: "text_commit", text: this.textBuf, createdAt: now2 });
|
|
64381
|
-
const seg2 = { type: "text", content: this.textBuf, createdAt: now2 };
|
|
64382
|
-
if (turnThinking)
|
|
64383
|
-
seg2.thinking = turnThinking;
|
|
64384
|
-
this.msgSegments.push(seg2);
|
|
64385
|
-
this.textBuf = "";
|
|
64386
|
-
} else if (turnThinking) {
|
|
64387
|
-
this.msgSegments.push({ type: "text", content: "", thinking: turnThinking, createdAt: now2 });
|
|
64388
|
-
}
|
|
64389
64633
|
if (event.usage?.outputTokens) {
|
|
64390
64634
|
this.totalTokens = Math.max(this.totalTokens, event.usage.outputTokens);
|
|
64391
64635
|
this.processedTokens = event.usage.outputTokens;
|
|
@@ -64458,8 +64702,8 @@ var init_sse_handler = __esm({
|
|
|
64458
64702
|
});
|
|
64459
64703
|
|
|
64460
64704
|
// ../org-manager/dist/skill-service.js
|
|
64461
|
-
import { join as join22, resolve as
|
|
64462
|
-
import { existsSync as existsSync26, writeFileSync as
|
|
64705
|
+
import { join as join22, resolve as resolve12 } from "node:path";
|
|
64706
|
+
import { existsSync as existsSync26, writeFileSync as writeFileSync16, mkdirSync as mkdirSync18, readFileSync as readFileSync20, readdirSync as readdirSync9, copyFileSync as copyFileSync3 } from "node:fs";
|
|
64463
64707
|
import { homedir as homedir13 } from "node:os";
|
|
64464
64708
|
import { execSync as execSync2 } from "node:child_process";
|
|
64465
64709
|
async function searchSkillHub(query2) {
|
|
@@ -64593,7 +64837,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64593
64837
|
let installed = false;
|
|
64594
64838
|
let installMethod = "metadata-only";
|
|
64595
64839
|
if (source === "builtin") {
|
|
64596
|
-
const builtinDir =
|
|
64840
|
+
const builtinDir = resolve12(process.cwd(), "templates", "skills", safeName);
|
|
64597
64841
|
if (existsSync26(builtinDir)) {
|
|
64598
64842
|
mkdirSync18(targetDir, { recursive: true });
|
|
64599
64843
|
for (const file of readdirSync9(builtinDir)) {
|
|
@@ -64610,7 +64854,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64610
64854
|
if (zipResp.ok) {
|
|
64611
64855
|
const tmpZip = join22(skillsDir, `_tmp_${safeName}.zip`);
|
|
64612
64856
|
const buffer = Buffer.from(await zipResp.arrayBuffer());
|
|
64613
|
-
|
|
64857
|
+
writeFileSync16(tmpZip, buffer);
|
|
64614
64858
|
mkdirSync18(targetDir, { recursive: true });
|
|
64615
64859
|
try {
|
|
64616
64860
|
execSync2(`unzip -o "${tmpZip}" -d "${targetDir}"`, { timeout: 3e4 });
|
|
@@ -64636,7 +64880,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64636
64880
|
const mdResp = await fetch(skillMdUrl, { signal: AbortSignal.timeout(15e3) });
|
|
64637
64881
|
if (mdResp.ok) {
|
|
64638
64882
|
mkdirSync18(targetDir, { recursive: true });
|
|
64639
|
-
|
|
64883
|
+
writeFileSync16(join22(targetDir, "SKILL.md"), await mdResp.text(), "utf-8");
|
|
64640
64884
|
installed = true;
|
|
64641
64885
|
installMethod = "github-skillmd";
|
|
64642
64886
|
}
|
|
@@ -64650,7 +64894,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64650
64894
|
const mdResp = await fetch(rootMd, { signal: AbortSignal.timeout(15e3) });
|
|
64651
64895
|
if (mdResp.ok) {
|
|
64652
64896
|
mkdirSync18(targetDir, { recursive: true });
|
|
64653
|
-
|
|
64897
|
+
writeFileSync16(join22(targetDir, "SKILL.md"), await mdResp.text(), "utf-8");
|
|
64654
64898
|
installed = true;
|
|
64655
64899
|
installMethod = "github-root-skillmd";
|
|
64656
64900
|
}
|
|
@@ -64666,7 +64910,7 @@ async function installSkill(request, skillRegistry) {
|
|
|
64666
64910
|
if (zipResp.ok) {
|
|
64667
64911
|
const tmpZip = join22(skillsDir, `_tmp_${safeName}.zip`);
|
|
64668
64912
|
const buffer = Buffer.from(await zipResp.arrayBuffer());
|
|
64669
|
-
|
|
64913
|
+
writeFileSync16(tmpZip, buffer);
|
|
64670
64914
|
mkdirSync18(targetDir, { recursive: true });
|
|
64671
64915
|
try {
|
|
64672
64916
|
execSync2(`unzip -o "${tmpZip}" -d "${targetDir}"`, { timeout: 3e4 });
|
|
@@ -64698,13 +64942,13 @@ async function installSkill(request, skillRegistry) {
|
|
|
64698
64942
|
};
|
|
64699
64943
|
const manifest = buildManifest("skill", raw);
|
|
64700
64944
|
manifest.source = skillSource;
|
|
64701
|
-
|
|
64945
|
+
writeFileSync16(skillMfPath, JSON.stringify(manifest, null, 2), "utf-8");
|
|
64702
64946
|
} else {
|
|
64703
64947
|
try {
|
|
64704
64948
|
const mf = JSON.parse(readFileSync20(skillMfPath, "utf-8"));
|
|
64705
64949
|
if (!mf.source) {
|
|
64706
64950
|
mf.source = skillSource;
|
|
64707
|
-
|
|
64951
|
+
writeFileSync16(skillMfPath, JSON.stringify(mf, null, 2), "utf-8");
|
|
64708
64952
|
}
|
|
64709
64953
|
} catch {
|
|
64710
64954
|
}
|
|
@@ -64737,8 +64981,8 @@ var init_skill_service = __esm({
|
|
|
64737
64981
|
|
|
64738
64982
|
// ../org-manager/dist/api-server.js
|
|
64739
64983
|
import { createServer as createServer2 } from "node:http";
|
|
64740
|
-
import { join as join23, resolve as
|
|
64741
|
-
import { readdirSync as readdirSync10, readFileSync as readFileSync21, existsSync as existsSync27, writeFileSync as
|
|
64984
|
+
import { join as join23, resolve as resolve13, dirname as dirname6 } from "node:path";
|
|
64985
|
+
import { readdirSync as readdirSync10, readFileSync as readFileSync21, existsSync as existsSync27, writeFileSync as writeFileSync17, mkdirSync as mkdirSync19, rmSync as rmSync3, statSync as statSync5 } from "node:fs";
|
|
64742
64986
|
import { homedir as homedir14 } from "node:os";
|
|
64743
64987
|
import { execSync as execSync3 } from "node:child_process";
|
|
64744
64988
|
async function signToken(payload, secret) {
|
|
@@ -64828,7 +65072,7 @@ var init_api_server = __esm({
|
|
|
64828
65072
|
init_skill_service();
|
|
64829
65073
|
log57 = createLogger("api-server");
|
|
64830
65074
|
PBKDF2_ITERATIONS = 1e4;
|
|
64831
|
-
APIServer = class {
|
|
65075
|
+
APIServer = class _APIServer {
|
|
64832
65076
|
orgService;
|
|
64833
65077
|
taskService;
|
|
64834
65078
|
port;
|
|
@@ -64853,7 +65097,7 @@ var init_api_server = __esm({
|
|
|
64853
65097
|
builderService;
|
|
64854
65098
|
workflowEngine;
|
|
64855
65099
|
teamTemplateRegistry;
|
|
64856
|
-
|
|
65100
|
+
// Custom group chats are now persisted in SQLite via storage.groupChatRepo
|
|
64857
65101
|
constructor(orgService, taskService, port = 8056) {
|
|
64858
65102
|
this.orgService = orgService;
|
|
64859
65103
|
this.taskService = taskService;
|
|
@@ -64868,15 +65112,18 @@ var init_api_server = __esm({
|
|
|
64868
65112
|
am.setGroupChatHandlers({
|
|
64869
65113
|
sendGroupMessage: async (channelKey, message, senderId, senderName) => {
|
|
64870
65114
|
const cleanText = stripInternalBlocks(message);
|
|
65115
|
+
const orgId2 = "default";
|
|
65116
|
+
let persistedMsgId;
|
|
64871
65117
|
if (this.storage) {
|
|
64872
|
-
await this.storage.channelMessageRepo.append({
|
|
64873
|
-
orgId:
|
|
65118
|
+
const saved = await this.storage.channelMessageRepo.append({
|
|
65119
|
+
orgId: orgId2,
|
|
64874
65120
|
channel: channelKey,
|
|
64875
65121
|
senderId,
|
|
64876
65122
|
senderType: "agent",
|
|
64877
65123
|
senderName,
|
|
64878
65124
|
text: cleanText
|
|
64879
65125
|
});
|
|
65126
|
+
persistedMsgId = saved.id;
|
|
64880
65127
|
}
|
|
64881
65128
|
this.ws.broadcast({
|
|
64882
65129
|
type: "chat:message",
|
|
@@ -64889,41 +65136,81 @@ var init_api_server = __esm({
|
|
|
64889
65136
|
},
|
|
64890
65137
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
64891
65138
|
});
|
|
64892
|
-
|
|
64893
|
-
if (
|
|
64894
|
-
|
|
64895
|
-
|
|
64896
|
-
|
|
64897
|
-
|
|
64898
|
-
|
|
64899
|
-
|
|
64900
|
-
|
|
64901
|
-
|
|
64902
|
-
|
|
64903
|
-
|
|
64904
|
-
|
|
65139
|
+
let allAgentIds = [];
|
|
65140
|
+
if (channelKey.startsWith("group:custom:") && this.storage?.groupChatRepo) {
|
|
65141
|
+
allAgentIds = this.storage.groupChatRepo.getAgentMemberIds(channelKey);
|
|
65142
|
+
} else if (channelKey.startsWith("group:")) {
|
|
65143
|
+
const teamId = channelKey.replace(/^group:/, "");
|
|
65144
|
+
const team = this.orgService.getTeam(teamId);
|
|
65145
|
+
allAgentIds = team?.memberAgentIds ?? [];
|
|
65146
|
+
}
|
|
65147
|
+
const peerAgentIds = allAgentIds.filter((id) => id !== senderId);
|
|
65148
|
+
if (peerAgentIds.length > 0) {
|
|
65149
|
+
const agentManager = this.orgService.getAgentManager();
|
|
65150
|
+
const nameMap = this.buildAgentNameMap(allAgentIds, agentManager);
|
|
65151
|
+
const mentionedNames = this.parseAgentMentions(cleanText, [...nameMap.keys()]);
|
|
65152
|
+
const filteredMentions = mentionedNames.filter((n) => {
|
|
65153
|
+
const id = nameMap.get(n);
|
|
65154
|
+
return id && id !== senderId;
|
|
65155
|
+
});
|
|
65156
|
+
if (filteredMentions.length > 0) {
|
|
65157
|
+
let channelContext = [];
|
|
65158
|
+
if (this.storage) {
|
|
65159
|
+
try {
|
|
65160
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channelKey, 20);
|
|
65161
|
+
channelContext = (recent.messages ?? []).map((m) => ({
|
|
65162
|
+
role: m.senderType === "agent" ? "assistant" : "user",
|
|
65163
|
+
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
65164
|
+
}));
|
|
65165
|
+
} catch {
|
|
65166
|
+
}
|
|
65167
|
+
}
|
|
65168
|
+
const roundId = `round_${Date.now()}`;
|
|
65169
|
+
const respondedAgents = /* @__PURE__ */ new Set([senderId]);
|
|
65170
|
+
void this.triggerAgentToAgentChain(filteredMentions, nameMap, senderName, senderId, cleanText, persistedMsgId, channelKey, orgId2, agentManager, allAgentIds.length, { roundId, depth: 1, respondedAgents, allAgentIds });
|
|
65171
|
+
} else {
|
|
65172
|
+
for (const peerId of peerAgentIds) {
|
|
65173
|
+
try {
|
|
65174
|
+
agentManager.getAgent(peerId).enqueueToMailbox("a2a_message", {
|
|
65175
|
+
summary: `Group chat message from ${senderName}`,
|
|
65176
|
+
content: `[Group chat message from ${senderName}]:
|
|
65177
|
+
${cleanText}`,
|
|
65178
|
+
extra: { senderId, senderName, channelKey }
|
|
65179
|
+
}, {
|
|
65180
|
+
metadata: { senderId, senderName, senderRole: "agent" }
|
|
65181
|
+
});
|
|
65182
|
+
} catch {
|
|
65183
|
+
}
|
|
64905
65184
|
}
|
|
64906
65185
|
}
|
|
64907
65186
|
}
|
|
64908
65187
|
return "Message sent to group chat";
|
|
64909
65188
|
},
|
|
64910
65189
|
createGroupChat: async (name, creatorId, creatorName, memberIds) => {
|
|
64911
|
-
|
|
64912
|
-
|
|
64913
|
-
|
|
64914
|
-
|
|
64915
|
-
|
|
64916
|
-
|
|
64917
|
-
|
|
64918
|
-
|
|
64919
|
-
|
|
64920
|
-
|
|
64921
|
-
|
|
64922
|
-
|
|
64923
|
-
|
|
64924
|
-
|
|
64925
|
-
|
|
64926
|
-
|
|
65190
|
+
if (this.storage?.groupChatRepo) {
|
|
65191
|
+
const members = memberIds.map((id) => {
|
|
65192
|
+
try {
|
|
65193
|
+
const agentInfo = this.orgService.getAgentManager().getAgent(id);
|
|
65194
|
+
return { id, type: "agent", name: agentInfo?.config?.name ?? id };
|
|
65195
|
+
} catch {
|
|
65196
|
+
return { id, type: "agent", name: id };
|
|
65197
|
+
}
|
|
65198
|
+
});
|
|
65199
|
+
const gc = this.storage.groupChatRepo.create({
|
|
65200
|
+
orgId: "default",
|
|
65201
|
+
name,
|
|
65202
|
+
creatorId,
|
|
65203
|
+
creatorName,
|
|
65204
|
+
members
|
|
65205
|
+
});
|
|
65206
|
+
this.ws.broadcast({
|
|
65207
|
+
type: "chat:group_created",
|
|
65208
|
+
payload: { chatId: gc.channelKey, name, creatorId, creatorName },
|
|
65209
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
65210
|
+
});
|
|
65211
|
+
return { id: gc.channelKey, name };
|
|
65212
|
+
}
|
|
65213
|
+
return { id: `group:custom:${Date.now().toString(36)}`, name };
|
|
64927
65214
|
},
|
|
64928
65215
|
listGroupChats: async () => {
|
|
64929
65216
|
const teams = this.orgService.listTeamsWithMembers("default");
|
|
@@ -64933,13 +65220,27 @@ var init_api_server = __esm({
|
|
|
64933
65220
|
type: "team",
|
|
64934
65221
|
channelKey: `group:${t.id}`
|
|
64935
65222
|
}));
|
|
64936
|
-
const customChats = this.
|
|
64937
|
-
id: c.
|
|
65223
|
+
const customChats = this.storage?.groupChatRepo ? this.storage.groupChatRepo.list("default").map((c) => ({
|
|
65224
|
+
id: c.channelKey,
|
|
64938
65225
|
name: c.name,
|
|
64939
65226
|
type: "custom",
|
|
64940
|
-
channelKey: c.
|
|
64941
|
-
}));
|
|
65227
|
+
channelKey: c.channelKey
|
|
65228
|
+
})) : [];
|
|
64942
65229
|
return [...teamChats, ...customChats];
|
|
65230
|
+
},
|
|
65231
|
+
getChannelMessages: async (channelKey, limit, before2) => {
|
|
65232
|
+
if (!this.storage)
|
|
65233
|
+
return { messages: [], hasMore: false };
|
|
65234
|
+
const result = this.storage.channelMessageRepo.getMessages(channelKey, limit, before2);
|
|
65235
|
+
return {
|
|
65236
|
+
messages: result.messages.map((m) => ({
|
|
65237
|
+
senderName: m.senderName,
|
|
65238
|
+
senderType: m.senderType,
|
|
65239
|
+
text: stripInternalBlocks(m.text),
|
|
65240
|
+
createdAt: m.createdAt instanceof Date ? m.createdAt.toISOString() : String(m.createdAt)
|
|
65241
|
+
})),
|
|
65242
|
+
hasMore: result.hasMore
|
|
65243
|
+
};
|
|
64943
65244
|
}
|
|
64944
65245
|
});
|
|
64945
65246
|
}
|
|
@@ -65005,10 +65306,10 @@ var init_api_server = __esm({
|
|
|
65005
65306
|
for (const [fname, content] of Object.entries(data.files)) {
|
|
65006
65307
|
const filePath = join23(artDir, fname);
|
|
65007
65308
|
mkdirSync19(dirname6(filePath), { recursive: true });
|
|
65008
|
-
|
|
65309
|
+
writeFileSync17(filePath, content, "utf-8");
|
|
65009
65310
|
}
|
|
65010
65311
|
} else if (data.config) {
|
|
65011
|
-
|
|
65312
|
+
writeFileSync17(join23(artDir, manifestFilename(mode)), JSON.stringify(data.config, null, 2), "utf-8");
|
|
65012
65313
|
}
|
|
65013
65314
|
return self.builderService.installArtifact(mode, slug);
|
|
65014
65315
|
}
|
|
@@ -65239,48 +65540,167 @@ var init_api_server = __esm({
|
|
|
65239
65540
|
log57.warn("Failed to persist chat turn", { error: String(err) });
|
|
65240
65541
|
}
|
|
65241
65542
|
}
|
|
65543
|
+
// ── Agent-to-agent reply storm prevention ───────────────────────────────────
|
|
65544
|
+
static A2A_MAX_DEPTH = 3;
|
|
65545
|
+
static A2A_COOLDOWN_MS = 3e4;
|
|
65546
|
+
/** Per-channel cooldown tracker: channel → agentId → last reply timestamp */
|
|
65547
|
+
a2aCooldowns = /* @__PURE__ */ new Map();
|
|
65548
|
+
/** Extract @mentions from agent reply text. Returns agent names found.
|
|
65549
|
+
* Handles multi-word names (e.g. "Ryan 莱恩") by checking known names after each @ sign.
|
|
65550
|
+
* Also matches partial names: "@Sofia" matches "Sofia 索菲亚" if "Sofia" is a token in the name. */
|
|
65551
|
+
parseAgentMentions(text, knownAgentNames) {
|
|
65552
|
+
const mentioned = /* @__PURE__ */ new Set();
|
|
65553
|
+
const sorted = [...knownAgentNames].sort((a, b) => b.length - a.length);
|
|
65554
|
+
const tokenToName = /* @__PURE__ */ new Map();
|
|
65555
|
+
for (const name of sorted) {
|
|
65556
|
+
for (const token of name.split(/\s+/)) {
|
|
65557
|
+
if (token.length >= 2) {
|
|
65558
|
+
const key2 = token.toLowerCase();
|
|
65559
|
+
if (!tokenToName.has(key2))
|
|
65560
|
+
tokenToName.set(key2, name);
|
|
65561
|
+
}
|
|
65562
|
+
}
|
|
65563
|
+
}
|
|
65564
|
+
let idx = 0;
|
|
65565
|
+
while (idx < text.length) {
|
|
65566
|
+
const atPos = text.indexOf("@", idx);
|
|
65567
|
+
if (atPos < 0)
|
|
65568
|
+
break;
|
|
65569
|
+
if (text[atPos + 1] === "[") {
|
|
65570
|
+
const close = text.indexOf("]", atPos + 2);
|
|
65571
|
+
if (close > atPos + 2) {
|
|
65572
|
+
const bracketed = text.slice(atPos + 2, close);
|
|
65573
|
+
const match = sorted.find((n) => n.toLowerCase() === bracketed.toLowerCase());
|
|
65574
|
+
if (match)
|
|
65575
|
+
mentioned.add(match);
|
|
65576
|
+
idx = close + 1;
|
|
65577
|
+
continue;
|
|
65578
|
+
}
|
|
65579
|
+
}
|
|
65580
|
+
const after2 = text.slice(atPos + 1);
|
|
65581
|
+
const afterLower = after2.toLowerCase();
|
|
65582
|
+
const fullMatch = sorted.find((n) => afterLower.startsWith(n.toLowerCase()));
|
|
65583
|
+
if (fullMatch) {
|
|
65584
|
+
mentioned.add(fullMatch);
|
|
65585
|
+
idx = atPos + 1 + fullMatch.length;
|
|
65586
|
+
continue;
|
|
65587
|
+
}
|
|
65588
|
+
const tokenMatch = after2.match(/^(\S+)/);
|
|
65589
|
+
if (tokenMatch) {
|
|
65590
|
+
const token = tokenMatch[1].toLowerCase().replace(/[,,。!?!?;;::、()()[\]【】]+$/, "");
|
|
65591
|
+
const resolved = tokenToName.get(token);
|
|
65592
|
+
if (resolved) {
|
|
65593
|
+
mentioned.add(resolved);
|
|
65594
|
+
idx = atPos + 1 + tokenMatch[1].length;
|
|
65595
|
+
continue;
|
|
65596
|
+
}
|
|
65597
|
+
}
|
|
65598
|
+
idx = atPos + 1;
|
|
65599
|
+
}
|
|
65600
|
+
return [...mentioned];
|
|
65601
|
+
}
|
|
65602
|
+
/** Build name→id lookup for agents in a channel */
|
|
65603
|
+
buildAgentNameMap(agentIds, agentManager) {
|
|
65604
|
+
const map = /* @__PURE__ */ new Map();
|
|
65605
|
+
for (const id of agentIds) {
|
|
65606
|
+
try {
|
|
65607
|
+
map.set(agentManager.getAgent(id).config.name, id);
|
|
65608
|
+
} catch {
|
|
65609
|
+
}
|
|
65610
|
+
}
|
|
65611
|
+
return map;
|
|
65612
|
+
}
|
|
65242
65613
|
/**
|
|
65243
65614
|
* Process a single agent's reply in a group chat broadcast.
|
|
65244
65615
|
* Each agent decides independently whether to respond.
|
|
65245
65616
|
* Replies are persisted and broadcast via WebSocket.
|
|
65617
|
+
* If the agent @mentions other agents, a chain reply is triggered (with storm prevention).
|
|
65246
65618
|
*/
|
|
65247
|
-
async processGroupChatReply(agentId2, userMessage, senderId, senderInfo, channel, orgId2, channelContext, agentManager, teamSize) {
|
|
65619
|
+
async processGroupChatReply(agentId2, userMessage, senderId, senderInfo, channel, orgId2, channelContext, agentManager, teamSize, opts, chainCtx) {
|
|
65248
65620
|
try {
|
|
65249
65621
|
const agent = agentManager.getAgent(agentId2);
|
|
65250
65622
|
const agentName = agent.config.name;
|
|
65251
|
-
const
|
|
65252
|
-
|
|
65253
|
-
|
|
65254
|
-
|
|
65255
|
-
|
|
65256
|
-
|
|
65257
|
-
|
|
65258
|
-
|
|
65259
|
-
|
|
65260
|
-
|
|
65261
|
-
|
|
65262
|
-
|
|
65623
|
+
const isA2A = !!chainCtx && chainCtx.depth > 0;
|
|
65624
|
+
const hasReplyTarget = !!opts?.replyToAgentName;
|
|
65625
|
+
const hasMentions = !!opts?.mentionedNames?.length;
|
|
65626
|
+
const isTargeted = hasReplyTarget || hasMentions;
|
|
65627
|
+
const targetNames = /* @__PURE__ */ new Set();
|
|
65628
|
+
if (opts?.replyToAgentName)
|
|
65629
|
+
targetNames.add(opts.replyToAgentName);
|
|
65630
|
+
if (opts?.mentionedNames)
|
|
65631
|
+
opts.mentionedNames.forEach((n) => targetNames.add(n));
|
|
65632
|
+
const thisAgentIsTarget = targetNames.has(agentName);
|
|
65633
|
+
const prefixLines = [
|
|
65634
|
+
`[GROUP CHAT \u2014 ${teamSize} team members | You are: ${agentName}]`,
|
|
65263
65635
|
""
|
|
65264
|
-
]
|
|
65636
|
+
];
|
|
65637
|
+
if (isA2A) {
|
|
65638
|
+
prefixLines.push(`[AGENT COLLABORATION] This message is from a fellow agent (${opts?.replyToAgentName ?? "teammate"}), not from the user.`);
|
|
65639
|
+
prefixLines.push("You were @mentioned because your expertise is needed. Respond concisely to the specific request.");
|
|
65640
|
+
prefixLines.push("You may @mention another agent if (and ONLY if) you genuinely need their specific expertise to answer.");
|
|
65641
|
+
prefixLines.push("Do NOT @mention agents just to be polite or to pass the conversation along.");
|
|
65642
|
+
prefixLines.push("");
|
|
65643
|
+
}
|
|
65644
|
+
if (isTargeted && !isA2A) {
|
|
65645
|
+
if (hasReplyTarget) {
|
|
65646
|
+
prefixLines.push(`[REPLY] The user is replying to ${opts.replyToAgentName}'s message: "${(opts.replyToText ?? "").slice(0, 200)}"`);
|
|
65647
|
+
}
|
|
65648
|
+
if (hasMentions) {
|
|
65649
|
+
prefixLines.push(`[MENTIONED] The user @mentioned: ${opts.mentionedNames.join(", ")}`);
|
|
65650
|
+
}
|
|
65651
|
+
prefixLines.push("");
|
|
65652
|
+
if (thisAgentIsTarget) {
|
|
65653
|
+
prefixLines.push(">>> You are the target of this message. You SHOULD respond. <<<");
|
|
65654
|
+
} else {
|
|
65655
|
+
prefixLines.push(">>> STOP. This message is NOT for you. The user is talking to " + [...targetNames].join(", ") + ", not you.");
|
|
65656
|
+
prefixLines.push("You MUST respond with exactly: [NO_RESPONSE]");
|
|
65657
|
+
prefixLines.push('The ONLY exception: you are directly contradicted by a factual error. Offering opinions, agreement, "me too", or generic help does NOT count. <<<');
|
|
65658
|
+
}
|
|
65659
|
+
} else if (!isA2A) {
|
|
65660
|
+
prefixLines.push("This is an open group message (no specific @mention or reply target).");
|
|
65661
|
+
}
|
|
65662
|
+
prefixLines.push("");
|
|
65663
|
+
prefixLines.push("Rules for ALL group chat messages:");
|
|
65664
|
+
prefixLines.push("1. Check channel history \u2014 if another agent already answered, do NOT repeat.");
|
|
65665
|
+
prefixLines.push("2. Only respond if your specific role/expertise is directly relevant.");
|
|
65666
|
+
prefixLines.push("3. Be concise \u2014 short, actionable responses only.");
|
|
65667
|
+
if (agent.config.agentRole === "manager") {
|
|
65668
|
+
prefixLines.push("4. When assigning work to agents, you MUST use `task_create` to formalize each assignment as a tracked task. Verbal delegation without a task is NOT allowed \u2014 oral promises are meaningless without task tracking. Every commitment must have a corresponding task.");
|
|
65669
|
+
} else {
|
|
65670
|
+
prefixLines.push("4. When you accept a work assignment, verify a task has been created for it (`task_list`). If the coordinator did not create one, remind them or create it yourself with the correct `assigned_agent_id`. Do NOT make promises without task tracking.");
|
|
65671
|
+
}
|
|
65672
|
+
prefixLines.push("5. DEFAULT IS SILENCE. When in doubt, respond with exactly: [NO_RESPONSE]");
|
|
65673
|
+
prefixLines.push('6. If the provided context is insufficient, use `recall_context` (scope="channel") to fetch earlier messages before responding. For task/requirement details use `task_get`/`requirement_get`. Do NOT guess about prior discussion.');
|
|
65674
|
+
if (isTargeted && !thisAgentIsTarget && !isA2A) {
|
|
65675
|
+
prefixLines.push("7. REMINDER: This message is directed at " + [...targetNames].join(", ") + ". You are " + agentName + ". Respond ONLY with [NO_RESPONSE].");
|
|
65676
|
+
}
|
|
65677
|
+
prefixLines.push("---", "");
|
|
65678
|
+
const groupChatPrefix = prefixLines.join("\n");
|
|
65265
65679
|
const toolEvents = [];
|
|
65266
65680
|
const reply = await agent.sendMessage(groupChatPrefix + userMessage, senderId, senderInfo, {
|
|
65267
|
-
sourceType: "human_chat",
|
|
65681
|
+
sourceType: isA2A ? "a2a_message" : "human_chat",
|
|
65682
|
+
scenario: isA2A ? "a2a" : void 0,
|
|
65268
65683
|
channelContext,
|
|
65269
65684
|
toolEventCollector: toolEvents
|
|
65270
65685
|
});
|
|
65271
|
-
if (!reply || reply.trim()
|
|
65686
|
+
if (!reply || !reply.trim() || reply.includes("[NO_RESPONSE]")) {
|
|
65272
65687
|
return;
|
|
65273
65688
|
}
|
|
65274
|
-
const { thinking, clean:
|
|
65275
|
-
|
|
65689
|
+
const { thinking, clean: rawClean } = extractThinkBlocks(reply);
|
|
65690
|
+
const cleanReply = rawClean.replace(/\[NO_RESPONSE\]/gi, "").trim();
|
|
65691
|
+
if (!cleanReply)
|
|
65276
65692
|
return;
|
|
65277
65693
|
const metadata = {};
|
|
65278
65694
|
if (thinking.length > 0)
|
|
65279
65695
|
metadata["thinking"] = thinking;
|
|
65280
65696
|
if (toolEvents.length > 0)
|
|
65281
65697
|
metadata["toolCalls"] = toolEvents;
|
|
65698
|
+
if (isA2A && opts?.replyToAgentName) {
|
|
65699
|
+
metadata["replyToAgent"] = opts.replyToAgentName;
|
|
65700
|
+
}
|
|
65701
|
+
let persistedMsgId;
|
|
65282
65702
|
if (this.storage) {
|
|
65283
|
-
await this.storage.channelMessageRepo.append({
|
|
65703
|
+
const saved = await this.storage.channelMessageRepo.append({
|
|
65284
65704
|
orgId: orgId2,
|
|
65285
65705
|
channel,
|
|
65286
65706
|
senderId: agentId2,
|
|
@@ -65288,8 +65708,10 @@ var init_api_server = __esm({
|
|
|
65288
65708
|
senderName: agentName,
|
|
65289
65709
|
text: cleanReply,
|
|
65290
65710
|
mentions: [],
|
|
65291
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
65711
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
65712
|
+
replyToId: isA2A ? opts?.replyToMsgId : void 0
|
|
65292
65713
|
});
|
|
65714
|
+
persistedMsgId = saved.id;
|
|
65293
65715
|
}
|
|
65294
65716
|
this.ws.broadcast({
|
|
65295
65717
|
type: "chat:message",
|
|
@@ -65299,10 +65721,29 @@ var init_api_server = __esm({
|
|
|
65299
65721
|
senderType: "agent",
|
|
65300
65722
|
senderName: agentName,
|
|
65301
65723
|
text: cleanReply,
|
|
65302
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
65724
|
+
metadata: Object.keys(metadata).length > 0 ? metadata : void 0,
|
|
65725
|
+
...isA2A ? {
|
|
65726
|
+
replyToId: opts?.replyToMsgId,
|
|
65727
|
+
replyToSender: opts?.replyToAgentName,
|
|
65728
|
+
replyToText: (opts?.replyToText ?? "").slice(0, 120)
|
|
65729
|
+
} : {}
|
|
65303
65730
|
},
|
|
65304
65731
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
65305
65732
|
});
|
|
65733
|
+
const allAgentIds = chainCtx?.allAgentIds ?? [];
|
|
65734
|
+
if (allAgentIds.length > 0) {
|
|
65735
|
+
const nameMap = this.buildAgentNameMap(allAgentIds, agentManager);
|
|
65736
|
+
const mentionedNames = this.parseAgentMentions(cleanReply, [...nameMap.keys()]);
|
|
65737
|
+
const filteredMentions = mentionedNames.filter((n) => n !== agentName);
|
|
65738
|
+
log57.info("A2A mention scan", { agentName, mentionedNames, filteredMentions, depth: chainCtx?.depth ?? 0 });
|
|
65739
|
+
if (filteredMentions.length > 0) {
|
|
65740
|
+
const depth = (chainCtx?.depth ?? 0) + 1;
|
|
65741
|
+
const roundId = chainCtx?.roundId ?? `round_${Date.now()}`;
|
|
65742
|
+
const responded = chainCtx?.respondedAgents ?? /* @__PURE__ */ new Set();
|
|
65743
|
+
responded.add(agentId2);
|
|
65744
|
+
void this.triggerAgentToAgentChain(filteredMentions, nameMap, agentName, agentId2, cleanReply, persistedMsgId, channel, orgId2, agentManager, teamSize, { roundId, depth, respondedAgents: responded, allAgentIds });
|
|
65745
|
+
}
|
|
65746
|
+
}
|
|
65306
65747
|
} catch (err) {
|
|
65307
65748
|
log57.warn("Group chat agent reply failed", { agentId: agentId2, error: String(err) });
|
|
65308
65749
|
if (this.storage) {
|
|
@@ -65322,6 +65763,56 @@ var init_api_server = __esm({
|
|
|
65322
65763
|
}
|
|
65323
65764
|
}
|
|
65324
65765
|
}
|
|
65766
|
+
/**
|
|
65767
|
+
* Trigger agent-to-agent chain replies with 3-layer storm prevention:
|
|
65768
|
+
* 1. Depth limit (max 3 hops)
|
|
65769
|
+
* 2. Per-round dedup (each agent responds at most once per conversation round)
|
|
65770
|
+
* 3. Cooldown window (same agent won't be triggered twice within 30s on same channel)
|
|
65771
|
+
*/
|
|
65772
|
+
async triggerAgentToAgentChain(mentionedNames, nameMap, fromAgentName, fromAgentId, fromText, fromMsgId, channel, orgId2, agentManager, teamSize, chainCtx) {
|
|
65773
|
+
if (chainCtx.depth > _APIServer.A2A_MAX_DEPTH) {
|
|
65774
|
+
log57.info("A2A chain depth limit reached", { channel, depth: chainCtx.depth, roundId: chainCtx.roundId });
|
|
65775
|
+
return;
|
|
65776
|
+
}
|
|
65777
|
+
const now2 = Date.now();
|
|
65778
|
+
if (!this.a2aCooldowns.has(channel)) {
|
|
65779
|
+
this.a2aCooldowns.set(channel, /* @__PURE__ */ new Map());
|
|
65780
|
+
}
|
|
65781
|
+
const channelCooldowns = this.a2aCooldowns.get(channel);
|
|
65782
|
+
let channelContext = [];
|
|
65783
|
+
if (this.storage) {
|
|
65784
|
+
try {
|
|
65785
|
+
const recent = await this.storage.channelMessageRepo.getMessages(channel, 20);
|
|
65786
|
+
channelContext = (recent.messages ?? []).map((m) => ({
|
|
65787
|
+
role: m.senderType === "agent" ? "assistant" : "user",
|
|
65788
|
+
content: m.senderType === "agent" ? stripInternalBlocks(m.text) : `[${m.senderName}]: ${m.text}`
|
|
65789
|
+
}));
|
|
65790
|
+
} catch {
|
|
65791
|
+
}
|
|
65792
|
+
}
|
|
65793
|
+
for (const targetName of mentionedNames) {
|
|
65794
|
+
const targetId = nameMap.get(targetName);
|
|
65795
|
+
if (!targetId)
|
|
65796
|
+
continue;
|
|
65797
|
+
if (chainCtx.respondedAgents.has(targetId)) {
|
|
65798
|
+
log57.info("A2A skipping (already responded this round)", { targetName, roundId: chainCtx.roundId });
|
|
65799
|
+
continue;
|
|
65800
|
+
}
|
|
65801
|
+
const lastReply = channelCooldowns.get(targetId) ?? 0;
|
|
65802
|
+
if (now2 - lastReply < _APIServer.A2A_COOLDOWN_MS) {
|
|
65803
|
+
log57.info("A2A skipping (cooldown)", { targetName, channel, cooldownRemaining: _APIServer.A2A_COOLDOWN_MS - (now2 - lastReply) });
|
|
65804
|
+
continue;
|
|
65805
|
+
}
|
|
65806
|
+
channelCooldowns.set(targetId, now2);
|
|
65807
|
+
const a2aMessage = `[From @${fromAgentName}]: ${fromText}`;
|
|
65808
|
+
void this.processGroupChatReply(targetId, a2aMessage, fromAgentId, { name: fromAgentName, role: "agent" }, channel, orgId2, channelContext, agentManager, teamSize, {
|
|
65809
|
+
mentionedNames: [targetName],
|
|
65810
|
+
replyToAgentName: fromAgentName,
|
|
65811
|
+
replyToText: fromText.slice(0, 200),
|
|
65812
|
+
replyToMsgId: fromMsgId
|
|
65813
|
+
}, chainCtx);
|
|
65814
|
+
}
|
|
65815
|
+
}
|
|
65325
65816
|
/** Persist the user message first (before LLM), returns session id for subsequent assistant persistence.
|
|
65326
65817
|
* When sessionId is provided, appends to that session; when null/undefined, creates a new session. */
|
|
65327
65818
|
async persistUserMessage(agentId2, userMessage, senderId, images, sessionId) {
|
|
@@ -65577,7 +66068,7 @@ var init_api_server = __esm({
|
|
|
65577
66068
|
const avatarDir = join23(homedir14(), ".markus", "avatars");
|
|
65578
66069
|
mkdirSync19(avatarDir, { recursive: true });
|
|
65579
66070
|
const filename = `${targetType}_${targetId}.${ext}`;
|
|
65580
|
-
|
|
66071
|
+
writeFileSync17(join23(avatarDir, filename), buf);
|
|
65581
66072
|
const avatarUrl = `/api/avatars/${filename}`;
|
|
65582
66073
|
if (targetType === "user" && this.storage) {
|
|
65583
66074
|
this.storage.userRepo.updateAvatarUrl(targetId, avatarUrl);
|
|
@@ -65654,6 +66145,7 @@ var init_api_server = __esm({
|
|
|
65654
66145
|
const senderName = body["senderName"] ?? "You";
|
|
65655
66146
|
const mentions = body["mentions"] ?? [];
|
|
65656
66147
|
const targetAgentId = body["targetAgentId"];
|
|
66148
|
+
const replyToId = body["replyToId"];
|
|
65657
66149
|
const orgId2 = body["orgId"] ?? "default";
|
|
65658
66150
|
let userMsg;
|
|
65659
66151
|
if (this.storage) {
|
|
@@ -65664,7 +66156,8 @@ var init_api_server = __esm({
|
|
|
65664
66156
|
senderType: "human",
|
|
65665
66157
|
senderName,
|
|
65666
66158
|
text,
|
|
65667
|
-
mentions
|
|
66159
|
+
mentions,
|
|
66160
|
+
replyToId
|
|
65668
66161
|
});
|
|
65669
66162
|
}
|
|
65670
66163
|
const humanOnly = body["humanOnly"] === true;
|
|
@@ -65682,21 +66175,50 @@ var init_api_server = __esm({
|
|
|
65682
66175
|
return [];
|
|
65683
66176
|
}
|
|
65684
66177
|
};
|
|
65685
|
-
|
|
65686
|
-
|
|
65687
|
-
|
|
65688
|
-
|
|
66178
|
+
let replyToAgentName;
|
|
66179
|
+
let replyToText;
|
|
66180
|
+
if (replyToId && this.storage) {
|
|
66181
|
+
try {
|
|
66182
|
+
const original = this.storage.channelMessageRepo.getMessageById(replyToId);
|
|
66183
|
+
if (original) {
|
|
66184
|
+
replyToAgentName = original.senderName;
|
|
66185
|
+
replyToText = original.text.slice(0, 200);
|
|
66186
|
+
}
|
|
66187
|
+
} catch {
|
|
66188
|
+
}
|
|
66189
|
+
}
|
|
66190
|
+
const enrichedUserMsg = userMsg ? {
|
|
66191
|
+
...userMsg,
|
|
66192
|
+
...replyToAgentName ? { replyToSender: replyToAgentName, replyToText } : {}
|
|
66193
|
+
} : null;
|
|
66194
|
+
if (!isHumanChannel && channel.startsWith("group:")) {
|
|
66195
|
+
let allAgentIds;
|
|
66196
|
+
if (channel.startsWith("group:custom:")) {
|
|
66197
|
+
allAgentIds = this.storage?.groupChatRepo?.getAgentMemberIds(channel) ?? [];
|
|
66198
|
+
} else {
|
|
66199
|
+
const teamId = channel.replace(/^group:/, "");
|
|
66200
|
+
const team = this.orgService.getTeam(teamId);
|
|
66201
|
+
allAgentIds = team?.memberAgentIds ?? [];
|
|
66202
|
+
}
|
|
65689
66203
|
if (allAgentIds.length === 0) {
|
|
65690
|
-
this.json(res, 200, { userMessage:
|
|
66204
|
+
this.json(res, 200, { userMessage: enrichedUserMsg, agentMessage: null });
|
|
65691
66205
|
return;
|
|
65692
66206
|
}
|
|
65693
66207
|
const channelContext2 = await buildChannelContext();
|
|
65694
66208
|
const senderInfo2 = this.orgService.resolveHumanIdentity(senderId);
|
|
65695
66209
|
const agentManager = this.orgService.getAgentManager();
|
|
66210
|
+
const broadcastOpts = {
|
|
66211
|
+
mentionedNames: mentions.length > 0 ? mentions : void 0,
|
|
66212
|
+
replyToAgentName,
|
|
66213
|
+
replyToText
|
|
66214
|
+
};
|
|
66215
|
+
const roundId = `round_${Date.now()}`;
|
|
66216
|
+
const respondedAgents = /* @__PURE__ */ new Set();
|
|
66217
|
+
const chainCtx = { roundId, depth: 0, respondedAgents, allAgentIds };
|
|
65696
66218
|
for (const agentId2 of allAgentIds) {
|
|
65697
|
-
void this.processGroupChatReply(agentId2, text, senderId, senderInfo2, channel, orgId2, channelContext2, agentManager, allAgentIds.length);
|
|
66219
|
+
void this.processGroupChatReply(agentId2, text, senderId, senderInfo2, channel, orgId2, channelContext2, agentManager, allAgentIds.length, broadcastOpts, chainCtx);
|
|
65698
66220
|
}
|
|
65699
|
-
this.json(res, 200, { userMessage:
|
|
66221
|
+
this.json(res, 200, { userMessage: enrichedUserMsg, agentMessage: null });
|
|
65700
66222
|
return;
|
|
65701
66223
|
}
|
|
65702
66224
|
let routedAgentId = null;
|
|
@@ -65710,7 +66232,7 @@ var init_api_server = __esm({
|
|
|
65710
66232
|
}
|
|
65711
66233
|
}
|
|
65712
66234
|
if (!routedAgentId) {
|
|
65713
|
-
this.json(res, 200, { userMessage:
|
|
66235
|
+
this.json(res, 200, { userMessage: enrichedUserMsg, agentMessage: null });
|
|
65714
66236
|
return;
|
|
65715
66237
|
}
|
|
65716
66238
|
const agent = this.orgService.getAgentManager().getAgent(routedAgentId);
|
|
@@ -65753,7 +66275,7 @@ var init_api_server = __esm({
|
|
|
65753
66275
|
}
|
|
65754
66276
|
const statusCode = raw.includes("402") ? 402 : raw.includes("401") ? 401 : raw.includes("429") ? 429 : 502;
|
|
65755
66277
|
this.json(res, statusCode, {
|
|
65756
|
-
userMessage:
|
|
66278
|
+
userMessage: enrichedUserMsg,
|
|
65757
66279
|
agentMessage: errorMsg ?? null,
|
|
65758
66280
|
error: detail2
|
|
65759
66281
|
});
|
|
@@ -65780,7 +66302,7 @@ var init_api_server = __esm({
|
|
|
65780
66302
|
void this.persistChatTurn(routedAgentId, text, reply, senderId);
|
|
65781
66303
|
}
|
|
65782
66304
|
this.json(res, 200, {
|
|
65783
|
-
userMessage:
|
|
66305
|
+
userMessage: enrichedUserMsg,
|
|
65784
66306
|
agentMessage: agentMsg ?? {
|
|
65785
66307
|
id: `tmp_${Date.now()}`,
|
|
65786
66308
|
channel,
|
|
@@ -65980,7 +66502,7 @@ var init_api_server = __esm({
|
|
|
65980
66502
|
if (path === "/api/group-chats" && req.method === "GET") {
|
|
65981
66503
|
const orgId2 = url.searchParams.get("orgId") ?? "default";
|
|
65982
66504
|
const teams = this.orgService.listTeamsWithMembers(orgId2);
|
|
65983
|
-
const
|
|
66505
|
+
const teamChats = teams.map((t) => ({
|
|
65984
66506
|
id: `group:${t.id}`,
|
|
65985
66507
|
name: t.name,
|
|
65986
66508
|
type: "team",
|
|
@@ -65988,21 +66510,16 @@ var init_api_server = __esm({
|
|
|
65988
66510
|
memberCount: t.members.length,
|
|
65989
66511
|
channelKey: `group:${t.id}`
|
|
65990
66512
|
}));
|
|
65991
|
-
const customChats = this.
|
|
65992
|
-
|
|
65993
|
-
|
|
65994
|
-
|
|
65995
|
-
|
|
65996
|
-
|
|
65997
|
-
|
|
65998
|
-
|
|
65999
|
-
|
|
66000
|
-
|
|
66001
|
-
memberCount: c.memberIds?.length ?? 0,
|
|
66002
|
-
channelKey: c.id
|
|
66003
|
-
}))
|
|
66004
|
-
]
|
|
66005
|
-
});
|
|
66513
|
+
const customChats = this.storage?.groupChatRepo ? this.storage.groupChatRepo.list(orgId2).map((c) => ({
|
|
66514
|
+
id: c.id,
|
|
66515
|
+
name: c.name,
|
|
66516
|
+
type: "custom",
|
|
66517
|
+
creatorId: c.creatorId,
|
|
66518
|
+
creatorName: c.creatorName,
|
|
66519
|
+
memberCount: c.memberCount,
|
|
66520
|
+
channelKey: c.channelKey
|
|
66521
|
+
})) : [];
|
|
66522
|
+
this.json(res, 200, { chats: [...teamChats, ...customChats] });
|
|
66006
66523
|
return;
|
|
66007
66524
|
}
|
|
66008
66525
|
if (path === "/api/group-chats" && req.method === "POST") {
|
|
@@ -66012,31 +66529,129 @@ var init_api_server = __esm({
|
|
|
66012
66529
|
const creatorId = body["creatorId"];
|
|
66013
66530
|
const creatorName = body["creatorName"];
|
|
66014
66531
|
const memberIds = body["memberIds"];
|
|
66532
|
+
const memberTypes = body["memberTypes"];
|
|
66533
|
+
const memberNames = body["memberNames"];
|
|
66015
66534
|
if (!name) {
|
|
66016
66535
|
this.json(res, 400, { error: "name is required" });
|
|
66017
66536
|
return;
|
|
66018
66537
|
}
|
|
66019
|
-
|
|
66020
|
-
|
|
66021
|
-
|
|
66022
|
-
|
|
66023
|
-
|
|
66024
|
-
|
|
66025
|
-
|
|
66026
|
-
|
|
66027
|
-
|
|
66028
|
-
|
|
66029
|
-
|
|
66538
|
+
if (!this.storage?.groupChatRepo) {
|
|
66539
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66540
|
+
return;
|
|
66541
|
+
}
|
|
66542
|
+
const members = (memberIds ?? []).map((id) => {
|
|
66543
|
+
const mType = memberTypes?.[id] ?? "agent";
|
|
66544
|
+
let mName = memberNames?.[id] ?? id;
|
|
66545
|
+
if (mType === "agent") {
|
|
66546
|
+
try {
|
|
66547
|
+
mName = this.orgService.getAgentManager().getAgent(id)?.config?.name ?? mName;
|
|
66548
|
+
} catch {
|
|
66549
|
+
}
|
|
66550
|
+
}
|
|
66551
|
+
return { id, type: mType, name: mName };
|
|
66552
|
+
});
|
|
66553
|
+
const gc = this.storage.groupChatRepo.create({ orgId: orgId2, name, creatorId, creatorName, members });
|
|
66030
66554
|
this.ws?.broadcast({
|
|
66031
66555
|
type: "chat:group_created",
|
|
66032
|
-
payload: { chatId, name, creatorId, creatorName },
|
|
66556
|
+
payload: { chatId: gc.channelKey, name, creatorId, creatorName },
|
|
66033
66557
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
66034
66558
|
});
|
|
66035
66559
|
this.json(res, 201, {
|
|
66036
|
-
chat: {
|
|
66560
|
+
chat: {
|
|
66561
|
+
id: gc.id,
|
|
66562
|
+
name: gc.name,
|
|
66563
|
+
type: "custom",
|
|
66564
|
+
creatorId: gc.creatorId,
|
|
66565
|
+
creatorName: gc.creatorName,
|
|
66566
|
+
channelKey: gc.channelKey,
|
|
66567
|
+
memberCount: gc.members.length,
|
|
66568
|
+
members: gc.members.map((m) => ({ id: m.memberId, name: m.memberName, type: m.memberType }))
|
|
66569
|
+
}
|
|
66037
66570
|
});
|
|
66038
66571
|
return;
|
|
66039
66572
|
}
|
|
66573
|
+
if (path.match(/^\/api\/group-chats\/[^/]+$/) && req.method === "GET") {
|
|
66574
|
+
const gcId = path.split("/").pop();
|
|
66575
|
+
if (!this.storage?.groupChatRepo) {
|
|
66576
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66577
|
+
return;
|
|
66578
|
+
}
|
|
66579
|
+
const gc = this.storage.groupChatRepo.getById(gcId);
|
|
66580
|
+
if (!gc) {
|
|
66581
|
+
this.json(res, 404, { error: "Group chat not found" });
|
|
66582
|
+
return;
|
|
66583
|
+
}
|
|
66584
|
+
this.json(res, 200, {
|
|
66585
|
+
chat: {
|
|
66586
|
+
id: gc.id,
|
|
66587
|
+
name: gc.name,
|
|
66588
|
+
type: "custom",
|
|
66589
|
+
channelKey: gc.channelKey,
|
|
66590
|
+
creatorId: gc.creatorId,
|
|
66591
|
+
creatorName: gc.creatorName,
|
|
66592
|
+
members: gc.members.map((m) => ({ id: m.memberId, name: m.memberName, type: m.memberType }))
|
|
66593
|
+
}
|
|
66594
|
+
});
|
|
66595
|
+
return;
|
|
66596
|
+
}
|
|
66597
|
+
if (path.match(/^\/api\/group-chats\/[^/]+$/) && req.method === "PATCH") {
|
|
66598
|
+
const gcId = path.split("/").pop();
|
|
66599
|
+
if (!this.storage?.groupChatRepo) {
|
|
66600
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66601
|
+
return;
|
|
66602
|
+
}
|
|
66603
|
+
const body = await this.readBody(req);
|
|
66604
|
+
const newName = body["name"];
|
|
66605
|
+
if (newName)
|
|
66606
|
+
this.storage.groupChatRepo.updateName(gcId, newName);
|
|
66607
|
+
this.json(res, 200, { ok: true });
|
|
66608
|
+
return;
|
|
66609
|
+
}
|
|
66610
|
+
if (path.match(/^\/api\/group-chats\/[^/]+$/) && req.method === "DELETE") {
|
|
66611
|
+
const gcId = path.split("/").pop();
|
|
66612
|
+
if (!this.storage?.groupChatRepo) {
|
|
66613
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66614
|
+
return;
|
|
66615
|
+
}
|
|
66616
|
+
this.storage.groupChatRepo.delete(gcId);
|
|
66617
|
+
this.ws?.broadcast({ type: "chat:group_deleted", payload: { chatId: gcId }, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
66618
|
+
this.json(res, 200, { ok: true });
|
|
66619
|
+
return;
|
|
66620
|
+
}
|
|
66621
|
+
if (path.match(/^\/api\/group-chats\/[^/]+\/members$/) && req.method === "POST") {
|
|
66622
|
+
const gcId = path.split("/")[3];
|
|
66623
|
+
if (!this.storage?.groupChatRepo) {
|
|
66624
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66625
|
+
return;
|
|
66626
|
+
}
|
|
66627
|
+
const body = await this.readBody(req);
|
|
66628
|
+
const memberId = body["memberId"];
|
|
66629
|
+
const memberType = body["memberType"] ?? "agent";
|
|
66630
|
+
let memberName = body["memberName"] ?? memberId;
|
|
66631
|
+
if (memberType === "agent") {
|
|
66632
|
+
try {
|
|
66633
|
+
memberName = this.orgService.getAgentManager().getAgent(memberId)?.config?.name ?? memberName;
|
|
66634
|
+
} catch {
|
|
66635
|
+
}
|
|
66636
|
+
}
|
|
66637
|
+
this.storage.groupChatRepo.addMember(gcId, memberId, memberType, memberName);
|
|
66638
|
+
this.ws?.broadcast({ type: "chat:group_updated", payload: { chatId: gcId }, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
66639
|
+
this.json(res, 200, { ok: true });
|
|
66640
|
+
return;
|
|
66641
|
+
}
|
|
66642
|
+
if (path.match(/^\/api\/group-chats\/[^/]+\/members\/[^/]+$/) && req.method === "DELETE") {
|
|
66643
|
+
const parts = path.split("/");
|
|
66644
|
+
const gcId = parts[3];
|
|
66645
|
+
const memberId = parts[5];
|
|
66646
|
+
if (!this.storage?.groupChatRepo) {
|
|
66647
|
+
this.json(res, 500, { error: "Storage not initialized" });
|
|
66648
|
+
return;
|
|
66649
|
+
}
|
|
66650
|
+
this.storage.groupChatRepo.removeMember(gcId, memberId);
|
|
66651
|
+
this.ws?.broadcast({ type: "chat:group_updated", payload: { chatId: gcId }, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
66652
|
+
this.json(res, 200, { ok: true });
|
|
66653
|
+
return;
|
|
66654
|
+
}
|
|
66040
66655
|
if (path === "/api/teams" && req.method === "GET") {
|
|
66041
66656
|
const orgId2 = url.searchParams.get("orgId") ?? "default";
|
|
66042
66657
|
const teams = this.orgService.listTeamsWithMembers(orgId2);
|
|
@@ -66271,7 +66886,7 @@ var init_api_server = __esm({
|
|
|
66271
66886
|
const content = body["content"];
|
|
66272
66887
|
const dir = this.orgService.getTeamDataDir(teamId);
|
|
66273
66888
|
mkdirSync19(dir, { recursive: true });
|
|
66274
|
-
|
|
66889
|
+
writeFileSync17(join23(dir, filename), content ?? "", "utf-8");
|
|
66275
66890
|
this.json(res, 200, { ok: true });
|
|
66276
66891
|
return;
|
|
66277
66892
|
}
|
|
@@ -67116,7 +67731,7 @@ var init_api_server = __esm({
|
|
|
67116
67731
|
}
|
|
67117
67732
|
const body = await this.readBody(req);
|
|
67118
67733
|
const content = body["content"] ?? "";
|
|
67119
|
-
|
|
67734
|
+
writeFileSync17(join23(roleDir, filename), content, "utf-8");
|
|
67120
67735
|
this.json(res, 200, { ok: true });
|
|
67121
67736
|
} catch {
|
|
67122
67737
|
this.json(res, 404, { error: `Agent not found: ${agentId2}` });
|
|
@@ -68155,7 +68770,7 @@ EXPLANATION_END`;
|
|
|
68155
68770
|
return;
|
|
68156
68771
|
}
|
|
68157
68772
|
if (path === "/api/skills/builtin" && req.method === "GET") {
|
|
68158
|
-
const builtinDir =
|
|
68773
|
+
const builtinDir = resolve13(process.cwd(), "templates", "skills");
|
|
68159
68774
|
const found = discoverSkillsInDir(builtinDir);
|
|
68160
68775
|
const installedSkills = new Map((this.skillRegistry?.list() ?? []).map((s) => [s.name, s]));
|
|
68161
68776
|
const skills = found.map(({ manifest, path: p }) => {
|
|
@@ -68455,7 +69070,7 @@ EXPLANATION_END`;
|
|
|
68455
69070
|
const mfName = manifestFilename(pkgType);
|
|
68456
69071
|
const artDir = join23(homedir14(), ".markus", "builder-artifacts", typeDir, manifest.name);
|
|
68457
69072
|
mkdirSync19(artDir, { recursive: true });
|
|
68458
|
-
|
|
69073
|
+
writeFileSync17(join23(artDir, mfName), JSON.stringify(manifest, null, 2), "utf-8");
|
|
68459
69074
|
const artFiles = artifact.files;
|
|
68460
69075
|
if (artFiles) {
|
|
68461
69076
|
for (const [fn, c] of Object.entries(artFiles)) {
|
|
@@ -68463,18 +69078,18 @@ EXPLANATION_END`;
|
|
|
68463
69078
|
continue;
|
|
68464
69079
|
const filePath = join23(artDir, fn);
|
|
68465
69080
|
mkdirSync19(dirname6(filePath), { recursive: true });
|
|
68466
|
-
|
|
69081
|
+
writeFileSync17(filePath, c, "utf-8");
|
|
68467
69082
|
}
|
|
68468
69083
|
}
|
|
68469
69084
|
if (mode === "team") {
|
|
68470
69085
|
const fileSet = new Set(artFiles ? Object.keys(artFiles) : []);
|
|
68471
69086
|
const announcement = artifact.announcement;
|
|
68472
69087
|
if (announcement && !fileSet.has("ANNOUNCEMENT.md")) {
|
|
68473
|
-
|
|
69088
|
+
writeFileSync17(join23(artDir, "ANNOUNCEMENT.md"), announcement, "utf-8");
|
|
68474
69089
|
}
|
|
68475
69090
|
const norms = artifact.norms;
|
|
68476
69091
|
if (norms && !fileSet.has("NORMS.md")) {
|
|
68477
|
-
|
|
69092
|
+
writeFileSync17(join23(artDir, "NORMS.md"), norms, "utf-8");
|
|
68478
69093
|
}
|
|
68479
69094
|
const rawMembers = Array.isArray(artifact.team?.members) ? artifact.team.members : Array.isArray(artifact.members) ? artifact.members : [];
|
|
68480
69095
|
for (const m of rawMembers) {
|
|
@@ -68486,15 +69101,15 @@ EXPLANATION_END`;
|
|
|
68486
69101
|
const contextContent = m.contextContent || m.context_md;
|
|
68487
69102
|
if (roleContent && !fileSet.has(`members/${slug}/ROLE.md`)) {
|
|
68488
69103
|
mkdirSync19(memberDir, { recursive: true });
|
|
68489
|
-
|
|
69104
|
+
writeFileSync17(join23(memberDir, "ROLE.md"), roleContent, "utf-8");
|
|
68490
69105
|
}
|
|
68491
69106
|
if (policiesContent && !fileSet.has(`members/${slug}/POLICIES.md`)) {
|
|
68492
69107
|
mkdirSync19(memberDir, { recursive: true });
|
|
68493
|
-
|
|
69108
|
+
writeFileSync17(join23(memberDir, "POLICIES.md"), policiesContent, "utf-8");
|
|
68494
69109
|
}
|
|
68495
69110
|
if (contextContent && !fileSet.has(`members/${slug}/CONTEXT.md`)) {
|
|
68496
69111
|
mkdirSync19(memberDir, { recursive: true });
|
|
68497
|
-
|
|
69112
|
+
writeFileSync17(join23(memberDir, "CONTEXT.md"), contextContent, "utf-8");
|
|
68498
69113
|
}
|
|
68499
69114
|
}
|
|
68500
69115
|
const memberFiles = artifact.memberFiles;
|
|
@@ -68503,7 +69118,7 @@ EXPLANATION_END`;
|
|
|
68503
69118
|
const memberDir = join23(artDir, "members", slug);
|
|
68504
69119
|
mkdirSync19(memberDir, { recursive: true });
|
|
68505
69120
|
for (const [fn, c] of Object.entries(files))
|
|
68506
|
-
|
|
69121
|
+
writeFileSync17(join23(memberDir, fn), c, "utf-8");
|
|
68507
69122
|
}
|
|
68508
69123
|
}
|
|
68509
69124
|
}
|
|
@@ -68541,7 +69156,7 @@ EXPLANATION_END`;
|
|
|
68541
69156
|
for (const [fn, content] of Object.entries(files)) {
|
|
68542
69157
|
const filePath = join23(artDir, fn);
|
|
68543
69158
|
mkdirSync19(dirname6(filePath), { recursive: true });
|
|
68544
|
-
|
|
69159
|
+
writeFileSync17(filePath, content, "utf-8");
|
|
68545
69160
|
}
|
|
68546
69161
|
if (source) {
|
|
68547
69162
|
const mfName = manifestFilename(type);
|
|
@@ -68550,7 +69165,7 @@ EXPLANATION_END`;
|
|
|
68550
69165
|
try {
|
|
68551
69166
|
const mf = JSON.parse(readFileSync21(mfPath, "utf-8"));
|
|
68552
69167
|
mf.source = source;
|
|
68553
|
-
|
|
69168
|
+
writeFileSync17(mfPath, JSON.stringify(mf, null, 2), "utf-8");
|
|
68554
69169
|
} catch {
|
|
68555
69170
|
}
|
|
68556
69171
|
}
|
|
@@ -69224,10 +69839,10 @@ EXPLANATION_END`;
|
|
|
69224
69839
|
if (path === "/api/templates/teams" && req.method === "GET") {
|
|
69225
69840
|
try {
|
|
69226
69841
|
const { readdirSync: readdirSync13, readFileSync: readFileSync27 } = await import("node:fs");
|
|
69227
|
-
const { resolve:
|
|
69228
|
-
const teamsDir =
|
|
69842
|
+
const { resolve: resolve20 } = await import("node:path");
|
|
69843
|
+
const teamsDir = resolve20(process.cwd(), "templates", "teams");
|
|
69229
69844
|
const files = readdirSync13(teamsDir).filter((f) => f.endsWith(".json"));
|
|
69230
|
-
const teams = files.map((f) => JSON.parse(readFileSync27(
|
|
69845
|
+
const teams = files.map((f) => JSON.parse(readFileSync27(resolve20(teamsDir, f), "utf-8")));
|
|
69231
69846
|
this.json(res, 200, { templates: teams });
|
|
69232
69847
|
} catch {
|
|
69233
69848
|
this.json(res, 200, { templates: [] });
|
|
@@ -69351,7 +69966,7 @@ EXPLANATION_END`;
|
|
|
69351
69966
|
try {
|
|
69352
69967
|
if (token) {
|
|
69353
69968
|
mkdirSync19(join23(homedir14(), ".markus"), { recursive: true });
|
|
69354
|
-
|
|
69969
|
+
writeFileSync17(tokenPath, token, "utf-8");
|
|
69355
69970
|
} else if (existsSync27(tokenPath)) {
|
|
69356
69971
|
rmSync3(tokenPath);
|
|
69357
69972
|
}
|
|
@@ -69778,7 +70393,9 @@ EXPLANATION_END`;
|
|
|
69778
70393
|
return;
|
|
69779
70394
|
}
|
|
69780
70395
|
try {
|
|
70396
|
+
const prevDefault = this.llmRouter.getSettings().defaultProvider;
|
|
69781
70397
|
this.llmRouter.setProviderEnabled(providerName, enabled);
|
|
70398
|
+
const newDefault = this.llmRouter.getSettings().defaultProvider;
|
|
69782
70399
|
try {
|
|
69783
70400
|
const { loadConfig: loadCfg } = await Promise.resolve().then(() => (init_dist(), dist_exports));
|
|
69784
70401
|
const currentConfig = loadCfg(this.markusConfigPath);
|
|
@@ -69788,7 +70405,11 @@ EXPLANATION_END`;
|
|
|
69788
70405
|
} else {
|
|
69789
70406
|
providers[providerName] = { enabled };
|
|
69790
70407
|
}
|
|
69791
|
-
|
|
70408
|
+
const configUpdates = { llm: { providers } };
|
|
70409
|
+
if (prevDefault !== newDefault) {
|
|
70410
|
+
configUpdates.llm.defaultProvider = newDefault;
|
|
70411
|
+
}
|
|
70412
|
+
saveConfig(configUpdates, this.markusConfigPath);
|
|
69792
70413
|
} catch (e) {
|
|
69793
70414
|
log57.warn("Failed to persist provider enabled state", { error: String(e) });
|
|
69794
70415
|
}
|
|
@@ -69798,6 +70419,70 @@ EXPLANATION_END`;
|
|
|
69798
70419
|
}
|
|
69799
70420
|
return;
|
|
69800
70421
|
}
|
|
70422
|
+
if (path.match(/^\/api\/settings\/llm\/providers\/[^/]+\/test$/) && req.method === "POST") {
|
|
70423
|
+
const auth = await this.requireAuth(req, res);
|
|
70424
|
+
if (!auth)
|
|
70425
|
+
return;
|
|
70426
|
+
if (!this.llmRouter) {
|
|
70427
|
+
this.json(res, 503, { error: "LLM router not available" });
|
|
70428
|
+
return;
|
|
70429
|
+
}
|
|
70430
|
+
const providerName = path.split("/")[5];
|
|
70431
|
+
const provider = this.llmRouter.getProvider(providerName);
|
|
70432
|
+
if (!provider) {
|
|
70433
|
+
this.json(res, 404, { ok: false, error: `Provider "${providerName}" not found or not configured` });
|
|
70434
|
+
return;
|
|
70435
|
+
}
|
|
70436
|
+
try {
|
|
70437
|
+
const startMs = Date.now();
|
|
70438
|
+
const response = await this.llmRouter.chat({
|
|
70439
|
+
messages: [{ role: "user", content: "Reply with exactly one word: hello" }],
|
|
70440
|
+
maxTokens: 32,
|
|
70441
|
+
temperature: 0
|
|
70442
|
+
}, providerName);
|
|
70443
|
+
const durationMs = Date.now() - startMs;
|
|
70444
|
+
const reply = (response.content ?? "").trim();
|
|
70445
|
+
if (!reply) {
|
|
70446
|
+
this.json(res, 200, {
|
|
70447
|
+
ok: false,
|
|
70448
|
+
error: "Model returned empty response \u2014 API key or model may be misconfigured",
|
|
70449
|
+
model: provider.model,
|
|
70450
|
+
durationMs
|
|
70451
|
+
});
|
|
70452
|
+
} else {
|
|
70453
|
+
this.json(res, 200, {
|
|
70454
|
+
ok: true,
|
|
70455
|
+
durationMs,
|
|
70456
|
+
model: provider.model,
|
|
70457
|
+
reply: reply.slice(0, 100),
|
|
70458
|
+
usage: response.usage
|
|
70459
|
+
});
|
|
70460
|
+
}
|
|
70461
|
+
} catch (err) {
|
|
70462
|
+
const raw = String(err);
|
|
70463
|
+
const statusMatch = raw.match(/(?:API error|status)\s+(\d{3})/i);
|
|
70464
|
+
const errorCode = statusMatch ? Number(statusMatch[1]) : void 0;
|
|
70465
|
+
let errorMsg = raw.replace(/^Error:\s*/, "");
|
|
70466
|
+
const jsonStart = errorMsg.indexOf("{");
|
|
70467
|
+
if (jsonStart >= 0) {
|
|
70468
|
+
try {
|
|
70469
|
+
const jsonStr = errorMsg.slice(jsonStart);
|
|
70470
|
+
const parsed = JSON.parse(jsonStr);
|
|
70471
|
+
if (parsed.error?.message) {
|
|
70472
|
+
errorMsg = `[${parsed.error.type ?? parsed.error.code ?? errorCode ?? "error"}] ${parsed.error.message}`;
|
|
70473
|
+
}
|
|
70474
|
+
} catch {
|
|
70475
|
+
}
|
|
70476
|
+
}
|
|
70477
|
+
this.json(res, 200, {
|
|
70478
|
+
ok: false,
|
|
70479
|
+
error: errorMsg.slice(0, 500),
|
|
70480
|
+
errorCode,
|
|
70481
|
+
model: provider.model
|
|
70482
|
+
});
|
|
70483
|
+
}
|
|
70484
|
+
return;
|
|
70485
|
+
}
|
|
69801
70486
|
if (path === "/api/settings/env-models" && req.method === "GET") {
|
|
69802
70487
|
const auth = await this.requireAuth(req, res);
|
|
69803
70488
|
if (!auth)
|
|
@@ -69809,7 +70494,8 @@ EXPLANATION_END`;
|
|
|
69809
70494
|
{ provider: "siliconflow", displayName: "SiliconFlow", keyEnv: "SILICONFLOW_API_KEY", modelEnv: "SILICONFLOW_MODEL", baseUrlEnv: "SILICONFLOW_BASE_URL", defaultModel: "Qwen/Qwen3.5-35B-A3B", defaultBaseUrl: "https://api.siliconflow.cn/v1" },
|
|
69810
70495
|
{ provider: "minimax", displayName: "MiniMax", keyEnv: "MINIMAX_API_KEY", modelEnv: "MINIMAX_MODEL", baseUrlEnv: "MINIMAX_BASE_URL", defaultModel: "MiniMax-M2.7", defaultBaseUrl: "https://api.minimax.io/v1" },
|
|
69811
70496
|
{ provider: "openrouter", displayName: "OpenRouter", keyEnv: "OPENROUTER_API_KEY", modelEnv: "OPENROUTER_MODEL", baseUrlEnv: "OPENROUTER_BASE_URL", defaultModel: "xiaomi/mimo-v2-pro", defaultBaseUrl: "https://openrouter.ai/api/v1" },
|
|
69812
|
-
{ provider: "zai", displayName: "ZAI", keyEnv: "ZAI_API_KEY", modelEnv: "ZAI_MODEL", baseUrlEnv: "ZAI_BASE_URL", defaultModel: "glm-5.1", defaultBaseUrl: "https://api.z.ai/api/paas/v4" }
|
|
70497
|
+
{ provider: "zai", displayName: "ZAI", keyEnv: "ZAI_API_KEY", modelEnv: "ZAI_MODEL", baseUrlEnv: "ZAI_BASE_URL", defaultModel: "glm-5.1", defaultBaseUrl: "https://api.z.ai/api/paas/v4" },
|
|
70498
|
+
{ provider: "deepseek", displayName: "DeepSeek", keyEnv: "DEEPSEEK_API_KEY", modelEnv: "DEEPSEEK_MODEL", baseUrlEnv: "DEEPSEEK_BASE_URL", defaultModel: "deepseek-v4-flash", defaultBaseUrl: "https://api.deepseek.com" }
|
|
69813
70499
|
];
|
|
69814
70500
|
const detected = [];
|
|
69815
70501
|
for (const def of ENV_MODEL_MAP) {
|
|
@@ -69862,7 +70548,9 @@ EXPLANATION_END`;
|
|
|
69862
70548
|
google: "GOOGLE_API_KEY",
|
|
69863
70549
|
siliconflow: "SILICONFLOW_API_KEY",
|
|
69864
70550
|
minimax: "MINIMAX_API_KEY",
|
|
69865
|
-
openrouter: "OPENROUTER_API_KEY"
|
|
70551
|
+
openrouter: "OPENROUTER_API_KEY",
|
|
70552
|
+
zai: "ZAI_API_KEY",
|
|
70553
|
+
deepseek: "DEEPSEEK_API_KEY"
|
|
69866
70554
|
};
|
|
69867
70555
|
const apiKey = process.env[envKeyMap[pu.provider] ?? ""];
|
|
69868
70556
|
if (!apiKey)
|
|
@@ -70481,14 +71169,14 @@ EXPLANATION_END`;
|
|
|
70481
71169
|
return;
|
|
70482
71170
|
}
|
|
70483
71171
|
try {
|
|
70484
|
-
const { resolve:
|
|
71172
|
+
const { resolve: resolve20, extname } = await import("node:path");
|
|
70485
71173
|
const { existsSync: existsSync36, statSync: statSync6 } = await import("node:fs");
|
|
70486
71174
|
const results = {};
|
|
70487
71175
|
const mdExts = [".md", ".markdown"];
|
|
70488
71176
|
const imageExts = [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg"];
|
|
70489
71177
|
for (const p of paths.slice(0, 50)) {
|
|
70490
71178
|
try {
|
|
70491
|
-
const resolved =
|
|
71179
|
+
const resolved = resolve20(p);
|
|
70492
71180
|
if (!existsSync36(resolved)) {
|
|
70493
71181
|
results[p] = { exists: false, isFile: false, type: "unknown" };
|
|
70494
71182
|
continue;
|
|
@@ -70521,9 +71209,9 @@ EXPLANATION_END`;
|
|
|
70521
71209
|
return;
|
|
70522
71210
|
}
|
|
70523
71211
|
try {
|
|
70524
|
-
const { resolve:
|
|
71212
|
+
const { resolve: resolve20, extname } = await import("node:path");
|
|
70525
71213
|
const { readFileSync: readFileSync27, existsSync: existsSync36, statSync: statSync6 } = await import("node:fs");
|
|
70526
|
-
const resolved =
|
|
71214
|
+
const resolved = resolve20(filePath);
|
|
70527
71215
|
if (!existsSync36(resolved)) {
|
|
70528
71216
|
this.json(res, 404, { error: "File not found" });
|
|
70529
71217
|
return;
|
|
@@ -70571,10 +71259,10 @@ EXPLANATION_END`;
|
|
|
70571
71259
|
return;
|
|
70572
71260
|
}
|
|
70573
71261
|
try {
|
|
70574
|
-
const { resolve:
|
|
71262
|
+
const { resolve: resolve20, dirname: dirname11 } = await import("node:path");
|
|
70575
71263
|
const { existsSync: existsSync36, statSync: statSync6 } = await import("node:fs");
|
|
70576
71264
|
const { exec: exec2 } = await import("node:child_process");
|
|
70577
|
-
const resolved =
|
|
71265
|
+
const resolved = resolve20(filePath);
|
|
70578
71266
|
if (!existsSync36(resolved)) {
|
|
70579
71267
|
this.json(res, 404, { error: "Path not found" });
|
|
70580
71268
|
return;
|
|
@@ -71304,14 +71992,14 @@ EXPLANATION_END`;
|
|
|
71304
71992
|
res.end(JSON.stringify(data));
|
|
71305
71993
|
}
|
|
71306
71994
|
readBody(req) {
|
|
71307
|
-
return new Promise((
|
|
71995
|
+
return new Promise((resolve20, reject) => {
|
|
71308
71996
|
const chunks = [];
|
|
71309
71997
|
req.on("data", (chunk) => chunks.push(chunk));
|
|
71310
71998
|
req.on("end", () => {
|
|
71311
71999
|
try {
|
|
71312
|
-
|
|
72000
|
+
resolve20(JSON.parse(Buffer.concat(chunks).toString()));
|
|
71313
72001
|
} catch {
|
|
71314
|
-
|
|
72002
|
+
resolve20({});
|
|
71315
72003
|
}
|
|
71316
72004
|
});
|
|
71317
72005
|
req.on("error", reject);
|
|
@@ -71621,7 +72309,7 @@ var init_hitl_service = __esm({
|
|
|
71621
72309
|
this.persistApproval(approval);
|
|
71622
72310
|
log58.info(`Approval requested: ${id} by ${opts.agentName}`);
|
|
71623
72311
|
this.notify({
|
|
71624
|
-
targetUserId: opts.targetUserId ?? "
|
|
72312
|
+
targetUserId: opts.targetUserId ?? "all",
|
|
71625
72313
|
type: "approval_request",
|
|
71626
72314
|
title: `Approval needed: ${opts.title}`,
|
|
71627
72315
|
body: opts.description,
|
|
@@ -71634,13 +72322,13 @@ var init_hitl_service = __esm({
|
|
|
71634
72322
|
}
|
|
71635
72323
|
async requestApprovalAndWait(opts) {
|
|
71636
72324
|
const approval = this.requestApproval(opts);
|
|
71637
|
-
return new Promise((
|
|
71638
|
-
this.pendingResolvers.set(approval.id,
|
|
72325
|
+
return new Promise((resolve20) => {
|
|
72326
|
+
this.pendingResolvers.set(approval.id, resolve20);
|
|
71639
72327
|
if (opts.expiresInMs) {
|
|
71640
72328
|
setTimeout(() => {
|
|
71641
72329
|
if (this.pendingResolvers.has(approval.id)) {
|
|
71642
72330
|
this.pendingResolvers.delete(approval.id);
|
|
71643
|
-
|
|
72331
|
+
resolve20({ approved: false, comment: "Approval timed out" });
|
|
71644
72332
|
}
|
|
71645
72333
|
}, opts.expiresInMs);
|
|
71646
72334
|
}
|
|
@@ -71670,10 +72358,10 @@ var init_hitl_service = __esm({
|
|
|
71670
72358
|
} catch {
|
|
71671
72359
|
}
|
|
71672
72360
|
}
|
|
71673
|
-
const
|
|
71674
|
-
if (
|
|
72361
|
+
const resolve20 = this.pendingResolvers.get(id);
|
|
72362
|
+
if (resolve20) {
|
|
71675
72363
|
this.pendingResolvers.delete(id);
|
|
71676
|
-
|
|
72364
|
+
resolve20({ approved, comment, selectedOption });
|
|
71677
72365
|
}
|
|
71678
72366
|
return approval;
|
|
71679
72367
|
}
|
|
@@ -72389,7 +73077,7 @@ var init_requirement_service = __esm({
|
|
|
72389
73077
|
title: `Requirement approval: ${req.title}`,
|
|
72390
73078
|
description: `Agent "${req.createdBy}" proposed requirement "${req.title}" (priority: ${req.priority}).`,
|
|
72391
73079
|
details: { requirementId: req.id, priority: req.priority },
|
|
72392
|
-
targetUserId: "
|
|
73080
|
+
targetUserId: "all"
|
|
72393
73081
|
}).then((result) => {
|
|
72394
73082
|
const current = this.requirements.get(req.id);
|
|
72395
73083
|
if (!current || current.status !== "pending")
|
|
@@ -72522,7 +73210,7 @@ var init_requirement_service = __esm({
|
|
|
72522
73210
|
title: `Requirement approval (resubmitted): ${req.title}`,
|
|
72523
73211
|
description: `Agent "${req.createdBy}" resubmitted requirement "${req.title}" (priority: ${req.priority}).`,
|
|
72524
73212
|
details: { requirementId: req.id, priority: req.priority },
|
|
72525
|
-
targetUserId: "
|
|
73213
|
+
targetUserId: "all"
|
|
72526
73214
|
}).then((result) => {
|
|
72527
73215
|
const current = this.requirements.get(req.id);
|
|
72528
73216
|
if (!current || current.status !== "pending")
|
|
@@ -72643,11 +73331,13 @@ var init_requirement_service = __esm({
|
|
|
72643
73331
|
req.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
72644
73332
|
}
|
|
72645
73333
|
/**
|
|
72646
|
-
* Check if all tasks for a requirement are done.
|
|
73334
|
+
* Check if all tasks for a requirement are done. Instead of auto-completing,
|
|
73335
|
+
* notify the creator agent so they can review results and decide whether to
|
|
73336
|
+
* complete the requirement or create additional tasks.
|
|
72647
73337
|
*/
|
|
72648
73338
|
checkCompletion(requirementId2, taskStatuses) {
|
|
72649
73339
|
const req = this.requirements.get(requirementId2);
|
|
72650
|
-
if (!req || req.status === "completed")
|
|
73340
|
+
if (!req || req.status === "completed" || req.status === "cancelled")
|
|
72651
73341
|
return false;
|
|
72652
73342
|
if (req.taskIds.length === 0)
|
|
72653
73343
|
return false;
|
|
@@ -72655,14 +73345,28 @@ var init_requirement_service = __esm({
|
|
|
72655
73345
|
const status = taskStatuses.get(tid);
|
|
72656
73346
|
return status === "completed" || status === "cancelled" || status === "archived";
|
|
72657
73347
|
});
|
|
72658
|
-
if (allDone) {
|
|
72659
|
-
|
|
72660
|
-
|
|
72661
|
-
|
|
72662
|
-
|
|
73348
|
+
if (allDone && req.createdBy && this.agentManager) {
|
|
73349
|
+
try {
|
|
73350
|
+
const agent = this.agentManager.getAgent(req.createdBy);
|
|
73351
|
+
if (agent) {
|
|
73352
|
+
agent.enqueueToMailbox("requirement_update", {
|
|
73353
|
+
summary: `All tasks for requirement "${req.title}" are done \u2014 review needed`,
|
|
73354
|
+
content: [
|
|
73355
|
+
`[REQUIREMENT REVIEW NEEDED] All linked tasks for "${req.title}" (ID: ${requirementId2}) have reached terminal state.`,
|
|
73356
|
+
"",
|
|
73357
|
+
"Please review the results and decide:",
|
|
73358
|
+
`1. If the requirement is fully satisfied, complete it: requirement_update_status(requirement_id="${requirementId2}", status="completed")`,
|
|
73359
|
+
`2. If more work is needed, create additional tasks with task_create(requirement_id="${requirementId2}", ...)`
|
|
73360
|
+
].join("\n"),
|
|
73361
|
+
requirementId: requirementId2,
|
|
73362
|
+
extra: { actionRequired: true }
|
|
73363
|
+
}, {
|
|
73364
|
+
priority: 2,
|
|
73365
|
+
metadata: { senderName: "System", senderRole: "manager" }
|
|
73366
|
+
});
|
|
73367
|
+
}
|
|
73368
|
+
} catch {
|
|
72663
73369
|
}
|
|
72664
|
-
this.broadcast("requirement:completed", req);
|
|
72665
|
-
log62.info("Requirement completed", { id: requirementId2 });
|
|
72666
73370
|
return true;
|
|
72667
73371
|
}
|
|
72668
73372
|
return false;
|
|
@@ -72806,14 +73510,13 @@ var init_requirement_service = __esm({
|
|
|
72806
73510
|
parts.push("2. Abandon this requirement if the feedback indicates it is not needed");
|
|
72807
73511
|
}
|
|
72808
73512
|
const agent = this.agentManager.getAgent(creatorId);
|
|
72809
|
-
const isRejection = decision === "rejected";
|
|
72810
73513
|
agent.enqueueToMailbox("requirement_update", {
|
|
72811
73514
|
summary: `Requirement "${req.title}" ${decision}`,
|
|
72812
73515
|
content: parts.join("\n"),
|
|
72813
73516
|
requirementId: req.id,
|
|
72814
|
-
extra:
|
|
73517
|
+
extra: { actionRequired: true }
|
|
72815
73518
|
}, {
|
|
72816
|
-
priority:
|
|
73519
|
+
priority: 1,
|
|
72817
73520
|
metadata: { senderName: "System", senderRole: "manager" }
|
|
72818
73521
|
});
|
|
72819
73522
|
log62.info("Notified creator agent about requirement decision", {
|
|
@@ -72826,7 +73529,7 @@ var init_requirement_service = __esm({
|
|
|
72826
73529
|
const title = decision === "approved" ? `Requirement approved: ${req.title}` : `Requirement rejected: ${req.title}`;
|
|
72827
73530
|
const body = decision === "approved" ? `Requirement "${req.title}" has been approved and is now in progress.` : `Requirement "${req.title}" has been rejected.${reason ? ` Reason: ${reason}` : ""}`;
|
|
72828
73531
|
this.hitlService.notify({
|
|
72829
|
-
targetUserId: "
|
|
73532
|
+
targetUserId: "all",
|
|
72830
73533
|
type: "requirement_decision",
|
|
72831
73534
|
title,
|
|
72832
73535
|
body,
|
|
@@ -73031,7 +73734,7 @@ var init_knowledge_service = __esm({
|
|
|
73031
73734
|
});
|
|
73032
73735
|
|
|
73033
73736
|
// ../org-manager/dist/file-knowledge-store.js
|
|
73034
|
-
import { readFileSync as readFileSync22, writeFileSync as
|
|
73737
|
+
import { readFileSync as readFileSync22, writeFileSync as writeFileSync18, existsSync as existsSync28, mkdirSync as mkdirSync20, readdirSync as readdirSync11, unlinkSync as unlinkSync3 } from "node:fs";
|
|
73035
73738
|
import { join as join24 } from "node:path";
|
|
73036
73739
|
function readdirSafe(dir) {
|
|
73037
73740
|
try {
|
|
@@ -73087,12 +73790,12 @@ var init_file_knowledge_store = __esm({
|
|
|
73087
73790
|
saveEntry(entry) {
|
|
73088
73791
|
const dir = this.scopeDir(entry.scope, entry.scopeId);
|
|
73089
73792
|
mkdirSync20(dir, { recursive: true });
|
|
73090
|
-
|
|
73793
|
+
writeFileSync18(join24(dir, `${entry.id}.json`), JSON.stringify(entry, null, 2));
|
|
73091
73794
|
}
|
|
73092
73795
|
saveIndex(scope, scopeId, entries2) {
|
|
73093
73796
|
const dir = this.scopeDir(scope, scopeId);
|
|
73094
73797
|
mkdirSync20(dir, { recursive: true });
|
|
73095
|
-
|
|
73798
|
+
writeFileSync18(join24(dir, "_index.json"), JSON.stringify(entries2, null, 2));
|
|
73096
73799
|
}
|
|
73097
73800
|
removeEntryFile(entry) {
|
|
73098
73801
|
const p = join24(this.scopeDir(entry.scope, entry.scopeId), `${entry.id}.json`);
|
|
@@ -74130,7 +74833,8 @@ function openSqlite(dbPath) {
|
|
|
74130
74833
|
{ table: "chat_sessions", column: "is_main", sql: "ALTER TABLE chat_sessions ADD COLUMN is_main INTEGER NOT NULL DEFAULT 0" },
|
|
74131
74834
|
{ table: "mailbox_items", column: "retry_count", sql: "ALTER TABLE mailbox_items ADD COLUMN retry_count INTEGER NOT NULL DEFAULT 0" },
|
|
74132
74835
|
{ table: "users", column: "avatar_url", sql: "ALTER TABLE users ADD COLUMN avatar_url TEXT" },
|
|
74133
|
-
{ table: "agents", column: "avatar_url", sql: "ALTER TABLE agents ADD COLUMN avatar_url TEXT" }
|
|
74836
|
+
{ table: "agents", column: "avatar_url", sql: "ALTER TABLE agents ADD COLUMN avatar_url TEXT" },
|
|
74837
|
+
{ table: "channel_messages", column: "reply_to_id", sql: "ALTER TABLE channel_messages ADD COLUMN reply_to_id TEXT" }
|
|
74134
74838
|
];
|
|
74135
74839
|
for (const m of migrations) {
|
|
74136
74840
|
const cols = _db.prepare(`PRAGMA table_info(${m.table})`).all();
|
|
@@ -74187,7 +74891,7 @@ function migrateToExecutionStreamLogs(db) {
|
|
|
74187
74891
|
log71.info(`Migration: copied ${actLogCount} agent_activity_logs to execution_stream_logs`);
|
|
74188
74892
|
}
|
|
74189
74893
|
}
|
|
74190
|
-
var log71, SCHEMA_SQL, _db, SqliteOrgRepo, SqliteAgentRepo, SqliteTaskRepo, SqliteRequirementRepo, SqliteProjectRepo, SqliteTaskLogRepo, SqliteTaskCommentRepo, SqliteRequirementCommentRepo, SqliteMessageRepo, SqliteChatSessionRepo, SqliteChannelMessageRepo, SqliteUserRepo, SqliteTeamRepo, SqliteMarketplaceTemplateRepo, SqliteMarketplaceSkillRepo, SqliteMarketplaceRatingRepo, SqliteAgentKnowledgeRepo, SqliteExternalAgentRepo, SqliteDeliverableRepo, SqliteActivityRepo, SqliteExecutionStreamRepo, SqliteMailboxRepo, SqliteDecisionRepo, SqliteNotificationRepo, SqliteApprovalRepo;
|
|
74894
|
+
var log71, SCHEMA_SQL, _db, SqliteOrgRepo, SqliteAgentRepo, SqliteTaskRepo, SqliteRequirementRepo, SqliteProjectRepo, SqliteTaskLogRepo, SqliteTaskCommentRepo, SqliteRequirementCommentRepo, SqliteMessageRepo, SqliteChatSessionRepo, SqliteChannelMessageRepo, SqliteUserRepo, SqliteTeamRepo, SqliteMarketplaceTemplateRepo, SqliteMarketplaceSkillRepo, SqliteMarketplaceRatingRepo, SqliteAgentKnowledgeRepo, SqliteExternalAgentRepo, SqliteDeliverableRepo, SqliteActivityRepo, SqliteExecutionStreamRepo, SqliteMailboxRepo, SqliteDecisionRepo, SqliteNotificationRepo, SqliteApprovalRepo, SqliteGroupChatRepo;
|
|
74191
74895
|
var init_sqlite_storage = __esm({
|
|
74192
74896
|
"../storage/dist/sqlite-storage.js"() {
|
|
74193
74897
|
"use strict";
|
|
@@ -74325,6 +75029,7 @@ CREATE TABLE IF NOT EXISTS channel_messages (
|
|
|
74325
75029
|
text TEXT NOT NULL,
|
|
74326
75030
|
mentions TEXT NOT NULL DEFAULT '[]',
|
|
74327
75031
|
metadata TEXT DEFAULT '{}',
|
|
75032
|
+
reply_to_id TEXT,
|
|
74328
75033
|
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
74329
75034
|
);
|
|
74330
75035
|
CREATE INDEX IF NOT EXISTS idx_channel_messages_channel ON channel_messages(channel, created_at);
|
|
@@ -74685,6 +75390,26 @@ CREATE TABLE IF NOT EXISTS approvals (
|
|
|
74685
75390
|
selected_option TEXT
|
|
74686
75391
|
);
|
|
74687
75392
|
CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_at DESC);
|
|
75393
|
+
|
|
75394
|
+
CREATE TABLE IF NOT EXISTS group_chats (
|
|
75395
|
+
id TEXT PRIMARY KEY,
|
|
75396
|
+
org_id TEXT NOT NULL DEFAULT 'default',
|
|
75397
|
+
name TEXT NOT NULL,
|
|
75398
|
+
channel_key TEXT NOT NULL UNIQUE,
|
|
75399
|
+
creator_id TEXT NOT NULL,
|
|
75400
|
+
creator_name TEXT NOT NULL,
|
|
75401
|
+
created_at TEXT NOT NULL DEFAULT (datetime('now'))
|
|
75402
|
+
);
|
|
75403
|
+
|
|
75404
|
+
CREATE TABLE IF NOT EXISTS group_chat_members (
|
|
75405
|
+
group_chat_id TEXT NOT NULL REFERENCES group_chats(id) ON DELETE CASCADE,
|
|
75406
|
+
member_id TEXT NOT NULL,
|
|
75407
|
+
member_type TEXT NOT NULL CHECK(member_type IN ('human', 'agent')),
|
|
75408
|
+
member_name TEXT NOT NULL,
|
|
75409
|
+
added_at TEXT NOT NULL DEFAULT (datetime('now')),
|
|
75410
|
+
PRIMARY KEY (group_chat_id, member_id)
|
|
75411
|
+
);
|
|
75412
|
+
CREATE INDEX IF NOT EXISTS idx_group_chat_members_group ON group_chat_members(group_chat_id);
|
|
74688
75413
|
`;
|
|
74689
75414
|
_db = null;
|
|
74690
75415
|
SqliteOrgRepo = class {
|
|
@@ -75553,7 +76278,7 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
75553
76278
|
async append(data) {
|
|
75554
76279
|
const id = generateId2("chm");
|
|
75555
76280
|
const ts = now();
|
|
75556
|
-
this.db.prepare("INSERT INTO channel_messages (id, org_id, channel, sender_id, sender_type, sender_name, text, mentions, metadata, created_at) VALUES (
|
|
76281
|
+
this.db.prepare("INSERT INTO channel_messages (id, org_id, channel, sender_id, sender_type, sender_name, text, mentions, metadata, reply_to_id, created_at) VALUES (?,?,?,?,?,?,?,?,?,?,?)").run(id, data.orgId, data.channel, data.senderId, data.senderType, data.senderName, data.text, toJson(data.mentions ?? []), toJson(data.metadata ?? {}), data.replyToId ?? null, ts);
|
|
75557
76282
|
return {
|
|
75558
76283
|
id,
|
|
75559
76284
|
orgId: data.orgId,
|
|
@@ -75564,17 +76289,20 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
75564
76289
|
text: data.text,
|
|
75565
76290
|
mentions: data.mentions ?? [],
|
|
75566
76291
|
metadata: data.metadata ?? null,
|
|
76292
|
+
replyToId: data.replyToId,
|
|
75567
76293
|
createdAt: new Date(ts)
|
|
75568
76294
|
};
|
|
75569
76295
|
}
|
|
75570
76296
|
getMessages(channel, limit = 50, before2) {
|
|
75571
|
-
let q =
|
|
76297
|
+
let q = `SELECT m.*, r.sender_name AS reply_to_sender, SUBSTR(r.text, 1, 120) AS reply_to_text
|
|
76298
|
+
FROM channel_messages m LEFT JOIN channel_messages r ON m.reply_to_id = r.id
|
|
76299
|
+
WHERE m.channel = ?`;
|
|
75572
76300
|
const vals = [channel];
|
|
75573
76301
|
if (before2) {
|
|
75574
|
-
q += " AND created_at < ?";
|
|
76302
|
+
q += " AND m.created_at < ?";
|
|
75575
76303
|
vals.push(before2);
|
|
75576
76304
|
}
|
|
75577
|
-
q += " ORDER BY created_at DESC LIMIT ?";
|
|
76305
|
+
q += " ORDER BY m.created_at DESC LIMIT ?";
|
|
75578
76306
|
vals.push(limit + 1);
|
|
75579
76307
|
const rows = this.db.prepare(q).all(...vals).map((r) => ({
|
|
75580
76308
|
id: r["id"],
|
|
@@ -75586,11 +76314,26 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
75586
76314
|
text: r["text"],
|
|
75587
76315
|
mentions: fromJson(r["mentions"]),
|
|
75588
76316
|
metadata: fromJson(r["metadata"]),
|
|
76317
|
+
replyToId: r["reply_to_id"] ?? void 0,
|
|
76318
|
+
replyToSender: r["reply_to_sender"] ?? void 0,
|
|
76319
|
+
replyToText: r["reply_to_text"] ?? void 0,
|
|
75589
76320
|
createdAt: toDate(r["created_at"])
|
|
75590
76321
|
}));
|
|
75591
76322
|
const hasMore = rows.length > limit;
|
|
75592
76323
|
return { messages: rows.slice(0, limit).reverse(), hasMore };
|
|
75593
76324
|
}
|
|
76325
|
+
getMessageById(id) {
|
|
76326
|
+
const r = this.db.prepare("SELECT * FROM channel_messages WHERE id = ?").get(id);
|
|
76327
|
+
if (!r)
|
|
76328
|
+
return void 0;
|
|
76329
|
+
return {
|
|
76330
|
+
id: r["id"],
|
|
76331
|
+
senderName: r["sender_name"],
|
|
76332
|
+
senderType: r["sender_type"],
|
|
76333
|
+
senderId: r["sender_id"],
|
|
76334
|
+
text: r["text"]
|
|
76335
|
+
};
|
|
76336
|
+
}
|
|
75594
76337
|
};
|
|
75595
76338
|
SqliteUserRepo = class {
|
|
75596
76339
|
db;
|
|
@@ -76610,8 +77353,8 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
76610
77353
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(n.id, n.userId, n.type, n.title, n.body, n.priority, n.read ? 1 : 0, n.actionType, n.actionTarget, n.metadata ? JSON.stringify(n.metadata) : null, n.createdAt);
|
|
76611
77354
|
}
|
|
76612
77355
|
list(userId, opts) {
|
|
76613
|
-
const conditions = ["(user_id = ? OR user_id = ?)"];
|
|
76614
|
-
const params = [userId, "all"];
|
|
77356
|
+
const conditions = ["(user_id = ? OR user_id = ? OR user_id = ?)"];
|
|
77357
|
+
const params = [userId, "all", "default"];
|
|
76615
77358
|
if (opts?.unreadOnly) {
|
|
76616
77359
|
conditions.push("read = 0");
|
|
76617
77360
|
}
|
|
@@ -76626,8 +77369,8 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
76626
77369
|
return this.db.prepare(sql).all(...params).map((r) => this.mapRow(r));
|
|
76627
77370
|
}
|
|
76628
77371
|
count(userId, unreadOnly = false) {
|
|
76629
|
-
const conditions = ["(user_id = ? OR user_id = ?)"];
|
|
76630
|
-
const params = [userId, "all"];
|
|
77372
|
+
const conditions = ["(user_id = ? OR user_id = ? OR user_id = ?)"];
|
|
77373
|
+
const params = [userId, "all", "default"];
|
|
76631
77374
|
if (unreadOnly)
|
|
76632
77375
|
conditions.push("read = 0");
|
|
76633
77376
|
const row = this.db.prepare(`SELECT COUNT(*) as cnt FROM user_notifications WHERE ${conditions.join(" AND ")}`).get(...params);
|
|
@@ -76638,7 +77381,7 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
76638
77381
|
return info4.changes > 0;
|
|
76639
77382
|
}
|
|
76640
77383
|
markAllRead(userId) {
|
|
76641
|
-
const info4 = this.db.prepare("UPDATE user_notifications SET read = 1 WHERE (user_id = ? OR user_id = ?) AND read = 0").run(userId, "all");
|
|
77384
|
+
const info4 = this.db.prepare("UPDATE user_notifications SET read = 1 WHERE (user_id = ? OR user_id = ? OR user_id = ?) AND read = 0").run(userId, "all", "default");
|
|
76642
77385
|
return Number(info4.changes);
|
|
76643
77386
|
}
|
|
76644
77387
|
mapRow(r) {
|
|
@@ -76708,6 +77451,96 @@ CREATE INDEX IF NOT EXISTS idx_approvals_status ON approvals(status, requested_a
|
|
|
76708
77451
|
};
|
|
76709
77452
|
}
|
|
76710
77453
|
};
|
|
77454
|
+
SqliteGroupChatRepo = class {
|
|
77455
|
+
db;
|
|
77456
|
+
constructor(db) {
|
|
77457
|
+
this.db = db;
|
|
77458
|
+
}
|
|
77459
|
+
create(data) {
|
|
77460
|
+
const id = generateId2("gc");
|
|
77461
|
+
const channelKey = `group:custom:${id}`;
|
|
77462
|
+
const ts = now();
|
|
77463
|
+
this.db.prepare("INSERT INTO group_chats (id, org_id, name, channel_key, creator_id, creator_name, created_at) VALUES (?,?,?,?,?,?,?)").run(id, data.orgId, data.name, channelKey, data.creatorId, data.creatorName, ts);
|
|
77464
|
+
const insertMember = this.db.prepare("INSERT OR IGNORE INTO group_chat_members (group_chat_id, member_id, member_type, member_name, added_at) VALUES (?,?,?,?,?)");
|
|
77465
|
+
const members = [];
|
|
77466
|
+
for (const m of data.members) {
|
|
77467
|
+
insertMember.run(id, m.id, m.type, m.name, ts);
|
|
77468
|
+
members.push({ groupChatId: id, memberId: m.id, memberType: m.type, memberName: m.name, addedAt: new Date(ts) });
|
|
77469
|
+
}
|
|
77470
|
+
return {
|
|
77471
|
+
id,
|
|
77472
|
+
orgId: data.orgId,
|
|
77473
|
+
name: data.name,
|
|
77474
|
+
channelKey,
|
|
77475
|
+
creatorId: data.creatorId,
|
|
77476
|
+
creatorName: data.creatorName,
|
|
77477
|
+
createdAt: new Date(ts),
|
|
77478
|
+
members
|
|
77479
|
+
};
|
|
77480
|
+
}
|
|
77481
|
+
list(orgId2) {
|
|
77482
|
+
const rows = this.db.prepare(`SELECT g.*, (SELECT COUNT(*) FROM group_chat_members WHERE group_chat_id = g.id) AS member_count
|
|
77483
|
+
FROM group_chats g WHERE g.org_id = ? ORDER BY g.created_at DESC`).all(orgId2);
|
|
77484
|
+
return rows.map((r) => ({
|
|
77485
|
+
...this.mapRow(r),
|
|
77486
|
+
memberCount: r["member_count"]
|
|
77487
|
+
}));
|
|
77488
|
+
}
|
|
77489
|
+
getById(id) {
|
|
77490
|
+
const r = this.db.prepare("SELECT * FROM group_chats WHERE id = ?").get(id);
|
|
77491
|
+
if (!r)
|
|
77492
|
+
return void 0;
|
|
77493
|
+
const members = this.getMembers(id);
|
|
77494
|
+
return { ...this.mapRow(r), members };
|
|
77495
|
+
}
|
|
77496
|
+
getByChannelKey(channelKey) {
|
|
77497
|
+
const r = this.db.prepare("SELECT * FROM group_chats WHERE channel_key = ?").get(channelKey);
|
|
77498
|
+
if (!r)
|
|
77499
|
+
return void 0;
|
|
77500
|
+
const gc = this.mapRow(r);
|
|
77501
|
+
return { ...gc, members: this.getMembers(gc.id) };
|
|
77502
|
+
}
|
|
77503
|
+
getMembers(groupChatId) {
|
|
77504
|
+
const rows = this.db.prepare("SELECT * FROM group_chat_members WHERE group_chat_id = ?").all(groupChatId);
|
|
77505
|
+
return rows.map((r) => ({
|
|
77506
|
+
groupChatId: r["group_chat_id"],
|
|
77507
|
+
memberId: r["member_id"],
|
|
77508
|
+
memberType: r["member_type"],
|
|
77509
|
+
memberName: r["member_name"],
|
|
77510
|
+
addedAt: toDate(r["added_at"])
|
|
77511
|
+
}));
|
|
77512
|
+
}
|
|
77513
|
+
getAgentMemberIds(channelKey) {
|
|
77514
|
+
const gc = this.db.prepare("SELECT id FROM group_chats WHERE channel_key = ?").get(channelKey);
|
|
77515
|
+
if (!gc)
|
|
77516
|
+
return [];
|
|
77517
|
+
const rows = this.db.prepare("SELECT member_id FROM group_chat_members WHERE group_chat_id = ? AND member_type = 'agent'").all(gc.id);
|
|
77518
|
+
return rows.map((r) => r.member_id);
|
|
77519
|
+
}
|
|
77520
|
+
addMember(groupChatId, memberId, memberType, memberName) {
|
|
77521
|
+
this.db.prepare("INSERT OR IGNORE INTO group_chat_members (group_chat_id, member_id, member_type, member_name, added_at) VALUES (?,?,?,?,?)").run(groupChatId, memberId, memberType, memberName, now());
|
|
77522
|
+
}
|
|
77523
|
+
removeMember(groupChatId, memberId) {
|
|
77524
|
+
this.db.prepare("DELETE FROM group_chat_members WHERE group_chat_id = ? AND member_id = ?").run(groupChatId, memberId);
|
|
77525
|
+
}
|
|
77526
|
+
updateName(id, name) {
|
|
77527
|
+
this.db.prepare("UPDATE group_chats SET name = ? WHERE id = ?").run(name, id);
|
|
77528
|
+
}
|
|
77529
|
+
delete(id) {
|
|
77530
|
+
this.db.prepare("DELETE FROM group_chats WHERE id = ?").run(id);
|
|
77531
|
+
}
|
|
77532
|
+
mapRow(r) {
|
|
77533
|
+
return {
|
|
77534
|
+
id: r["id"],
|
|
77535
|
+
orgId: r["org_id"],
|
|
77536
|
+
name: r["name"],
|
|
77537
|
+
channelKey: r["channel_key"],
|
|
77538
|
+
creatorId: r["creator_id"],
|
|
77539
|
+
creatorName: r["creator_name"],
|
|
77540
|
+
createdAt: toDate(r["created_at"])
|
|
77541
|
+
};
|
|
77542
|
+
}
|
|
77543
|
+
};
|
|
76711
77544
|
}
|
|
76712
77545
|
});
|
|
76713
77546
|
|
|
@@ -76724,6 +77557,7 @@ __export(dist_exports3, {
|
|
|
76724
77557
|
SqliteDeliverableRepo: () => SqliteDeliverableRepo,
|
|
76725
77558
|
SqliteExecutionStreamRepo: () => SqliteExecutionStreamRepo,
|
|
76726
77559
|
SqliteExternalAgentRepo: () => SqliteExternalAgentRepo,
|
|
77560
|
+
SqliteGroupChatRepo: () => SqliteGroupChatRepo,
|
|
76727
77561
|
SqliteMailboxRepo: () => SqliteMailboxRepo,
|
|
76728
77562
|
SqliteMarketplaceRatingRepo: () => SqliteMarketplaceRatingRepo,
|
|
76729
77563
|
SqliteMarketplaceSkillRepo: () => SqliteMarketplaceSkillRepo,
|
|
@@ -76793,7 +77627,8 @@ async function initSqliteStorage(url) {
|
|
|
76793
77627
|
mailboxRepo: new storage.SqliteMailboxRepo(db),
|
|
76794
77628
|
decisionRepo: new storage.SqliteDecisionRepo(db),
|
|
76795
77629
|
notificationRepo: new storage.SqliteNotificationRepo(db),
|
|
76796
|
-
approvalRepo: new storage.SqliteApprovalRepo(db)
|
|
77630
|
+
approvalRepo: new storage.SqliteApprovalRepo(db),
|
|
77631
|
+
groupChatRepo: new storage.SqliteGroupChatRepo(db)
|
|
76797
77632
|
};
|
|
76798
77633
|
log72.info("SQLite storage initialized", { path: dbPath });
|
|
76799
77634
|
return bridge;
|
|
@@ -77884,8 +78719,8 @@ var init_startupProgress = __esm({
|
|
|
77884
78719
|
});
|
|
77885
78720
|
|
|
77886
78721
|
// src/connector-service.ts
|
|
77887
|
-
import { resolve as
|
|
77888
|
-
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as
|
|
78722
|
+
import { resolve as resolve14, join as join28, dirname as dirname8 } from "node:path";
|
|
78723
|
+
import { existsSync as existsSync31, readFileSync as readFileSync23, writeFileSync as writeFileSync19, mkdirSync as mkdirSync24, readdirSync as readdirSync12, cpSync as cpSync3 } from "node:fs";
|
|
77889
78724
|
import { homedir as homedir18 } from "node:os";
|
|
77890
78725
|
import { execSync as execSync4 } from "node:child_process";
|
|
77891
78726
|
import { fileURLToPath as fileURLToPath4 } from "node:url";
|
|
@@ -77894,9 +78729,9 @@ function expandHome(p) {
|
|
|
77894
78729
|
}
|
|
77895
78730
|
function loadConnectors() {
|
|
77896
78731
|
const connectors = /* @__PURE__ */ new Map();
|
|
77897
|
-
const builtinDir =
|
|
78732
|
+
const builtinDir = resolve14(__dirname3, "..", "connectors");
|
|
77898
78733
|
loadFromDir(builtinDir, connectors);
|
|
77899
|
-
const devDir =
|
|
78734
|
+
const devDir = resolve14(process.cwd(), "packages", "cli", "connectors");
|
|
77900
78735
|
if (devDir !== builtinDir) loadFromDir(devDir, connectors);
|
|
77901
78736
|
const userDir = join28(homedir18(), ".markus", "connectors");
|
|
77902
78737
|
loadFromDir(userDir, connectors);
|
|
@@ -77986,7 +78821,7 @@ function writePlatformConfig(connector, markusUrl, token) {
|
|
|
77986
78821
|
setNestedField(config, connector.integration.tokenField, token);
|
|
77987
78822
|
try {
|
|
77988
78823
|
const content = JSON.stringify(config, null, 2);
|
|
77989
|
-
|
|
78824
|
+
writeFileSync19(configPath, content, "utf-8");
|
|
77990
78825
|
return true;
|
|
77991
78826
|
} catch {
|
|
77992
78827
|
return false;
|
|
@@ -78000,8 +78835,8 @@ function installSkillTemplate(connector) {
|
|
|
78000
78835
|
const templateName = connector.integration.skillTemplateName;
|
|
78001
78836
|
const candidates = [
|
|
78002
78837
|
join28(homedir18(), ".markus", "templates", templateName),
|
|
78003
|
-
|
|
78004
|
-
|
|
78838
|
+
resolve14(process.cwd(), "templates", templateName),
|
|
78839
|
+
resolve14(__dirname3, "..", "templates", templateName)
|
|
78005
78840
|
];
|
|
78006
78841
|
let sourceDir;
|
|
78007
78842
|
for (const c of candidates) {
|
|
@@ -78065,11 +78900,11 @@ __export(init_exports, {
|
|
|
78065
78900
|
quickInit: () => quickInit,
|
|
78066
78901
|
registerInitCommand: () => registerInitCommand
|
|
78067
78902
|
});
|
|
78068
|
-
import { resolve as
|
|
78903
|
+
import { resolve as resolve15 } from "node:path";
|
|
78069
78904
|
import { readFileSync as readFileSync24, existsSync as existsSync32, cpSync as cpSync4 } from "node:fs";
|
|
78070
78905
|
import { homedir as homedir19 } from "node:os";
|
|
78071
78906
|
function registerInitCommand(program2) {
|
|
78072
|
-
program2.command("init").description("Setup wizard: configure LLM provider, API keys, and server settings").option("--force", "Overwrite existing configuration").option("--non-interactive", "Run without prompts (use env vars or --import-from)").option("--provider <name>", "LLM provider (anthropic/openai/google/minimax/siliconflow/zai/ollama)").option("--api-key <key>", "LLM API key").option("--port <port>", "API server port", "8056").option("--import-from <platform>", "Import LLM config from an installed agent platform (e.g. openclaw, hermes)").option("--auto-connect", "Auto-connect detected agent platforms after init").action(async (opts) => {
|
|
78907
|
+
program2.command("init").description("Setup wizard: configure LLM provider, API keys, and server settings").option("--force", "Overwrite existing configuration").option("--non-interactive", "Run without prompts (use env vars or --import-from)").option("--provider <name>", "LLM provider (anthropic/openai/google/minimax/siliconflow/zai/deepseek/ollama)").option("--api-key <key>", "LLM API key").option("--port <port>", "API server port", "8056").option("--import-from <platform>", "Import LLM config from an installed agent platform (e.g. openclaw, hermes)").option("--auto-connect", "Auto-connect detected agent platforms after init").action(async (opts) => {
|
|
78073
78908
|
await quickInit({
|
|
78074
78909
|
force: opts.force,
|
|
78075
78910
|
nonInteractive: opts.nonInteractive,
|
|
@@ -78082,7 +78917,7 @@ function registerInitCommand(program2) {
|
|
|
78082
78917
|
});
|
|
78083
78918
|
}
|
|
78084
78919
|
async function quickInit(options) {
|
|
78085
|
-
const { writeFileSync:
|
|
78920
|
+
const { writeFileSync: writeFileSync21, mkdirSync: mkdirSync26 } = await import("node:fs");
|
|
78086
78921
|
const { join: pathJoin } = await import("node:path");
|
|
78087
78922
|
const readline4 = await import("node:readline");
|
|
78088
78923
|
const nonInteractive = options?.nonInteractive ?? false;
|
|
@@ -78126,7 +78961,8 @@ async function quickInit(options) {
|
|
|
78126
78961
|
siliconflow: "Qwen/Qwen3.5-35B-A3B",
|
|
78127
78962
|
ollama: "llama3",
|
|
78128
78963
|
openrouter: "xiaomi/mimo-v2-pro",
|
|
78129
|
-
zai: "glm-5.1"
|
|
78964
|
+
zai: "glm-5.1",
|
|
78965
|
+
deepseek: "deepseek-v4-flash"
|
|
78130
78966
|
};
|
|
78131
78967
|
const ENV_KEY_MAP = [
|
|
78132
78968
|
{ provider: "anthropic", label: "Anthropic", envKey: "ANTHROPIC_API_KEY" },
|
|
@@ -78135,7 +78971,8 @@ async function quickInit(options) {
|
|
|
78135
78971
|
{ provider: "siliconflow", label: "SiliconFlow", envKey: "SILICONFLOW_API_KEY", baseUrl: "https://api.siliconflow.cn/v1" },
|
|
78136
78972
|
{ provider: "minimax", label: "MiniMax", envKey: "MINIMAX_API_KEY", baseUrl: "https://api.minimax.io/v1" },
|
|
78137
78973
|
{ provider: "openrouter", label: "OpenRouter", envKey: "OPENROUTER_API_KEY", baseUrl: "https://openrouter.ai/api/v1" },
|
|
78138
|
-
{ provider: "zai", label: "ZAI", envKey: "ZAI_API_KEY", baseUrl: "https://api.z.ai/api/paas/v4" }
|
|
78974
|
+
{ provider: "zai", label: "ZAI", envKey: "ZAI_API_KEY", baseUrl: "https://api.z.ai/api/paas/v4" },
|
|
78975
|
+
{ provider: "deepseek", label: "DeepSeek", envKey: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com" }
|
|
78139
78976
|
];
|
|
78140
78977
|
console.log(" [1/3] LLM Provider Configuration\n");
|
|
78141
78978
|
const envProviders = [];
|
|
@@ -78294,7 +79131,8 @@ async function quickInit(options) {
|
|
|
78294
79131
|
const baseUrlMap = {
|
|
78295
79132
|
minimax: "https://api.minimax.io/v1",
|
|
78296
79133
|
siliconflow: "https://api.siliconflow.cn/v1",
|
|
78297
|
-
zai: "https://api.z.ai/api/paas/v4"
|
|
79134
|
+
zai: "https://api.z.ai/api/paas/v4",
|
|
79135
|
+
deepseek: "https://api.deepseek.com"
|
|
78298
79136
|
};
|
|
78299
79137
|
providers[provider] = {
|
|
78300
79138
|
...apiKey ? { apiKey } : {},
|
|
@@ -78307,7 +79145,7 @@ async function quickInit(options) {
|
|
|
78307
79145
|
console.log(" Warning: No API key provided. Configure manually in ~/.markus/markus.json");
|
|
78308
79146
|
}
|
|
78309
79147
|
} else {
|
|
78310
|
-
const provider = await ask(" LLM provider (anthropic/openai/google/minimax/siliconflow/zai/ollama)", "anthropic");
|
|
79148
|
+
const provider = await ask(" LLM provider (anthropic/openai/google/minimax/siliconflow/zai/deepseek/ollama)", "anthropic");
|
|
78311
79149
|
defaultProvider = provider;
|
|
78312
79150
|
let apiKey = "";
|
|
78313
79151
|
if (provider !== "ollama") {
|
|
@@ -78317,7 +79155,8 @@ async function quickInit(options) {
|
|
|
78317
79155
|
const baseUrlMap = {
|
|
78318
79156
|
minimax: "https://api.minimax.io/v1",
|
|
78319
79157
|
siliconflow: "https://api.siliconflow.cn/v1",
|
|
78320
|
-
zai: "https://api.z.ai/api/paas/v4"
|
|
79158
|
+
zai: "https://api.z.ai/api/paas/v4",
|
|
79159
|
+
deepseek: "https://api.deepseek.com"
|
|
78321
79160
|
};
|
|
78322
79161
|
providers[provider] = {
|
|
78323
79162
|
...apiKey ? { apiKey } : {},
|
|
@@ -78353,7 +79192,7 @@ async function quickInit(options) {
|
|
|
78353
79192
|
const userTemplatesDir = pathJoin(homedir19(), ".markus", "templates");
|
|
78354
79193
|
const builtinTemplatesDir = resolveTemplatesDir("roles");
|
|
78355
79194
|
if (builtinTemplatesDir && existsSync32(builtinTemplatesDir) && !existsSync32(userTemplatesDir)) {
|
|
78356
|
-
const builtinRoot =
|
|
79195
|
+
const builtinRoot = resolve15(builtinTemplatesDir, "..");
|
|
78357
79196
|
mkdirSync26(userTemplatesDir, { recursive: true });
|
|
78358
79197
|
cpSync4(builtinRoot, userTemplatesDir, { recursive: true });
|
|
78359
79198
|
console.log(` Copied templates to ${userTemplatesDir}`);
|
|
@@ -78361,7 +79200,7 @@ async function quickInit(options) {
|
|
|
78361
79200
|
const devRoleDir = pathJoin(userTemplatesDir || pathJoin(process.cwd(), "templates"), "roles", "developer");
|
|
78362
79201
|
if (!existsSync32(devRoleDir)) {
|
|
78363
79202
|
mkdirSync26(devRoleDir, { recursive: true });
|
|
78364
|
-
|
|
79203
|
+
writeFileSync21(
|
|
78365
79204
|
pathJoin(devRoleDir, "ROLE.md"),
|
|
78366
79205
|
[
|
|
78367
79206
|
"---",
|
|
@@ -78421,7 +79260,7 @@ var start_exports = {};
|
|
|
78421
79260
|
__export(start_exports, {
|
|
78422
79261
|
registerStartCommand: () => registerStartCommand
|
|
78423
79262
|
});
|
|
78424
|
-
import { resolve as
|
|
79263
|
+
import { resolve as resolve16, join as join29, dirname as dirname9 } from "node:path";
|
|
78425
79264
|
import { existsSync as existsSync33 } from "node:fs";
|
|
78426
79265
|
import { homedir as homedir20 } from "node:os";
|
|
78427
79266
|
function registerStartCommand(program2) {
|
|
@@ -78516,6 +79355,19 @@ async function createServices(config) {
|
|
|
78516
79355
|
defaultProvider = "zai";
|
|
78517
79356
|
}
|
|
78518
79357
|
}
|
|
79358
|
+
const deepseekKey = config.llm.providers["deepseek"]?.apiKey ?? process.env["DEEPSEEK_API_KEY"];
|
|
79359
|
+
if (deepseekKey) {
|
|
79360
|
+
providerConfigs["deepseek"] = {
|
|
79361
|
+
provider: "deepseek",
|
|
79362
|
+
model: config.llm.providers["deepseek"]?.model ?? process.env["DEEPSEEK_MODEL"] ?? "deepseek-v4-flash",
|
|
79363
|
+
apiKey: deepseekKey,
|
|
79364
|
+
baseUrl: config.llm.providers["deepseek"]?.baseUrl ?? process.env["DEEPSEEK_BASE_URL"] ?? "https://api.deepseek.com",
|
|
79365
|
+
timeoutMs: llmTimeoutMs
|
|
79366
|
+
};
|
|
79367
|
+
if (config.llm.defaultProvider === "deepseek") {
|
|
79368
|
+
defaultProvider = "deepseek";
|
|
79369
|
+
}
|
|
79370
|
+
}
|
|
78519
79371
|
if (!providerConfigs[defaultProvider]) {
|
|
78520
79372
|
const available = Object.keys(providerConfigs);
|
|
78521
79373
|
if (available.length > 0) {
|
|
@@ -78659,7 +79511,7 @@ async function startServer(config, values) {
|
|
|
78659
79511
|
startupLog("INFO", "\u6B63\u5728\u542F\u52A8\u670D\u52A1...");
|
|
78660
79512
|
const currentPath = process.env["PATH"] ?? "";
|
|
78661
79513
|
const extraPaths = [];
|
|
78662
|
-
const selfBinDir = dirname9(
|
|
79514
|
+
const selfBinDir = dirname9(resolve16(process.argv[1] ?? ""));
|
|
78663
79515
|
if (selfBinDir && !currentPath.includes(selfBinDir)) extraPaths.push(selfBinDir);
|
|
78664
79516
|
const cwdBin = join29(process.cwd(), "node_modules", ".bin");
|
|
78665
79517
|
if (existsSync33(cwdBin) && !currentPath.includes(cwdBin)) extraPaths.push(cwdBin);
|
|
@@ -78801,7 +79653,7 @@ async function startServer(config, values) {
|
|
|
78801
79653
|
});
|
|
78802
79654
|
agentManager.setUserNotifier((opts) => {
|
|
78803
79655
|
hitlService.notify({
|
|
78804
|
-
targetUserId: "
|
|
79656
|
+
targetUserId: "all",
|
|
78805
79657
|
type: opts.type,
|
|
78806
79658
|
title: opts.title,
|
|
78807
79659
|
body: opts.body,
|
|
@@ -78868,7 +79720,7 @@ ${body}`;
|
|
|
78868
79720
|
});
|
|
78869
79721
|
const hasTask = !!taskId2;
|
|
78870
79722
|
hitlService.notify({
|
|
78871
|
-
targetUserId: "
|
|
79723
|
+
targetUserId: "all",
|
|
78872
79724
|
type: "agent_report",
|
|
78873
79725
|
title,
|
|
78874
79726
|
body,
|
|
@@ -78902,7 +79754,7 @@ ${reason}`;
|
|
|
78902
79754
|
isMainSession: true
|
|
78903
79755
|
});
|
|
78904
79756
|
hitlService.notify({
|
|
78905
|
-
targetUserId: "
|
|
79757
|
+
targetUserId: "all",
|
|
78906
79758
|
type: "system",
|
|
78907
79759
|
title: "Agent needs help",
|
|
78908
79760
|
body: reason,
|
|
@@ -79269,6 +80121,19 @@ ${reason}`;
|
|
|
79269
80121
|
}, triageProvider);
|
|
79270
80122
|
return response.content;
|
|
79271
80123
|
});
|
|
80124
|
+
agent.getAttentionController().setLLMJudge(async (prompt) => {
|
|
80125
|
+
const response = await llmRouter.chat({
|
|
80126
|
+
messages: [
|
|
80127
|
+
{ role: "system", content: 'You are an attention interrupt judge. Decide whether to interrupt current work for a new incoming message. Reply with ONLY one word: continue, preempt, cancel, merge, or defer. Use "preempt" to pause (resume later) and "cancel" to permanently stop current work.' },
|
|
80128
|
+
{ role: "user", content: prompt }
|
|
80129
|
+
],
|
|
80130
|
+
temperature: 0.1,
|
|
80131
|
+
maxTokens: 32
|
|
80132
|
+
}, triageProvider);
|
|
80133
|
+
const raw = response.content.trim().toLowerCase();
|
|
80134
|
+
const valid = ["continue", "preempt", "cancel", "merge", "defer"];
|
|
80135
|
+
return valid.includes(raw) ? raw : "continue";
|
|
80136
|
+
});
|
|
79272
80137
|
agent.getAttentionController().setTriageChatFn(async (messages, tools) => {
|
|
79273
80138
|
const llmTools = tools?.map((t) => ({
|
|
79274
80139
|
name: t.name,
|
|
@@ -79281,7 +80146,7 @@ ${reason}`;
|
|
|
79281
80146
|
temperature: TRIAGE_TEMPERATURE,
|
|
79282
80147
|
maxTokens: TRIAGE_MAX_TOKENS
|
|
79283
80148
|
}, triageProvider);
|
|
79284
|
-
return { content: response.content, toolCalls: response.toolCalls };
|
|
80149
|
+
return { content: response.content, toolCalls: response.toolCalls, reasoningContent: response.reasoningContent };
|
|
79285
80150
|
});
|
|
79286
80151
|
const triageToolMap = /* @__PURE__ */ new Map();
|
|
79287
80152
|
const agentTools = agent.getTools();
|
|
@@ -79996,9 +80861,9 @@ var init_model = __esm({
|
|
|
79996
80861
|
id: "deepseek",
|
|
79997
80862
|
label: "DeepSeek",
|
|
79998
80863
|
envKey: "DEEPSEEK_API_KEY",
|
|
79999
|
-
baseUrl: "https://api.deepseek.com
|
|
80000
|
-
defaultModel: "deepseek-
|
|
80001
|
-
models: ["deepseek-
|
|
80864
|
+
baseUrl: "https://api.deepseek.com",
|
|
80865
|
+
defaultModel: "deepseek-v4-flash",
|
|
80866
|
+
models: ["deepseek-v4-flash", "deepseek-v4-pro", "deepseek-chat", "deepseek-reasoner"]
|
|
80002
80867
|
}
|
|
80003
80868
|
];
|
|
80004
80869
|
C = {
|
|
@@ -80295,6 +81160,12 @@ ${C3.BOLD}${C3.CYAN}\u2554\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
|
|
|
80295
81160
|
checkWarn("Skills directory not found", `${skillsDir} \u2014 run: markus skill install <name>`);
|
|
80296
81161
|
}
|
|
80297
81162
|
section("Network");
|
|
81163
|
+
const proxyUrl = process.env["HTTPS_PROXY"] || process.env["HTTP_PROXY"] || process.env["https_proxy"] || process.env["http_proxy"];
|
|
81164
|
+
if (proxyUrl) {
|
|
81165
|
+
checkOk("HTTP proxy configured", proxyUrl);
|
|
81166
|
+
} else {
|
|
81167
|
+
checkWarn("HTTP proxy", "not configured \u2014 if behind firewall, set HTTPS_PROXY env var");
|
|
81168
|
+
}
|
|
80298
81169
|
try {
|
|
80299
81170
|
const res = await fetch("https://api.anthropic.com/.well-known/ready", {
|
|
80300
81171
|
method: "HEAD",
|
|
@@ -80387,7 +81258,7 @@ var init_doctor = __esm({
|
|
|
80387
81258
|
{ id: "siliconflow", label: "SiliconFlow", envKey: "SILICONFLOW_API_KEY", baseUrl: "https://api.siliconflow.cn/v1", defaultModel: "Qwen/Qwen3.5-35B-A3B" },
|
|
80388
81259
|
{ id: "openrouter", label: "OpenRouter", envKey: "OPENROUTER_API_KEY", baseUrl: "https://openrouter.ai/api/v1", defaultModel: "xiaomi/mimo-v2-pro:free" },
|
|
80389
81260
|
{ id: "zai", label: "ZAI", envKey: "ZAI_API_KEY", baseUrl: "https://api.z.ai/api/paas/v4", defaultModel: "glm-5.1" },
|
|
80390
|
-
{ id: "deepseek", label: "DeepSeek", envKey: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com
|
|
81261
|
+
{ id: "deepseek", label: "DeepSeek", envKey: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com", defaultModel: "deepseek-v4-flash" }
|
|
80391
81262
|
];
|
|
80392
81263
|
}
|
|
80393
81264
|
});
|
|
@@ -80775,7 +81646,7 @@ var init_auth = __esm({
|
|
|
80775
81646
|
{ id: "siliconflow", label: "SiliconFlow", envKey: "SILICONFLOW_API_KEY", baseUrl: "https://api.siliconflow.cn/v1", defaultModel: "Qwen/Qwen3.5-35B-A3B" },
|
|
80776
81647
|
{ id: "openrouter", label: "OpenRouter", envKey: "OPENROUTER_API_KEY", baseUrl: "https://openrouter.ai/api/v1", defaultModel: "xiaomi/mimo-v2-pro:free" },
|
|
80777
81648
|
{ id: "zai", label: "ZAI", envKey: "ZAI_API_KEY", baseUrl: "https://api.z.ai/api/paas/v4", defaultModel: "glm-5.1" },
|
|
80778
|
-
{ id: "deepseek", label: "DeepSeek", envKey: "DEEPSEEK_API_KEY", defaultModel: "deepseek-
|
|
81649
|
+
{ id: "deepseek", label: "DeepSeek", envKey: "DEEPSEEK_API_KEY", baseUrl: "https://api.deepseek.com", defaultModel: "deepseek-v4-flash" }
|
|
80779
81650
|
];
|
|
80780
81651
|
PLACEHOLDER_PATTERNS3 = ["***", "your-", "dummy", "fake", "test-key", "replace-me"];
|
|
80781
81652
|
}
|
|
@@ -82976,8 +83847,8 @@ var skill_exports = {};
|
|
|
82976
83847
|
__export(skill_exports, {
|
|
82977
83848
|
registerSkillCommands: () => registerSkillCommands
|
|
82978
83849
|
});
|
|
82979
|
-
import { writeFileSync as
|
|
82980
|
-
import { resolve as
|
|
83850
|
+
import { writeFileSync as writeFileSync20, mkdirSync as mkdirSync25 } from "node:fs";
|
|
83851
|
+
import { resolve as resolve17 } from "node:path";
|
|
82981
83852
|
function registerSkillCommands(program2) {
|
|
82982
83853
|
const root = program2.command("skill").description("Skills registry and local scaffold");
|
|
82983
83854
|
root.command("list").action(async (_opts, cmd) => {
|
|
@@ -83065,7 +83936,7 @@ function registerSkillCommands(program2) {
|
|
|
83065
83936
|
const g = cmd.optsWithGlobals();
|
|
83066
83937
|
const out = { json: !!g.json };
|
|
83067
83938
|
if (!opts.dir && !opts.name) fail("Specify --dir or --name");
|
|
83068
|
-
const dir =
|
|
83939
|
+
const dir = resolve17(process.cwd(), opts.dir ?? opts.name);
|
|
83069
83940
|
mkdirSync25(dir, { recursive: true });
|
|
83070
83941
|
const skillName = opts.name ?? (opts.dir ? opts.dir.replace(/.*[/\\]/, "") : "my-skill");
|
|
83071
83942
|
const skillJson = {
|
|
@@ -83084,8 +83955,8 @@ Describe what this skill does for agents.
|
|
|
83084
83955
|
## Tools / behavior
|
|
83085
83956
|
|
|
83086
83957
|
`;
|
|
83087
|
-
|
|
83088
|
-
|
|
83958
|
+
writeFileSync20(resolve17(dir, "skill.json"), JSON.stringify(skillJson, null, 2) + "\n");
|
|
83959
|
+
writeFileSync20(resolve17(dir, "SKILL.md"), skillMd);
|
|
83089
83960
|
if (out.json) {
|
|
83090
83961
|
console.log(JSON.stringify({ dir, files: ["skill.json", "SKILL.md"] }, null, 2));
|
|
83091
83962
|
} else {
|
|
@@ -83109,12 +83980,12 @@ __export(system_exports, {
|
|
|
83109
83980
|
});
|
|
83110
83981
|
import { execSync as execSync6 } from "node:child_process";
|
|
83111
83982
|
import { existsSync as existsSync34, readFileSync as readFileSync25 } from "node:fs";
|
|
83112
|
-
import { resolve as
|
|
83983
|
+
import { resolve as resolve18, dirname as dirname10 } from "node:path";
|
|
83113
83984
|
import { fileURLToPath as fileURLToPath5 } from "node:url";
|
|
83114
83985
|
function findMarkusRoot() {
|
|
83115
83986
|
let dir = dirname10(fileURLToPath5(import.meta.url));
|
|
83116
83987
|
for (let i = 0; i < 10; i++) {
|
|
83117
|
-
if (existsSync34(
|
|
83988
|
+
if (existsSync34(resolve18(dir, "package.json")) && existsSync34(resolve18(dir, "packages"))) return dir;
|
|
83118
83989
|
dir = dirname10(dir);
|
|
83119
83990
|
}
|
|
83120
83991
|
return null;
|
|
@@ -83255,13 +84126,13 @@ function registerSystemCommands(program2) {
|
|
|
83255
84126
|
if (markusRoot) {
|
|
83256
84127
|
if (!info4.currentVersion) {
|
|
83257
84128
|
try {
|
|
83258
|
-
const pkg = JSON.parse(readFileSync25(
|
|
84129
|
+
const pkg = JSON.parse(readFileSync25(resolve18(markusRoot, "package.json"), "utf-8"));
|
|
83259
84130
|
info4.currentVersion = pkg.version;
|
|
83260
84131
|
} catch {
|
|
83261
84132
|
}
|
|
83262
84133
|
}
|
|
83263
84134
|
try {
|
|
83264
|
-
const isGit = existsSync34(
|
|
84135
|
+
const isGit = existsSync34(resolve18(markusRoot, ".git"));
|
|
83265
84136
|
if (isGit) {
|
|
83266
84137
|
info4.gitBranch = execSync6("git rev-parse --abbrev-ref HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
83267
84138
|
info4.gitCommit = execSync6("git rev-parse --short HEAD", { cwd: markusRoot, encoding: "utf-8" }).trim();
|
|
@@ -83300,7 +84171,7 @@ function registerSystemCommands(program2) {
|
|
|
83300
84171
|
fail("Cannot locate Markus installation directory");
|
|
83301
84172
|
return;
|
|
83302
84173
|
}
|
|
83303
|
-
if (!existsSync34(
|
|
84174
|
+
if (!existsSync34(resolve18(markusRoot, ".git"))) {
|
|
83304
84175
|
fail("Markus installation is not a git repository. Update manually.");
|
|
83305
84176
|
return;
|
|
83306
84177
|
}
|
|
@@ -83865,7 +84736,7 @@ var init_settings2 = __esm({
|
|
|
83865
84736
|
});
|
|
83866
84737
|
|
|
83867
84738
|
// src/index.ts
|
|
83868
|
-
import { resolve as
|
|
84739
|
+
import { resolve as resolve19 } from "node:path";
|
|
83869
84740
|
import { readFileSync as readFileSync26, existsSync as existsSync35 } from "node:fs";
|
|
83870
84741
|
import process2 from "node:process";
|
|
83871
84742
|
|
|
@@ -83889,7 +84760,7 @@ var {
|
|
|
83889
84760
|
// src/index.ts
|
|
83890
84761
|
init_dist();
|
|
83891
84762
|
init_output();
|
|
83892
|
-
var envPath =
|
|
84763
|
+
var envPath = resolve19(process2.cwd(), ".env");
|
|
83893
84764
|
if (existsSync35(envPath)) {
|
|
83894
84765
|
for (const line of readFileSync26(envPath, "utf-8").split("\n")) {
|
|
83895
84766
|
const trimmed = line.trim();
|