@opengoat/core 2026.2.17 → 2026.2.19
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/core/agents/application/agent.service.d.ts +10 -0
- package/dist/core/agents/application/agent.service.js +85 -38
- package/dist/core/agents/application/agent.service.js.map +1 -1
- package/dist/core/boards/application/board.service.d.ts +5 -1
- package/dist/core/boards/application/board.service.js +115 -29
- package/dist/core/boards/application/board.service.js.map +1 -1
- package/dist/core/boards/domain/board.d.ts +1 -2
- package/dist/core/opengoat/application/opengoat.service.d.ts +9 -2
- package/dist/core/opengoat/application/opengoat.service.helpers.d.ts +64 -0
- package/dist/core/opengoat/application/opengoat.service.helpers.js +188 -14
- package/dist/core/opengoat/application/opengoat.service.helpers.js.map +1 -1
- package/dist/core/opengoat/application/opengoat.service.js +282 -71
- package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
- package/dist/core/orchestration/application/orchestration.service.js +11 -2
- package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
- package/dist/core/providers/application/provider.service.d.ts +12 -0
- package/dist/core/providers/application/provider.service.js +286 -2
- package/dist/core/providers/application/provider.service.js.map +1 -1
- package/dist/core/providers/cli-provider.d.ts +1 -0
- package/dist/core/providers/cli-provider.js +11 -8
- package/dist/core/providers/cli-provider.js.map +1 -1
- package/dist/core/providers/openclaw-gateway-rpc.js +70 -17
- package/dist/core/providers/openclaw-gateway-rpc.js.map +1 -1
- package/dist/core/providers/provider-module.d.ts +4 -0
- package/dist/core/providers/provider-module.js +4 -0
- package/dist/core/providers/provider-module.js.map +1 -1
- package/dist/core/providers/providers/claude-code/index.js +4 -0
- package/dist/core/providers/providers/claude-code/index.js.map +1 -1
- package/dist/core/providers/providers/claude-code/provider.js +1 -0
- package/dist/core/providers/providers/claude-code/provider.js.map +1 -1
- package/dist/core/providers/providers/codex/index.js +4 -0
- package/dist/core/providers/providers/codex/index.js.map +1 -1
- package/dist/core/providers/providers/codex/provider.d.ts +1 -0
- package/dist/core/providers/providers/codex/provider.js +29 -0
- package/dist/core/providers/providers/codex/provider.js.map +1 -1
- package/dist/core/providers/providers/cursor/index.js +4 -0
- package/dist/core/providers/providers/cursor/index.js.map +1 -1
- package/dist/core/providers/providers/cursor/provider.js +2 -1
- package/dist/core/providers/providers/cursor/provider.js.map +1 -1
- package/dist/core/providers/providers/gemini-cli/index.js +4 -0
- package/dist/core/providers/providers/gemini-cli/index.js.map +1 -1
- package/dist/core/providers/providers/gemini-cli/provider.js +9 -1
- package/dist/core/providers/providers/gemini-cli/provider.js.map +1 -1
- package/dist/core/providers/providers/openclaw/index.js +4 -0
- package/dist/core/providers/providers/openclaw/index.js.map +1 -1
- package/dist/core/providers/providers/opencode/index.js +4 -0
- package/dist/core/providers/providers/opencode/index.js.map +1 -1
- package/dist/core/providers/providers/opencode/provider.d.ts +1 -0
- package/dist/core/providers/providers/opencode/provider.js +13 -0
- package/dist/core/providers/providers/opencode/provider.js.map +1 -1
- package/dist/core/providers/registry.js +26 -0
- package/dist/core/providers/registry.js.map +1 -1
- package/dist/core/providers/types.d.ts +1 -0
- package/dist/core/sessions/application/session.service.js +17 -0
- package/dist/core/sessions/application/session.service.js.map +1 -1
- package/dist/core/templates/assets/ceo/ROLE.md +1 -1
- package/dist/core/templates/assets/skills/og-board-manager/SKILL.md +3 -6
- package/dist/core/templates/default-templates.d.ts +1 -1
- package/dist/core/templates/default-templates.js +8 -2
- package/dist/core/templates/default-templates.js.map +1 -1
- package/package.json +1 -1
|
@@ -10,11 +10,12 @@ import { ProviderCommandNotFoundError, createDefaultProviderRegistry, } from "..
|
|
|
10
10
|
import { dirname, resolve as resolvePath } from "node:path";
|
|
11
11
|
import { SessionService, } from "../../sessions/index.js";
|
|
12
12
|
import { SkillService, } from "../../skills/index.js";
|
|
13
|
-
import { assertAgentExists, buildBlockedTaskMessage,
|
|
13
|
+
import { assertAgentExists, buildBlockedTaskMessage, buildDoingTaskMessage, buildInactiveAgentsMessage, buildNotificationSessionRef, buildPendingTaskMessage, buildReporteeStats, buildTopDownTaskDelegationMessage, buildTodoTaskMessage, collectAllReportees, containsAgentNotFoundMessage, containsAlreadyExistsMessage, extractManagedSkillsDir, extractOpenClawAgents, isSpawnPermissionOrMissing, pathIsWithin, pathMatches, prepareOpenClawCommandEnv, resolveInProgressTimeoutMinutes, resolveBottomUpTaskDelegationStrategy, resolveTopDownTaskDelegationStrategy, resolveMaxParallelFlows, toErrorMessage, } from "./opengoat.service.helpers.js";
|
|
14
14
|
const OPENCLAW_PROVIDER_ID = "openclaw";
|
|
15
15
|
const OPENCLAW_DEFAULT_AGENT_ID = "main";
|
|
16
16
|
const OPENCLAW_AGENT_SANDBOX_MODE = "off";
|
|
17
17
|
const OPENCLAW_AGENT_TOOLS_ALLOW_ALL_JSON = "[\"*\"]";
|
|
18
|
+
const OPENCLAW_AGENT_SKIP_BOOTSTRAP = true;
|
|
18
19
|
const OPENCLAW_OPENGOAT_PLUGIN_ID = "openclaw-plugin";
|
|
19
20
|
const OPENCLAW_OPENGOAT_PLUGIN_ROOT_ID = "opengoat-plugin";
|
|
20
21
|
const OPENCLAW_OPENGOAT_PLUGIN_LEGACY_PACK_ID = "openclaw-plugin-pack";
|
|
@@ -97,8 +98,10 @@ export class OpenGoatService {
|
|
|
97
98
|
agentManifestService: this.agentManifestService,
|
|
98
99
|
});
|
|
99
100
|
}
|
|
100
|
-
initialize() {
|
|
101
|
-
return this.initializeRuntimeDefaults(
|
|
101
|
+
initialize(options = {}) {
|
|
102
|
+
return this.initializeRuntimeDefaults({
|
|
103
|
+
syncRuntimeDefaults: options.syncRuntimeDefaults ?? true,
|
|
104
|
+
});
|
|
102
105
|
}
|
|
103
106
|
async hardReset() {
|
|
104
107
|
const paths = this.pathsProvider.getPaths();
|
|
@@ -203,23 +206,31 @@ export class OpenGoatService {
|
|
|
203
206
|
warnings.push(`OpenClaw role skill assignment sync for "ceo" failed: ${toErrorMessage(error)}`);
|
|
204
207
|
}
|
|
205
208
|
let openClawAgentEntriesById;
|
|
209
|
+
let openClawInventoryAvailable = false;
|
|
206
210
|
try {
|
|
207
211
|
openClawAgentEntriesById = new Map((await this.listOpenClawAgents(paths)).map((entry) => [entry.id, entry]));
|
|
212
|
+
openClawInventoryAvailable = true;
|
|
208
213
|
}
|
|
209
214
|
catch (error) {
|
|
210
215
|
warnings.push(`OpenClaw startup inventory check failed: ${toErrorMessage(error)}`);
|
|
211
216
|
}
|
|
212
217
|
try {
|
|
213
218
|
localAgents = await this.agentService.listAgents(paths);
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
219
|
+
if (!openClawInventoryAvailable) {
|
|
220
|
+
warnings.push("OpenClaw startup registration sync skipped because agent inventory is unavailable.");
|
|
221
|
+
ceoSynced = localAgents.some((agent) => agent.id === DEFAULT_AGENT_ID);
|
|
222
|
+
}
|
|
223
|
+
else {
|
|
224
|
+
for (const agent of localAgents) {
|
|
225
|
+
const sync = await this.syncOpenClawAgentRegistration(paths, {
|
|
226
|
+
descriptor: agent,
|
|
227
|
+
existingEntry: openClawAgentEntriesById?.get(agent.id),
|
|
228
|
+
});
|
|
229
|
+
warnings.push(...sync.warnings);
|
|
230
|
+
if (agent.id === DEFAULT_AGENT_ID) {
|
|
231
|
+
ceoSynced = sync.synced;
|
|
232
|
+
ceoSyncCode = sync.code;
|
|
233
|
+
}
|
|
223
234
|
}
|
|
224
235
|
}
|
|
225
236
|
}
|
|
@@ -306,24 +317,23 @@ export class OpenGoatService {
|
|
|
306
317
|
throw new Error(`OpenClaw agent location sync failed for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
307
318
|
}
|
|
308
319
|
await this.syncOpenClawAgentExecutionPolicies(paths, [created.agent.id]);
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (!created.alreadyExisted) {
|
|
320
|
+
if (!created.alreadyExisted) {
|
|
321
|
+
try {
|
|
322
|
+
const workspaceBootstrap = await this.agentService.ensureAgentWorkspaceBootstrap(paths, {
|
|
323
|
+
agentId: created.agent.id,
|
|
324
|
+
displayName: created.agent.displayName,
|
|
325
|
+
role: options.role?.trim() ?? "",
|
|
326
|
+
}, {
|
|
327
|
+
syncBootstrapMarkdown: false,
|
|
328
|
+
});
|
|
329
|
+
created.createdPaths.push(...workspaceBootstrap.createdPaths);
|
|
330
|
+
created.skippedPaths.push(...workspaceBootstrap.skippedPaths);
|
|
331
|
+
created.skippedPaths.push(...workspaceBootstrap.removedPaths);
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
324
334
|
await this.agentService.removeAgent(paths, created.agent.id);
|
|
335
|
+
throw new Error(`Failed to update workspace bootstrap for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
325
336
|
}
|
|
326
|
-
throw new Error(`Failed to update workspace bootstrap for "${created.agent.id}". ${toErrorMessage(error)}`);
|
|
327
337
|
}
|
|
328
338
|
return {
|
|
329
339
|
...created,
|
|
@@ -363,6 +373,10 @@ export class OpenGoatService {
|
|
|
363
373
|
};
|
|
364
374
|
}
|
|
365
375
|
async setAgentManager(rawAgentId, rawReportsTo) {
|
|
376
|
+
const managerAgentId = resolveCreateAgentManagerId(rawAgentId, rawReportsTo);
|
|
377
|
+
if (managerAgentId) {
|
|
378
|
+
await this.assertManagerSupportsReportees(managerAgentId);
|
|
379
|
+
}
|
|
366
380
|
const paths = this.pathsProvider.getPaths();
|
|
367
381
|
const updated = await this.agentService.setAgentManager(paths, rawAgentId, rawReportsTo);
|
|
368
382
|
await this.syncOpenClawRoleSkills(paths, updated.agentId);
|
|
@@ -538,6 +552,9 @@ export class OpenGoatService {
|
|
|
538
552
|
if (!provider) {
|
|
539
553
|
throw new Error(`Provider "${managerBinding.providerId}" is not available for manager "${managerAgentId}".`);
|
|
540
554
|
}
|
|
555
|
+
if (provider.id !== OPENCLAW_PROVIDER_ID) {
|
|
556
|
+
throw new Error(`Cannot assign "${managerAgentId}" as manager because only OpenClaw agents can be managers (found provider "${provider.displayName}").`);
|
|
557
|
+
}
|
|
541
558
|
if (!provider.capabilities.reportees) {
|
|
542
559
|
throw new Error(`Cannot assign "${managerAgentId}" as manager because provider "${provider.displayName}" does not support reportees.`);
|
|
543
560
|
}
|
|
@@ -546,18 +563,23 @@ export class OpenGoatService {
|
|
|
546
563
|
const paths = this.pathsProvider.getPaths();
|
|
547
564
|
const ranAt = this.resolveNowIso();
|
|
548
565
|
const manifests = await this.agentManifestService.listManifests(paths);
|
|
549
|
-
const
|
|
550
|
-
const
|
|
551
|
-
const
|
|
566
|
+
const inProgressMinutes = resolveInProgressTimeoutMinutes(options.inProgressMinutes);
|
|
567
|
+
const topDownStrategy = resolveTopDownTaskDelegationStrategy(options);
|
|
568
|
+
const bottomUpStrategy = resolveBottomUpTaskDelegationStrategy(options);
|
|
552
569
|
const maxParallelFlows = resolveMaxParallelFlows(options.maxParallelFlows);
|
|
553
|
-
const inactiveCandidates =
|
|
554
|
-
? await this.collectInactiveAgents(paths, manifests, inactiveMinutes, notificationTarget)
|
|
570
|
+
const inactiveCandidates = bottomUpStrategy.enabled
|
|
571
|
+
? await this.collectInactiveAgents(paths, manifests, bottomUpStrategy.inactiveMinutes, bottomUpStrategy.notificationTarget)
|
|
555
572
|
: [];
|
|
556
573
|
const tasks = await this.boardService.listTasks(paths, { limit: 10_000 });
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
574
|
+
const topDownDispatches = topDownStrategy.enabled
|
|
575
|
+
? await this.dispatchTopDownTaskDelegationAutomations(paths, tasks, manifests, topDownStrategy.openTasksThreshold, ranAt, maxParallelFlows)
|
|
576
|
+
: [];
|
|
577
|
+
const pendingTaskIds = new Set(await this.boardService.listPendingTaskIdsOlderThan(paths, bottomUpStrategy.inactiveMinutes));
|
|
578
|
+
const doingTaskIds = new Set(await this.boardService.listDoingTaskIdsOlderThan(paths, inProgressMinutes));
|
|
579
|
+
const taskStatusDispatch = await this.dispatchTaskStatusAutomations(paths, tasks, manifests, doingTaskIds, pendingTaskIds, inProgressMinutes, bottomUpStrategy.inactiveMinutes, ranAt, maxParallelFlows);
|
|
580
|
+
const inactiveDispatches = await this.dispatchInactiveAgentAutomations(paths, inactiveCandidates, bottomUpStrategy.inactiveMinutes, ranAt, maxParallelFlows);
|
|
560
581
|
const dispatches = [
|
|
582
|
+
...topDownDispatches,
|
|
561
583
|
...taskStatusDispatch.dispatches,
|
|
562
584
|
...inactiveDispatches,
|
|
563
585
|
];
|
|
@@ -566,6 +588,7 @@ export class OpenGoatService {
|
|
|
566
588
|
ranAt,
|
|
567
589
|
scannedTasks: tasks.length,
|
|
568
590
|
todoTasks: taskStatusDispatch.todoTasks,
|
|
591
|
+
doingTasks: taskStatusDispatch.doingTasks,
|
|
569
592
|
blockedTasks: taskStatusDispatch.blockedTasks,
|
|
570
593
|
inactiveAgents: inactiveCandidates.length,
|
|
571
594
|
sent: dispatches.length - failed,
|
|
@@ -573,10 +596,67 @@ export class OpenGoatService {
|
|
|
573
596
|
dispatches,
|
|
574
597
|
};
|
|
575
598
|
}
|
|
576
|
-
async
|
|
599
|
+
async dispatchTopDownTaskDelegationAutomations(paths, tasks, manifests, openTasksThreshold, notificationTimestamp, maxParallelFlows = 1) {
|
|
600
|
+
const openTasks = tasks
|
|
601
|
+
.filter((task) => task.status.trim().toLowerCase() !== "done")
|
|
602
|
+
.sort((left, right) => {
|
|
603
|
+
const leftTimestamp = Date.parse(left.updatedAt);
|
|
604
|
+
const rightTimestamp = Date.parse(right.updatedAt);
|
|
605
|
+
if (Number.isFinite(leftTimestamp) && Number.isFinite(rightTimestamp)) {
|
|
606
|
+
return rightTimestamp - leftTimestamp;
|
|
607
|
+
}
|
|
608
|
+
if (Number.isFinite(rightTimestamp)) {
|
|
609
|
+
return 1;
|
|
610
|
+
}
|
|
611
|
+
if (Number.isFinite(leftTimestamp)) {
|
|
612
|
+
return -1;
|
|
613
|
+
}
|
|
614
|
+
return right.taskId.localeCompare(left.taskId);
|
|
615
|
+
});
|
|
616
|
+
if (openTasks.length > openTasksThreshold) {
|
|
617
|
+
return [];
|
|
618
|
+
}
|
|
619
|
+
const managerAgents = manifests.filter((manifest) => manifest.metadata.type === "manager").length;
|
|
620
|
+
const ceoDirectReportees = manifests.filter((manifest) => normalizeAgentId(manifest.metadata.reportsTo ?? "") === DEFAULT_AGENT_ID).length;
|
|
621
|
+
const sessionRef = buildNotificationSessionRef(DEFAULT_AGENT_ID);
|
|
622
|
+
const message = buildTopDownTaskDelegationMessage({
|
|
623
|
+
openTasksThreshold,
|
|
624
|
+
openTasksCount: openTasks.length,
|
|
625
|
+
totalAgents: manifests.length,
|
|
626
|
+
managerAgents,
|
|
627
|
+
ceoDirectReportees,
|
|
628
|
+
openTasks: openTasks.map((task) => ({
|
|
629
|
+
taskId: task.taskId,
|
|
630
|
+
title: task.title,
|
|
631
|
+
status: task.status,
|
|
632
|
+
assignedTo: task.assignedTo,
|
|
633
|
+
})),
|
|
634
|
+
notificationTimestamp,
|
|
635
|
+
});
|
|
636
|
+
const requests = [
|
|
637
|
+
{
|
|
638
|
+
targetAgentId: DEFAULT_AGENT_ID,
|
|
639
|
+
sessionRef,
|
|
640
|
+
message,
|
|
641
|
+
},
|
|
642
|
+
];
|
|
643
|
+
return runWithConcurrencyByKey(requests, maxParallelFlows, (request) => request.targetAgentId, async (request) => {
|
|
644
|
+
const result = await this.dispatchAutomationMessage(paths, request.targetAgentId, request.sessionRef, request.message);
|
|
645
|
+
return {
|
|
646
|
+
kind: "topdown",
|
|
647
|
+
targetAgentId: request.targetAgentId,
|
|
648
|
+
sessionRef: request.sessionRef,
|
|
649
|
+
message: request.message,
|
|
650
|
+
ok: result.ok,
|
|
651
|
+
error: result.error,
|
|
652
|
+
};
|
|
653
|
+
});
|
|
654
|
+
}
|
|
655
|
+
async dispatchTaskStatusAutomations(paths, tasks, manifests, doingTaskIds, pendingTaskIds, doingMinutes, pendingMinutes, notificationTimestamp, maxParallelFlows) {
|
|
577
656
|
const manifestsById = new Map(manifests.map((manifest) => [manifest.agentId, manifest]));
|
|
578
657
|
const requests = [];
|
|
579
658
|
let todoTasks = 0;
|
|
659
|
+
let doingTasks = 0;
|
|
580
660
|
let pendingTasks = 0;
|
|
581
661
|
let blockedTasks = 0;
|
|
582
662
|
for (const task of tasks) {
|
|
@@ -597,6 +677,27 @@ export class OpenGoatService {
|
|
|
597
677
|
});
|
|
598
678
|
continue;
|
|
599
679
|
}
|
|
680
|
+
if (task.status === "doing") {
|
|
681
|
+
if (!doingTaskIds.has(task.taskId)) {
|
|
682
|
+
continue;
|
|
683
|
+
}
|
|
684
|
+
doingTasks += 1;
|
|
685
|
+
const targetAgentId = task.assignedTo;
|
|
686
|
+
const sessionRef = buildNotificationSessionRef(targetAgentId);
|
|
687
|
+
const message = buildDoingTaskMessage({
|
|
688
|
+
task,
|
|
689
|
+
doingMinutes,
|
|
690
|
+
notificationTimestamp,
|
|
691
|
+
});
|
|
692
|
+
requests.push({
|
|
693
|
+
kind: "doing",
|
|
694
|
+
targetAgentId,
|
|
695
|
+
sessionRef,
|
|
696
|
+
taskId: task.taskId,
|
|
697
|
+
message,
|
|
698
|
+
});
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
600
701
|
if (task.status === "pending") {
|
|
601
702
|
if (!pendingTaskIds.has(task.taskId)) {
|
|
602
703
|
continue;
|
|
@@ -649,34 +750,55 @@ export class OpenGoatService {
|
|
|
649
750
|
error: result.error,
|
|
650
751
|
};
|
|
651
752
|
});
|
|
753
|
+
const notifiedDoingTaskIds = dedupeStrings(dispatches
|
|
754
|
+
.filter((dispatch) => dispatch.kind === "doing" && dispatch.ok)
|
|
755
|
+
.map((dispatch) => dispatch.taskId)
|
|
756
|
+
.filter((taskId) => typeof taskId === "string"));
|
|
757
|
+
await Promise.all(notifiedDoingTaskIds.map(async (taskId) => {
|
|
758
|
+
await this.boardService.resetTaskStatusTimeout(paths, taskId, "doing");
|
|
759
|
+
}));
|
|
652
760
|
return {
|
|
653
761
|
dispatches,
|
|
654
762
|
todoTasks,
|
|
763
|
+
doingTasks,
|
|
655
764
|
pendingTasks,
|
|
656
765
|
blockedTasks,
|
|
657
766
|
};
|
|
658
767
|
}
|
|
659
768
|
async dispatchInactiveAgentAutomations(paths, inactiveCandidates, inactiveMinutes, notificationTimestamp, maxParallelFlows = 1) {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
const
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
769
|
+
const groupedCandidatesByManager = new Map();
|
|
770
|
+
for (const candidate of inactiveCandidates) {
|
|
771
|
+
const managerAgentId = normalizeAgentId(candidate.managerAgentId) || DEFAULT_AGENT_ID;
|
|
772
|
+
const bucket = groupedCandidatesByManager.get(managerAgentId) ?? [];
|
|
773
|
+
bucket.push(candidate);
|
|
774
|
+
groupedCandidatesByManager.set(managerAgentId, bucket);
|
|
775
|
+
}
|
|
776
|
+
const requests = [...groupedCandidatesByManager.entries()]
|
|
777
|
+
.sort(([leftManagerId], [rightManagerId]) => leftManagerId.localeCompare(rightManagerId))
|
|
778
|
+
.map(([managerAgentId, candidates]) => {
|
|
779
|
+
const orderedCandidates = [...candidates].sort((left, right) => left.subjectAgentId.localeCompare(right.subjectAgentId));
|
|
780
|
+
return {
|
|
781
|
+
managerAgentId,
|
|
782
|
+
candidates: orderedCandidates,
|
|
783
|
+
sessionRef: buildNotificationSessionRef(managerAgentId),
|
|
784
|
+
message: buildInactiveAgentsMessage({
|
|
785
|
+
inactiveMinutes,
|
|
786
|
+
notificationTimestamp,
|
|
787
|
+
candidates: orderedCandidates,
|
|
788
|
+
}),
|
|
789
|
+
subjectAgentId: orderedCandidates.length === 1
|
|
790
|
+
? orderedCandidates[0]?.subjectAgentId
|
|
791
|
+
: undefined,
|
|
792
|
+
};
|
|
793
|
+
});
|
|
794
|
+
return runWithConcurrencyByKey(requests, maxParallelFlows, (request) => request.managerAgentId, async (request) => {
|
|
795
|
+
const result = await this.dispatchAutomationMessage(paths, request.managerAgentId, request.sessionRef, request.message);
|
|
674
796
|
return {
|
|
675
797
|
kind: "inactive",
|
|
676
|
-
targetAgentId:
|
|
677
|
-
sessionRef,
|
|
678
|
-
subjectAgentId:
|
|
679
|
-
message,
|
|
798
|
+
targetAgentId: request.managerAgentId,
|
|
799
|
+
sessionRef: request.sessionRef,
|
|
800
|
+
subjectAgentId: request.subjectAgentId,
|
|
801
|
+
message: request.message,
|
|
680
802
|
ok: result.ok,
|
|
681
803
|
error: result.error,
|
|
682
804
|
};
|
|
@@ -773,9 +895,9 @@ export class OpenGoatService {
|
|
|
773
895
|
getPaths() {
|
|
774
896
|
return this.pathsProvider.getPaths();
|
|
775
897
|
}
|
|
776
|
-
async dispatchAutomationMessage(
|
|
898
|
+
async dispatchAutomationMessage(_paths, agentId, sessionRef, message, options = {}) {
|
|
777
899
|
try {
|
|
778
|
-
const result = await this.
|
|
900
|
+
const result = await this.runAgent(agentId, {
|
|
779
901
|
message,
|
|
780
902
|
sessionRef,
|
|
781
903
|
disableSession: options.disableSession ?? false,
|
|
@@ -802,13 +924,15 @@ export class OpenGoatService {
|
|
|
802
924
|
resolveNowIso() {
|
|
803
925
|
return this.nowIso();
|
|
804
926
|
}
|
|
805
|
-
async initializeRuntimeDefaults() {
|
|
927
|
+
async initializeRuntimeDefaults(options) {
|
|
806
928
|
const initialization = await this.bootstrapService.initialize();
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
929
|
+
if (options.syncRuntimeDefaults) {
|
|
930
|
+
try {
|
|
931
|
+
await this.syncRuntimeDefaults();
|
|
932
|
+
}
|
|
933
|
+
catch {
|
|
934
|
+
// Startup remains functional even if OpenClaw CLI/runtime is unavailable.
|
|
935
|
+
}
|
|
812
936
|
}
|
|
813
937
|
return initialization;
|
|
814
938
|
}
|
|
@@ -898,9 +1022,12 @@ export class OpenGoatService {
|
|
|
898
1022
|
}
|
|
899
1023
|
const runtimeProfile = await this.providerService.getAgentRuntimeProfile(paths, agentId);
|
|
900
1024
|
const managedRoleSkillDirectories = await this.providerService.listProviderRoleSkillDirectories();
|
|
1025
|
+
const managedRoleSkillIds = await this.providerService.listProviderRoleSkillIds();
|
|
901
1026
|
return this.agentService.ensureAgentWorkspaceRoleSkills(paths, agentId, {
|
|
902
1027
|
requiredSkillDirectories: runtimeProfile.roleSkillDirectories,
|
|
903
1028
|
managedSkillDirectories: managedRoleSkillDirectories,
|
|
1029
|
+
roleSkillIdsByType: runtimeProfile.roleSkillIds,
|
|
1030
|
+
managedRoleSkillIds,
|
|
904
1031
|
});
|
|
905
1032
|
}
|
|
906
1033
|
async resolveOpenClawManagedSkillsDir(paths) {
|
|
@@ -1135,6 +1262,12 @@ export class OpenGoatService {
|
|
|
1135
1262
|
warnings.push(`OpenClaw tools policy sync failed for "${agentId}" (code ${toolsSet.code}). ${toolsSet.stderr.trim() || toolsSet.stdout.trim() || ""}`.trim());
|
|
1136
1263
|
}
|
|
1137
1264
|
}
|
|
1265
|
+
if (readAgentSkipBootstrap(entry) !== OPENCLAW_AGENT_SKIP_BOOTSTRAP) {
|
|
1266
|
+
const bootstrapSet = await this.runOpenClaw(["config", "set", `agents.list[${index}].skipBootstrap`, "true"], { env });
|
|
1267
|
+
if (bootstrapSet.code !== 0) {
|
|
1268
|
+
warnings.push(`OpenClaw bootstrap policy sync failed for "${agentId}" (code ${bootstrapSet.code}). ${bootstrapSet.stderr.trim() || bootstrapSet.stdout.trim() || ""}`.trim());
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1138
1271
|
}
|
|
1139
1272
|
return warnings;
|
|
1140
1273
|
}
|
|
@@ -1349,6 +1482,22 @@ function hasAgentToolsAllowAll(entry) {
|
|
|
1349
1482
|
}
|
|
1350
1483
|
return allow.some((value) => typeof value === "string" && value.trim() === "*");
|
|
1351
1484
|
}
|
|
1485
|
+
function readAgentSkipBootstrap(entry) {
|
|
1486
|
+
const value = entry.skipBootstrap;
|
|
1487
|
+
if (typeof value === "boolean") {
|
|
1488
|
+
return value;
|
|
1489
|
+
}
|
|
1490
|
+
if (typeof value === "string") {
|
|
1491
|
+
const normalized = value.trim().toLowerCase();
|
|
1492
|
+
if (normalized === "true") {
|
|
1493
|
+
return true;
|
|
1494
|
+
}
|
|
1495
|
+
if (normalized === "false") {
|
|
1496
|
+
return false;
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
return undefined;
|
|
1500
|
+
}
|
|
1352
1501
|
function readStringArray(value) {
|
|
1353
1502
|
if (!Array.isArray(value)) {
|
|
1354
1503
|
return [];
|
|
@@ -1404,11 +1553,15 @@ function parseLooseJson(raw) {
|
|
|
1404
1553
|
if (!trimmed) {
|
|
1405
1554
|
return undefined;
|
|
1406
1555
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1556
|
+
const exact = tryParseJson(trimmed);
|
|
1557
|
+
if (exact !== undefined) {
|
|
1558
|
+
return exact;
|
|
1409
1559
|
}
|
|
1410
|
-
|
|
1411
|
-
|
|
1560
|
+
for (const line of trimmed.split(/\r?\n/)) {
|
|
1561
|
+
const parsedLine = tryParseJson(line.trim());
|
|
1562
|
+
if (parsedLine !== undefined) {
|
|
1563
|
+
return parsedLine;
|
|
1564
|
+
}
|
|
1412
1565
|
}
|
|
1413
1566
|
const starts = dedupeNumbers([
|
|
1414
1567
|
trimmed.indexOf("{"),
|
|
@@ -1421,11 +1574,69 @@ function parseLooseJson(raw) {
|
|
|
1421
1574
|
if (!candidate) {
|
|
1422
1575
|
continue;
|
|
1423
1576
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1577
|
+
const parsedCandidate = tryParseJson(candidate);
|
|
1578
|
+
if (parsedCandidate !== undefined) {
|
|
1579
|
+
return parsedCandidate;
|
|
1426
1580
|
}
|
|
1427
|
-
|
|
1428
|
-
|
|
1581
|
+
const balancedCandidate = extractBalancedJsonCandidate(trimmed, startIndex);
|
|
1582
|
+
if (!balancedCandidate) {
|
|
1583
|
+
continue;
|
|
1584
|
+
}
|
|
1585
|
+
const parsedBalancedCandidate = tryParseJson(balancedCandidate);
|
|
1586
|
+
if (parsedBalancedCandidate !== undefined) {
|
|
1587
|
+
return parsedBalancedCandidate;
|
|
1588
|
+
}
|
|
1589
|
+
}
|
|
1590
|
+
return undefined;
|
|
1591
|
+
}
|
|
1592
|
+
function tryParseJson(raw) {
|
|
1593
|
+
if (!raw) {
|
|
1594
|
+
return undefined;
|
|
1595
|
+
}
|
|
1596
|
+
try {
|
|
1597
|
+
return JSON.parse(raw);
|
|
1598
|
+
}
|
|
1599
|
+
catch {
|
|
1600
|
+
return undefined;
|
|
1601
|
+
}
|
|
1602
|
+
}
|
|
1603
|
+
function extractBalancedJsonCandidate(raw, startIndex) {
|
|
1604
|
+
const opening = raw[startIndex];
|
|
1605
|
+
if (opening !== "{" && opening !== "[") {
|
|
1606
|
+
return undefined;
|
|
1607
|
+
}
|
|
1608
|
+
const closing = opening === "{" ? "}" : "]";
|
|
1609
|
+
let depth = 0;
|
|
1610
|
+
let inString = false;
|
|
1611
|
+
let escaping = false;
|
|
1612
|
+
for (let index = startIndex; index < raw.length; index += 1) {
|
|
1613
|
+
const char = raw[index];
|
|
1614
|
+
if (inString) {
|
|
1615
|
+
if (escaping) {
|
|
1616
|
+
escaping = false;
|
|
1617
|
+
}
|
|
1618
|
+
else if (char === "\\") {
|
|
1619
|
+
escaping = true;
|
|
1620
|
+
}
|
|
1621
|
+
else if (char === "\"") {
|
|
1622
|
+
inString = false;
|
|
1623
|
+
}
|
|
1624
|
+
continue;
|
|
1625
|
+
}
|
|
1626
|
+
if (char === "\"") {
|
|
1627
|
+
inString = true;
|
|
1628
|
+
continue;
|
|
1629
|
+
}
|
|
1630
|
+
if (char === opening) {
|
|
1631
|
+
depth += 1;
|
|
1632
|
+
continue;
|
|
1633
|
+
}
|
|
1634
|
+
if (char !== closing) {
|
|
1635
|
+
continue;
|
|
1636
|
+
}
|
|
1637
|
+
depth -= 1;
|
|
1638
|
+
if (depth === 0) {
|
|
1639
|
+
return raw.slice(startIndex, index + 1).trim();
|
|
1429
1640
|
}
|
|
1430
1641
|
}
|
|
1431
1642
|
return undefined;
|