neuralos 3.2.2 → 3.2.5
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/bin/gybackend.cjs +220 -3
- package/package.json +2 -2
package/bin/gybackend.cjs
CHANGED
|
@@ -296885,6 +296885,13 @@ ${res.stderr}` : "")
|
|
|
296885
296885
|
task2.endTime = Date.now();
|
|
296886
296886
|
task2.exitCode = options?.exitCode;
|
|
296887
296887
|
task2.endOffset = task2.startOffset + task2.output.length;
|
|
296888
|
+
if (task2.capturedOutput !== void 0 && task2.capturedOutput.length < (task2.output || "").length) {
|
|
296889
|
+
task2.captureStatus = "partial";
|
|
296890
|
+
} else if ((task2.output || "").length > MAX_BUFFER_SIZE) {
|
|
296891
|
+
task2.captureStatus = "display-truncated";
|
|
296892
|
+
} else {
|
|
296893
|
+
task2.captureStatus = "complete";
|
|
296894
|
+
}
|
|
296888
296895
|
this.stopCommandTrackingWatcher(taskId);
|
|
296889
296896
|
this.activeTaskByTerminal.delete(terminalId);
|
|
296890
296897
|
this.pendingTaskFinishByTerminal.delete(terminalId);
|
|
@@ -296899,7 +296906,8 @@ ${res.stderr}` : "")
|
|
|
296899
296906
|
callback({
|
|
296900
296907
|
stdoutDelta: task2.output,
|
|
296901
296908
|
exitCode: options?.exitCode,
|
|
296902
|
-
history_command_match_id: taskId
|
|
296909
|
+
history_command_match_id: taskId,
|
|
296910
|
+
captureStatus: task2.captureStatus
|
|
296903
296911
|
});
|
|
296904
296912
|
}
|
|
296905
296913
|
}
|
|
@@ -349593,10 +349601,11 @@ async function runCommand(args, context2, options) {
|
|
|
349593
349601
|
});
|
|
349594
349602
|
finalResult = `The command has been running for over 120s and has been switched to nowait mode (running in the background). You can use read_command_output to check its progress. history_command_match_id=${historyCommandMatchId}, terminalId=${bestMatch.id}`;
|
|
349595
349603
|
} else {
|
|
349604
|
+
const captureNote = result.captureStatus === "partial" ? "\n[Note: Some output may have been lost during capture. Use read_command_output to retrieve the full output if needed.]" : result.captureStatus === "display-truncated" ? "\n[Note: Output was truncated for display. Use read_command_output to retrieve the full output if needed.]" : "";
|
|
349596
349605
|
finalResult = `The command has finished executing. The following is the output (history_command_match_id=${historyCommandMatchId}):
|
|
349597
349606
|
<terminal_content>
|
|
349598
349607
|
${truncatedOutput}
|
|
349599
|
-
</terminal_content
|
|
349608
|
+
</terminal_content>${captureNote}`;
|
|
349600
349609
|
}
|
|
349601
349610
|
context2.sendEvent(sessionId, {
|
|
349602
349611
|
messageId,
|
|
@@ -367392,6 +367401,114 @@ var SINGLE_CALL_TOOL_BOUNDARY_NAMES = /* @__PURE__ */ new Set([
|
|
|
367392
367401
|
"manage_template",
|
|
367393
367402
|
"import_putty"
|
|
367394
367403
|
]);
|
|
367404
|
+
var PARALLEL_SAFE_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
367405
|
+
"read_file",
|
|
367406
|
+
"read_terminal_tab",
|
|
367407
|
+
"read_command_output",
|
|
367408
|
+
"list_session_logs",
|
|
367409
|
+
"read_session_log",
|
|
367410
|
+
"search_session_logs",
|
|
367411
|
+
"get_metrics",
|
|
367412
|
+
"get_live_dashboard",
|
|
367413
|
+
"get_monitor_status",
|
|
367414
|
+
"get_cloud_inventory",
|
|
367415
|
+
"get_apm_summary",
|
|
367416
|
+
"get_dem_summary",
|
|
367417
|
+
"get_cost",
|
|
367418
|
+
"get_run_ledger",
|
|
367419
|
+
"list_gateway_methods",
|
|
367420
|
+
"manage_secret",
|
|
367421
|
+
// read operations (list/has) are safe; set/delete are rare
|
|
367422
|
+
"manage_oncall",
|
|
367423
|
+
// open_pages is read-only
|
|
367424
|
+
"manage_gitops",
|
|
367425
|
+
// export/drift/inSync are read-only
|
|
367426
|
+
"manage_playbook_version",
|
|
367427
|
+
// lint/history/diff are read-only
|
|
367428
|
+
"collect_facts",
|
|
367429
|
+
"run_fleet_command",
|
|
367430
|
+
// runs on different terminals — parallel-safe
|
|
367431
|
+
"synapse_health",
|
|
367432
|
+
"synapse_discover",
|
|
367433
|
+
"synapse_agents_summary",
|
|
367434
|
+
"synapse_reputation",
|
|
367435
|
+
"synapse_serve_status",
|
|
367436
|
+
"numbat_health",
|
|
367437
|
+
"numbat_findings_summary",
|
|
367438
|
+
"agentspan_health",
|
|
367439
|
+
"agentspan_list",
|
|
367440
|
+
"agentspan_status",
|
|
367441
|
+
"webintel_health",
|
|
367442
|
+
"web_search",
|
|
367443
|
+
"web_fetch",
|
|
367444
|
+
"web_find_similar",
|
|
367445
|
+
"web_watch_list",
|
|
367446
|
+
"patch_status",
|
|
367447
|
+
"list_requests",
|
|
367448
|
+
"request_status",
|
|
367449
|
+
"sop_search",
|
|
367450
|
+
"sop_get",
|
|
367451
|
+
"iam_user_info",
|
|
367452
|
+
"iam_user_groups",
|
|
367453
|
+
"iam_access_review",
|
|
367454
|
+
"fraudops_pipeline_status",
|
|
367455
|
+
"fraudops_str_status",
|
|
367456
|
+
"fraudops_decision_summary",
|
|
367457
|
+
"netdata_alert_summary",
|
|
367458
|
+
"netdata_correlate"
|
|
367459
|
+
]);
|
|
367460
|
+
function canRunInParallel(toolCalls) {
|
|
367461
|
+
if (toolCalls.length <= 1) return false;
|
|
367462
|
+
for (const tc of toolCalls) {
|
|
367463
|
+
if (SINGLE_CALL_TOOL_BOUNDARY_NAMES.has(tc?.name)) return false;
|
|
367464
|
+
if (!PARALLEL_SAFE_TOOL_NAMES.has(tc?.name)) return false;
|
|
367465
|
+
}
|
|
367466
|
+
const terminalIds = /* @__PURE__ */ new Set();
|
|
367467
|
+
for (const tc of toolCalls) {
|
|
367468
|
+
const args = typeof tc?.args === "string" ? (() => {
|
|
367469
|
+
try {
|
|
367470
|
+
return JSON.parse(tc.args);
|
|
367471
|
+
} catch {
|
|
367472
|
+
return {};
|
|
367473
|
+
}
|
|
367474
|
+
})() : tc?.args || {};
|
|
367475
|
+
const tid = args.terminalId || args.target;
|
|
367476
|
+
if (tid) {
|
|
367477
|
+
if (terminalIds.has(tid)) return false;
|
|
367478
|
+
terminalIds.add(tid);
|
|
367479
|
+
}
|
|
367480
|
+
}
|
|
367481
|
+
return true;
|
|
367482
|
+
}
|
|
367483
|
+
function reconcileToolCalls(toolCalls) {
|
|
367484
|
+
if (!Array.isArray(toolCalls) || toolCalls.length === 0) return [];
|
|
367485
|
+
const seen = /* @__PURE__ */ new Set();
|
|
367486
|
+
const result = [];
|
|
367487
|
+
for (const tc of toolCalls) {
|
|
367488
|
+
if (!tc || typeof tc !== "object") continue;
|
|
367489
|
+
if (!tc.name || typeof tc.name !== "string") continue;
|
|
367490
|
+
let args = tc.args;
|
|
367491
|
+
if (args == null) {
|
|
367492
|
+
args = {};
|
|
367493
|
+
} else if (typeof args === "string") {
|
|
367494
|
+
try {
|
|
367495
|
+
args = JSON.parse(args);
|
|
367496
|
+
} catch {
|
|
367497
|
+
args = {};
|
|
367498
|
+
}
|
|
367499
|
+
}
|
|
367500
|
+
const id = tc.id || "";
|
|
367501
|
+
if (id) {
|
|
367502
|
+
if (seen.has(id)) continue;
|
|
367503
|
+
seen.add(id);
|
|
367504
|
+
}
|
|
367505
|
+
const dedupKey = `${tc.name}::${JSON.stringify(args)}`;
|
|
367506
|
+
if (seen.has(dedupKey)) continue;
|
|
367507
|
+
seen.add(dedupKey);
|
|
367508
|
+
result.push({ ...tc, args });
|
|
367509
|
+
}
|
|
367510
|
+
return result;
|
|
367511
|
+
}
|
|
367395
367512
|
function clipTextMiddle(input, maxChars) {
|
|
367396
367513
|
if (maxChars <= 0) return "";
|
|
367397
367514
|
if (input.length <= maxChars) return input;
|
|
@@ -368358,7 +368475,9 @@ var AgentService_v2 = class {
|
|
|
368358
368475
|
if (!AIMessage.isInstance(lastMessage)) {
|
|
368359
368476
|
return { messages, sessionId, pendingToolCalls };
|
|
368360
368477
|
}
|
|
368361
|
-
const toolCalls =
|
|
368478
|
+
const toolCalls = reconcileToolCalls(
|
|
368479
|
+
Array.isArray(lastMessage.tool_calls) ? lastMessage.tool_calls : []
|
|
368480
|
+
);
|
|
368362
368481
|
if (!toolCalls || toolCalls.length === 0) {
|
|
368363
368482
|
this.cleanupModelToolCallMetadata(lastMessage, []);
|
|
368364
368483
|
return { messages, sessionId, pendingToolCalls };
|
|
@@ -368393,6 +368512,31 @@ var AgentService_v2 = class {
|
|
|
368393
368512
|
if (!sessionId) throw new Error("No session ID in state");
|
|
368394
368513
|
const sessionBinding = this.getSessionModelBinding(sessionId);
|
|
368395
368514
|
const queue2 = Array.isArray(state.pendingToolCalls) ? state.pendingToolCalls : [];
|
|
368515
|
+
if (canRunInParallel(queue2)) {
|
|
368516
|
+
const parallelResults = await Promise.all(
|
|
368517
|
+
queue2.map(async (tc) => {
|
|
368518
|
+
const tm = this.createToolMessage(tc);
|
|
368519
|
+
const ec = this.createExecutionContext(
|
|
368520
|
+
sessionId,
|
|
368521
|
+
tm.additional_kwargs._gyshellMessageId,
|
|
368522
|
+
config2
|
|
368523
|
+
);
|
|
368524
|
+
let res = "";
|
|
368525
|
+
try {
|
|
368526
|
+
res = await this.executeToolByName(tc, ec);
|
|
368527
|
+
} catch (err) {
|
|
368528
|
+
res = `Parallel execution error for ${tc.name}: ${err.message}`;
|
|
368529
|
+
}
|
|
368530
|
+
tm.content = res;
|
|
368531
|
+
return tm;
|
|
368532
|
+
})
|
|
368533
|
+
);
|
|
368534
|
+
return {
|
|
368535
|
+
messages: [...state.messages, ...parallelResults],
|
|
368536
|
+
sessionId,
|
|
368537
|
+
pendingToolCalls: []
|
|
368538
|
+
};
|
|
368539
|
+
}
|
|
368396
368540
|
const toolCall = queue2[0];
|
|
368397
368541
|
if (!toolCall) return state;
|
|
368398
368542
|
const toolMessage = this.createToolMessage(toolCall);
|
|
@@ -369245,6 +369389,71 @@ Actually, your intention might be different. Please re-read the description of t
|
|
|
369245
369389
|
};
|
|
369246
369390
|
});
|
|
369247
369391
|
}
|
|
369392
|
+
/** v3.2.4: Execute a single tool by name (used by the parallel execution path).
|
|
369393
|
+
* This is a simplified dispatch that handles the common read-only/parallel-safe tools.
|
|
369394
|
+
* Tools not handled here fall back to the sequential switch/case path. */
|
|
369395
|
+
async executeToolByName(toolCall, executionContext) {
|
|
369396
|
+
const name = toolCall.name;
|
|
369397
|
+
const args = typeof toolCall.args === "string" ? (() => {
|
|
369398
|
+
try {
|
|
369399
|
+
return JSON.parse(toolCall.args);
|
|
369400
|
+
} catch {
|
|
369401
|
+
return {};
|
|
369402
|
+
}
|
|
369403
|
+
})() : toolCall.args || {};
|
|
369404
|
+
const ti = toolImplementations;
|
|
369405
|
+
switch (name) {
|
|
369406
|
+
case "read_terminal_tab":
|
|
369407
|
+
return ti.readTerminalTab(args, executionContext);
|
|
369408
|
+
case "read_command_output":
|
|
369409
|
+
return ti.readCommandOutput(args, executionContext);
|
|
369410
|
+
case "list_session_logs":
|
|
369411
|
+
return ti.listSessionLogs(args, executionContext);
|
|
369412
|
+
case "read_session_log":
|
|
369413
|
+
return ti.readSessionLog(args, executionContext);
|
|
369414
|
+
case "search_session_logs":
|
|
369415
|
+
return ti.searchSessionLogs(args, executionContext);
|
|
369416
|
+
case "get_metrics":
|
|
369417
|
+
return ti.getMetrics(args, executionContext);
|
|
369418
|
+
case "get_live_dashboard":
|
|
369419
|
+
return ti.getLiveDashboard(args, executionContext);
|
|
369420
|
+
case "get_monitor_status":
|
|
369421
|
+
return ti.getMonitorStatus(args, executionContext);
|
|
369422
|
+
case "get_cloud_inventory":
|
|
369423
|
+
return ti.getCloudInventory(args, executionContext);
|
|
369424
|
+
case "get_apm_summary":
|
|
369425
|
+
return ti.getApmSummary(args, executionContext);
|
|
369426
|
+
case "get_dem_summary":
|
|
369427
|
+
return ti.getDemSummary(args, executionContext);
|
|
369428
|
+
case "get_cost":
|
|
369429
|
+
return ti.getCost(args, executionContext);
|
|
369430
|
+
case "get_run_ledger":
|
|
369431
|
+
return ti.getRunLedger(args, executionContext);
|
|
369432
|
+
case "list_gateway_methods":
|
|
369433
|
+
return ti.listGatewayMethods(args, executionContext);
|
|
369434
|
+
case "collect_facts":
|
|
369435
|
+
return ti.collectFacts(args, executionContext);
|
|
369436
|
+
case "run_fleet_command":
|
|
369437
|
+
return ti.runFleetCommand(args, executionContext);
|
|
369438
|
+
case "manage_secret":
|
|
369439
|
+
return ti.manageSecret(args, executionContext);
|
|
369440
|
+
case "manage_oncall":
|
|
369441
|
+
return ti.manageOncall(args, executionContext);
|
|
369442
|
+
case "manage_gitops":
|
|
369443
|
+
return ti.manageGitops(args, executionContext);
|
|
369444
|
+
case "manage_playbook_version":
|
|
369445
|
+
return ti.managePlaybookVersion(args, executionContext);
|
|
369446
|
+
// Plugin tools — delegate to the pluginTools map
|
|
369447
|
+
default: {
|
|
369448
|
+
const pluginHandler = this.pluginTools.get(name);
|
|
369449
|
+
if (pluginHandler) {
|
|
369450
|
+
const result = await pluginHandler(args);
|
|
369451
|
+
return typeof result === "string" ? result : JSON.stringify(result);
|
|
369452
|
+
}
|
|
369453
|
+
return `Tool "${name}" is not supported in parallel execution mode.`;
|
|
369454
|
+
}
|
|
369455
|
+
}
|
|
369456
|
+
}
|
|
369248
369457
|
createReadFileNode() {
|
|
369249
369458
|
return RunnableLambda.from(async (state, config2) => {
|
|
369250
369459
|
const sessionId = state.sessionId;
|
|
@@ -370593,12 +370802,20 @@ ${reminder}`;
|
|
|
370593
370802
|
lastCheckpointOffset: 0,
|
|
370594
370803
|
lastProfileMaxTokens: this.getEffectiveMaxTokensForSession(sessionId)
|
|
370595
370804
|
};
|
|
370805
|
+
const previousFrontier = session.lastCheckpointOffset || 0;
|
|
370806
|
+
const newFrontier = messages.length;
|
|
370596
370807
|
this.updateSessionFromMessages(
|
|
370597
370808
|
session,
|
|
370598
370809
|
messages,
|
|
370599
370810
|
this.getEffectiveMaxTokensForSession(sessionId)
|
|
370600
370811
|
);
|
|
370812
|
+
session.lastCheckpointOffset = newFrontier;
|
|
370601
370813
|
this.chatHistoryService.saveSession(session);
|
|
370814
|
+
if (newFrontier !== previousFrontier) {
|
|
370815
|
+
console.log(
|
|
370816
|
+
`[AgentService_v2] Reading frontier updated: ${previousFrontier} -> ${newFrontier} messages (session ${sessionId}).`
|
|
370817
|
+
);
|
|
370818
|
+
}
|
|
370602
370819
|
} catch (error40) {
|
|
370603
370820
|
console.warn(
|
|
370604
370821
|
"[AgentService_v2] Failed to save session from checkpoint:",
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "neuralos",
|
|
3
|
-
"version": "3.2.
|
|
4
|
-
"description": "Headless AI-native backend for RTerm / neuralOS — v3.2.
|
|
3
|
+
"version": "3.2.5",
|
|
4
|
+
"description": "Headless AI-native backend for RTerm / neuralOS — v3.2.5: captureStatus (complete/partial/truncated), reconcileToolCalls (streamed multi-tool validation), reading frontier for emergency recovery. 11 plugins, 55 plugin tools wired. Transports (SSH/serial/local), SQLite, and NATS libs install automatically.",
|
|
5
5
|
"main": "bin/gybackend.cjs",
|
|
6
6
|
"bin": { "gybackend": "bin/gybackend.cjs" },
|
|
7
7
|
"license": "MIT",
|