@opengoat/core 2026.2.9 → 2026.2.14
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/README.md +3 -3
- package/dist/core/acp/application/acp-agent.js +4 -8
- package/dist/core/acp/application/acp-agent.js.map +1 -1
- package/dist/core/agents/application/agent-manifest.service.d.ts +1 -4
- package/dist/core/agents/application/agent-manifest.service.js +39 -52
- package/dist/core/agents/application/agent-manifest.service.js.map +1 -1
- package/dist/core/agents/application/agent.service.d.ts +43 -4
- package/dist/core/agents/application/agent.service.js +476 -55
- package/dist/core/agents/application/agent.service.js.map +1 -1
- package/dist/core/agents/domain/agent-manifest.d.ts +10 -4
- package/dist/core/agents/domain/agent-manifest.js +118 -25
- package/dist/core/agents/domain/agent-manifest.js.map +1 -1
- package/dist/core/agents/index.d.ts +1 -3
- package/dist/core/agents/index.js +1 -3
- package/dist/core/agents/index.js.map +1 -1
- package/dist/core/boards/application/board.service.d.ts +64 -0
- package/dist/core/boards/application/board.service.js +590 -0
- package/dist/core/boards/application/board.service.js.map +1 -0
- package/dist/core/boards/domain/board.d.ts +30 -0
- package/dist/core/boards/domain/board.js +2 -0
- package/dist/core/boards/domain/board.js.map +1 -0
- package/dist/core/boards/index.d.ts +2 -0
- package/dist/core/boards/index.js +2 -0
- package/dist/core/boards/index.js.map +1 -0
- package/dist/core/bootstrap/application/bootstrap.service.d.ts +5 -2
- package/dist/core/bootstrap/application/bootstrap.service.js +32 -17
- package/dist/core/bootstrap/application/bootstrap.service.js.map +1 -1
- package/dist/core/domain/agent-id.d.ts +1 -1
- package/dist/core/domain/agent-id.js +1 -1
- package/dist/core/domain/agent-id.js.map +1 -1
- package/dist/core/domain/agent.d.ts +31 -8
- package/dist/core/domain/opengoat-paths.d.ts +1 -0
- package/dist/core/opengoat/application/opengoat.service.d.ts +111 -27
- package/dist/core/opengoat/application/opengoat.service.js +1048 -136
- package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
- package/dist/core/opengoat/index.d.ts +1 -0
- package/dist/core/orchestration/application/orchestration.service.d.ts +8 -21
- package/dist/core/orchestration/application/orchestration.service.js +59 -871
- package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
- package/dist/core/orchestration/application/routing.service.js +10 -8
- package/dist/core/orchestration/application/routing.service.js.map +1 -1
- package/dist/core/orchestration/domain/routing.d.ts +0 -17
- package/dist/core/orchestration/domain/run-events.d.ts +1 -1
- package/dist/core/orchestration/index.d.ts +0 -2
- package/dist/core/orchestration/index.js +0 -1
- package/dist/core/orchestration/index.js.map +1 -1
- package/dist/core/providers/application/provider.service.d.ts +16 -32
- package/dist/core/providers/application/provider.service.js +178 -202
- 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 +66 -1
- package/dist/core/providers/cli-provider.js.map +1 -1
- package/dist/core/providers/image-input.d.ts +16 -0
- package/dist/core/providers/image-input.js +158 -0
- package/dist/core/providers/image-input.js.map +1 -0
- package/dist/core/providers/index.d.ts +1 -7
- package/dist/core/providers/index.js +0 -13
- package/dist/core/providers/index.js.map +1 -1
- package/dist/core/providers/loader.js +1 -95
- package/dist/core/providers/loader.js.map +1 -1
- package/dist/core/providers/providers/openclaw/provider.js +213 -32
- package/dist/core/providers/providers/openclaw/provider.js.map +1 -1
- package/dist/core/providers/types.d.ts +8 -3
- package/dist/core/scenarios/application/scenario-runner.service.d.ts +0 -1
- package/dist/core/scenarios/application/scenario-runner.service.js +30 -87
- package/dist/core/scenarios/application/scenario-runner.service.js.map +1 -1
- package/dist/core/scenarios/domain/scenario.d.ts +0 -15
- package/dist/core/sessions/application/session.service.d.ts +10 -4
- package/dist/core/sessions/application/session.service.js +87 -89
- package/dist/core/sessions/application/session.service.js.map +1 -1
- package/dist/core/sessions/domain/session.d.ts +3 -3
- package/dist/core/sessions/domain/transcript.d.ts +1 -1
- package/dist/core/sessions/index.d.ts +1 -1
- package/dist/core/sessions/index.js.map +1 -1
- package/dist/core/skills/application/skill.service.d.ts +2 -3
- package/dist/core/skills/application/skill.service.js +153 -56
- package/dist/core/skills/application/skill.service.js.map +1 -1
- package/dist/core/skills/domain/skill.d.ts +2 -2
- package/dist/core/skills/domain/skill.js +4 -2
- package/dist/core/skills/domain/skill.js.map +1 -1
- package/dist/core/templates/assets/ceo/BOOTSTRAP.md +41 -0
- package/dist/core/templates/assets/ceo/ROLE.md +15 -0
- package/dist/core/templates/assets/organization/MISSION.md +73 -0
- package/dist/core/templates/assets/organization/STRATEGY.md +107 -0
- package/dist/core/templates/assets/organization/VISION.md +80 -0
- package/dist/core/templates/assets/organization/wiki/index.md +15 -0
- package/dist/core/templates/assets/skills/og-board-individual/SKILL.md +148 -0
- package/dist/core/templates/assets/skills/og-board-manager/SKILL.md +140 -0
- package/dist/core/templates/default-templates.d.ts +17 -14
- package/dist/core/templates/default-templates.js +115 -212
- package/dist/core/templates/default-templates.js.map +1 -1
- package/dist/index.d.ts +1 -4
- package/dist/index.js +1 -4
- package/dist/index.js.map +1 -1
- package/dist/platform/node/node-path.port.js +1 -0
- package/dist/platform/node/node-path.port.js.map +1 -1
- package/package.json +16 -13
- package/dist/core/agents/application/workspace-context.service.d.ts +0 -28
- package/dist/core/agents/application/workspace-context.service.js +0 -157
- package/dist/core/agents/application/workspace-context.service.js.map +0 -1
- package/dist/core/agents/domain/workspace-context.d.ts +0 -13
- package/dist/core/agents/domain/workspace-context.js +0 -14
- package/dist/core/agents/domain/workspace-context.js.map +0 -1
- package/dist/core/gateway/domain/protocol.d.ts +0 -113
- package/dist/core/gateway/domain/protocol.js +0 -394
- package/dist/core/gateway/domain/protocol.js.map +0 -1
- package/dist/core/gateway/index.d.ts +0 -2
- package/dist/core/gateway/index.js +0 -2
- package/dist/core/gateway/index.js.map +0 -1
- package/dist/core/llm/application/vercel-ai-text-runtime.d.ts +0 -26
- package/dist/core/llm/application/vercel-ai-text-runtime.js +0 -223
- package/dist/core/llm/application/vercel-ai-text-runtime.js.map +0 -1
- package/dist/core/llm/domain/text-runtime.d.ts +0 -22
- package/dist/core/llm/domain/text-runtime.js +0 -2
- package/dist/core/llm/domain/text-runtime.js.map +0 -1
- package/dist/core/llm/index.d.ts +0 -2
- package/dist/core/llm/index.js +0 -2
- package/dist/core/llm/index.js.map +0 -1
- package/dist/core/orchestration/application/orchestration-planner.service.d.ts +0 -28
- package/dist/core/orchestration/application/orchestration-planner.service.js +0 -279
- package/dist/core/orchestration/application/orchestration-planner.service.js.map +0 -1
- package/dist/core/orchestration/domain/loop.d.ts +0 -119
- package/dist/core/orchestration/domain/loop.js +0 -2
- package/dist/core/orchestration/domain/loop.js.map +0 -1
- package/dist/core/plugins/application/plugin.service.d.ts +0 -32
- package/dist/core/plugins/application/plugin.service.js +0 -236
- package/dist/core/plugins/application/plugin.service.js.map +0 -1
- package/dist/core/plugins/domain/openclaw-compat.d.ts +0 -60
- package/dist/core/plugins/domain/openclaw-compat.js +0 -9
- package/dist/core/plugins/domain/openclaw-compat.js.map +0 -1
- package/dist/core/plugins/index.d.ts +0 -3
- package/dist/core/plugins/index.js +0 -3
- package/dist/core/plugins/index.js.map +0 -1
- package/dist/core/providers/onboarding.d.ts +0 -13
- package/dist/core/providers/onboarding.js +0 -149
- package/dist/core/providers/onboarding.js.map +0 -1
- package/dist/core/providers/providers/claude/index.d.ts +0 -4
- package/dist/core/providers/providers/claude/index.js +0 -19
- package/dist/core/providers/providers/claude/index.js.map +0 -1
- package/dist/core/providers/providers/claude/provider.d.ts +0 -8
- package/dist/core/providers/providers/claude/provider.js +0 -106
- package/dist/core/providers/providers/claude/provider.js.map +0 -1
- package/dist/core/providers/providers/codex/index.d.ts +0 -4
- package/dist/core/providers/providers/codex/index.js +0 -19
- package/dist/core/providers/providers/codex/index.js.map +0 -1
- package/dist/core/providers/providers/codex/provider.d.ts +0 -7
- package/dist/core/providers/providers/codex/provider.js +0 -31
- package/dist/core/providers/providers/codex/provider.js.map +0 -1
- package/dist/core/providers/providers/cursor/index.d.ts +0 -4
- package/dist/core/providers/providers/cursor/index.js +0 -19
- package/dist/core/providers/providers/cursor/index.js.map +0 -1
- package/dist/core/providers/providers/cursor/provider.d.ts +0 -11
- package/dist/core/providers/providers/cursor/provider.js +0 -90
- package/dist/core/providers/providers/cursor/provider.js.map +0 -1
- package/dist/core/providers/providers/extended-http/catalog.d.ts +0 -40
- package/dist/core/providers/providers/extended-http/catalog.js +0 -728
- package/dist/core/providers/providers/extended-http/catalog.js.map +0 -1
- package/dist/core/providers/providers/extended-http/index.d.ts +0 -5
- package/dist/core/providers/providers/extended-http/index.js +0 -13
- package/dist/core/providers/providers/extended-http/index.js.map +0 -1
- package/dist/core/providers/providers/extended-http/provider.d.ts +0 -31
- package/dist/core/providers/providers/extended-http/provider.js +0 -580
- package/dist/core/providers/providers/extended-http/provider.js.map +0 -1
- package/dist/core/providers/providers/gemini/index.d.ts +0 -4
- package/dist/core/providers/providers/gemini/index.js +0 -37
- package/dist/core/providers/providers/gemini/index.js.map +0 -1
- package/dist/core/providers/providers/gemini/provider.d.ts +0 -7
- package/dist/core/providers/providers/gemini/provider.js +0 -59
- package/dist/core/providers/providers/gemini/provider.js.map +0 -1
- package/dist/core/providers/providers/grok/index.d.ts +0 -4
- package/dist/core/providers/providers/grok/index.js +0 -41
- package/dist/core/providers/providers/grok/index.js.map +0 -1
- package/dist/core/providers/providers/grok/provider.d.ts +0 -13
- package/dist/core/providers/providers/grok/provider.js +0 -95
- package/dist/core/providers/providers/grok/provider.js.map +0 -1
- package/dist/core/providers/providers/openai/index.d.ts +0 -4
- package/dist/core/providers/providers/openai/index.js +0 -45
- package/dist/core/providers/providers/openai/index.js.map +0 -1
- package/dist/core/providers/providers/openai/provider.d.ts +0 -14
- package/dist/core/providers/providers/openai/provider.js +0 -203
- package/dist/core/providers/providers/openai/provider.js.map +0 -1
- package/dist/core/providers/providers/opencode/index.d.ts +0 -4
- package/dist/core/providers/providers/opencode/index.js +0 -23
- package/dist/core/providers/providers/opencode/index.js.map +0 -1
- package/dist/core/providers/providers/opencode/provider.d.ts +0 -11
- package/dist/core/providers/providers/opencode/provider.js +0 -215
- package/dist/core/providers/providers/opencode/provider.js.map +0 -1
- package/dist/core/providers/providers/openrouter/index.d.ts +0 -4
- package/dist/core/providers/providers/openrouter/index.js +0 -37
- package/dist/core/providers/providers/openrouter/index.js.map +0 -1
- package/dist/core/providers/providers/openrouter/provider.d.ts +0 -13
- package/dist/core/providers/providers/openrouter/provider.js +0 -80
- package/dist/core/providers/providers/openrouter/provider.js.map +0 -1
- package/dist/platform/node/opengoat-gateway-client.d.ts +0 -19
- package/dist/platform/node/opengoat-gateway-client.js +0 -194
- package/dist/platform/node/opengoat-gateway-client.js.map +0 -1
- package/dist/platform/node/opengoat-gateway-server.d.ts +0 -53
- package/dist/platform/node/opengoat-gateway-server.js +0 -906
- package/dist/platform/node/opengoat-gateway-server.js.map +0 -1
|
@@ -1,38 +1,25 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { isDiscoverableByOrchestrator } from "../../agents/index.js";
|
|
4
2
|
import { DEFAULT_AGENT_ID, normalizeAgentId } from "../../domain/agent-id.js";
|
|
5
3
|
import { createNoopLogger } from "../../logging/index.js";
|
|
6
|
-
import { OrchestrationPlannerService } from "./orchestration-planner.service.js";
|
|
7
4
|
import { RoutingService } from "./routing.service.js";
|
|
8
|
-
const MAX_ORCHESTRATION_STEPS = 12;
|
|
9
|
-
const MAX_DELEGATION_STEPS = 8;
|
|
10
|
-
const SHARED_NOTES_MAX_CHARS = 12_000;
|
|
11
|
-
const RECENT_EVENTS_WINDOW = 10;
|
|
12
5
|
export class OrchestrationService {
|
|
13
6
|
providerService;
|
|
14
|
-
skillService;
|
|
15
7
|
agentManifestService;
|
|
16
8
|
sessionService;
|
|
17
|
-
commandRunner;
|
|
18
9
|
routingService;
|
|
19
|
-
plannerService;
|
|
20
10
|
fileSystem;
|
|
21
11
|
pathPort;
|
|
22
12
|
nowIso;
|
|
23
13
|
logger;
|
|
24
14
|
constructor(deps) {
|
|
25
15
|
this.providerService = deps.providerService;
|
|
26
|
-
this.skillService = deps.skillService;
|
|
27
16
|
this.agentManifestService = deps.agentManifestService;
|
|
28
17
|
this.sessionService = deps.sessionService;
|
|
29
|
-
this.commandRunner = deps.commandRunner;
|
|
30
18
|
this.routingService = deps.routingService ?? new RoutingService();
|
|
31
|
-
this.plannerService = deps.plannerService ?? new OrchestrationPlannerService();
|
|
32
19
|
this.fileSystem = deps.fileSystem;
|
|
33
20
|
this.pathPort = deps.pathPort;
|
|
34
21
|
this.nowIso = deps.nowIso;
|
|
35
|
-
this.logger = (deps.logger ?? createNoopLogger()).child({ scope: "
|
|
22
|
+
this.logger = (deps.logger ?? createNoopLogger()).child({ scope: "manager-runtime-service" });
|
|
36
23
|
}
|
|
37
24
|
async routeMessage(paths, entryAgentId, message) {
|
|
38
25
|
const manifests = await this.agentManifestService.listManifests(paths);
|
|
@@ -45,617 +32,74 @@ export class OrchestrationService {
|
|
|
45
32
|
}
|
|
46
33
|
async runAgent(paths, entryAgentId, options) {
|
|
47
34
|
const runId = generateRunId();
|
|
48
|
-
const runLogger = this.logger.child({ runId });
|
|
49
35
|
const startedAt = this.nowIso();
|
|
50
36
|
const manifests = await this.agentManifestService.listManifests(paths);
|
|
51
37
|
const resolvedEntryAgentId = resolveEntryAgentId(entryAgentId, manifests);
|
|
52
|
-
runLogger.info("Starting agent run.", {
|
|
53
|
-
entryAgentId,
|
|
54
|
-
resolvedEntryAgentId
|
|
55
|
-
});
|
|
56
38
|
emitRunStatusEvent(options, {
|
|
57
39
|
stage: "run_started",
|
|
58
40
|
runId,
|
|
59
41
|
timestamp: this.nowIso(),
|
|
60
42
|
agentId: resolvedEntryAgentId
|
|
61
43
|
});
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
message: options.message
|
|
70
|
-
}, { sessionAgentId, runId });
|
|
71
|
-
const completedAt = this.nowIso();
|
|
72
|
-
const routing = {
|
|
73
|
-
entryAgentId: resolvedEntryAgentId,
|
|
74
|
-
targetAgentId: resolvedEntryAgentId,
|
|
75
|
-
confidence: 1,
|
|
76
|
-
reason: "Direct invocation of a non-orchestrator agent.",
|
|
77
|
-
rewrittenMessage: options.message,
|
|
78
|
-
candidates: []
|
|
79
|
-
};
|
|
80
|
-
const trace = await this.buildAndWriteTrace({
|
|
81
|
-
paths,
|
|
82
|
-
runId,
|
|
83
|
-
startedAt,
|
|
84
|
-
completedAt,
|
|
85
|
-
entryAgentId: resolvedEntryAgentId,
|
|
86
|
-
userMessage: options.message,
|
|
87
|
-
routing,
|
|
88
|
-
execution: direct.execution,
|
|
89
|
-
durationMs: 0,
|
|
90
|
-
session: direct.session,
|
|
91
|
-
orchestration: {
|
|
92
|
-
mode: "single-agent",
|
|
93
|
-
finalMessage: direct.execution.stdout,
|
|
94
|
-
steps: [],
|
|
95
|
-
sessionGraph: {
|
|
96
|
-
nodes: [
|
|
97
|
-
{
|
|
98
|
-
agentId: resolvedEntryAgentId,
|
|
99
|
-
providerId: direct.execution.providerId,
|
|
100
|
-
sessionKey: direct.session?.sessionKey,
|
|
101
|
-
sessionId: direct.session?.sessionId,
|
|
102
|
-
providerSessionId: direct.execution.providerSessionId
|
|
103
|
-
}
|
|
104
|
-
],
|
|
105
|
-
edges: []
|
|
106
|
-
},
|
|
107
|
-
taskThreads: []
|
|
108
|
-
}
|
|
109
|
-
});
|
|
110
|
-
emitRunStatusEvent(options, {
|
|
111
|
-
stage: "run_completed",
|
|
112
|
-
runId,
|
|
113
|
-
timestamp: this.nowIso(),
|
|
114
|
-
agentId: resolvedEntryAgentId
|
|
115
|
-
});
|
|
116
|
-
return {
|
|
117
|
-
...direct.execution,
|
|
118
|
-
entryAgentId: resolvedEntryAgentId,
|
|
119
|
-
routing,
|
|
120
|
-
tracePath: trace.tracePath,
|
|
121
|
-
session: direct.session,
|
|
122
|
-
orchestration: trace.trace.orchestration
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
const startTime = Date.now();
|
|
126
|
-
const loopResult = await this.runAiOrchestrationLoop(paths, runId, manifests, options, runLogger);
|
|
127
|
-
const durationMs = Date.now() - startTime;
|
|
44
|
+
const sessionAgentId = resolvedEntryAgentId;
|
|
45
|
+
const startedMs = Date.now();
|
|
46
|
+
const direct = await this.invokeAgentWithSession(paths, resolvedEntryAgentId, options, {
|
|
47
|
+
sessionAgentId,
|
|
48
|
+
runId
|
|
49
|
+
});
|
|
50
|
+
const durationMs = Date.now() - startedMs;
|
|
128
51
|
const completedAt = this.nowIso();
|
|
129
|
-
const routing = {
|
|
130
|
-
entryAgentId: DEFAULT_AGENT_ID,
|
|
131
|
-
targetAgentId: DEFAULT_AGENT_ID,
|
|
132
|
-
confidence: 0.9,
|
|
133
|
-
reason: "AI orchestration loop executed by orchestrator.",
|
|
134
|
-
rewrittenMessage: options.message,
|
|
135
|
-
candidates: []
|
|
136
|
-
};
|
|
137
52
|
const trace = await this.buildAndWriteTrace({
|
|
138
53
|
paths,
|
|
139
54
|
runId,
|
|
140
55
|
startedAt,
|
|
141
56
|
completedAt,
|
|
142
|
-
entryAgentId:
|
|
57
|
+
entryAgentId: resolvedEntryAgentId,
|
|
143
58
|
userMessage: options.message,
|
|
144
|
-
|
|
145
|
-
execution: loopResult.execution,
|
|
59
|
+
execution: direct.execution,
|
|
146
60
|
durationMs,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
61
|
+
session: direct.session
|
|
62
|
+
});
|
|
63
|
+
this.logger.info("Completed manager runtime invocation.", {
|
|
64
|
+
runId,
|
|
65
|
+
entryAgentId: resolvedEntryAgentId,
|
|
66
|
+
code: direct.execution.code,
|
|
67
|
+
durationMs
|
|
154
68
|
});
|
|
155
69
|
emitRunStatusEvent(options, {
|
|
156
70
|
stage: "run_completed",
|
|
157
71
|
runId,
|
|
158
72
|
timestamp: this.nowIso(),
|
|
159
|
-
agentId:
|
|
73
|
+
agentId: resolvedEntryAgentId
|
|
160
74
|
});
|
|
161
75
|
return {
|
|
162
|
-
...
|
|
163
|
-
entryAgentId:
|
|
164
|
-
routing,
|
|
76
|
+
...direct.execution,
|
|
77
|
+
entryAgentId: resolvedEntryAgentId,
|
|
165
78
|
tracePath: trace.tracePath,
|
|
166
|
-
|
|
167
|
-
};
|
|
168
|
-
}
|
|
169
|
-
async runAiOrchestrationLoop(paths, runId, manifests, options, runLogger) {
|
|
170
|
-
const steps = [];
|
|
171
|
-
const sessionGraph = {
|
|
172
|
-
nodes: [],
|
|
173
|
-
edges: []
|
|
79
|
+
session: direct.session
|
|
174
80
|
};
|
|
175
|
-
const taskThreads = new Map();
|
|
176
|
-
const sharedNotes = [];
|
|
177
|
-
const recentEvents = [];
|
|
178
|
-
let orchestratorSkillsSnapshot = await this.skillService.buildSkillsPrompt(paths, DEFAULT_AGENT_ID);
|
|
179
|
-
let orchestratorSkillsSummary = orchestratorSkillsSnapshot.skills.map((skill) => ({
|
|
180
|
-
id: skill.id,
|
|
181
|
-
name: skill.name,
|
|
182
|
-
description: skill.description,
|
|
183
|
-
source: skill.source
|
|
184
|
-
}));
|
|
185
|
-
let delegationCount = 0;
|
|
186
|
-
let finalMessage = "";
|
|
187
|
-
let lastExecution = await this.buildSyntheticExecution(paths, DEFAULT_AGENT_ID);
|
|
188
|
-
runLogger.info("Starting orchestration loop.", {
|
|
189
|
-
maxSteps: MAX_ORCHESTRATION_STEPS,
|
|
190
|
-
maxDelegations: MAX_DELEGATION_STEPS,
|
|
191
|
-
loadedSkills: orchestratorSkillsSummary.length
|
|
192
|
-
});
|
|
193
|
-
for (let step = 1; step <= MAX_ORCHESTRATION_STEPS; step += 1) {
|
|
194
|
-
const stepLogger = runLogger.child({ step });
|
|
195
|
-
const plannerPrompt = this.plannerService.buildPlannerPrompt({
|
|
196
|
-
userMessage: options.message,
|
|
197
|
-
step,
|
|
198
|
-
maxSteps: MAX_ORCHESTRATION_STEPS,
|
|
199
|
-
sharedNotes: clampText(sharedNotes.join("\n\n"), SHARED_NOTES_MAX_CHARS),
|
|
200
|
-
recentEvents,
|
|
201
|
-
agents: manifests,
|
|
202
|
-
taskThreads: summarizeTaskThreads(taskThreads),
|
|
203
|
-
skills: orchestratorSkillsSummary
|
|
204
|
-
});
|
|
205
|
-
stepLogger.debug("Planner prompt payload.", {
|
|
206
|
-
prompt: plannerPrompt
|
|
207
|
-
});
|
|
208
|
-
emitRunStatusEvent(options, {
|
|
209
|
-
stage: "planner_started",
|
|
210
|
-
runId,
|
|
211
|
-
timestamp: this.nowIso(),
|
|
212
|
-
step,
|
|
213
|
-
agentId: DEFAULT_AGENT_ID
|
|
214
|
-
});
|
|
215
|
-
const plannerCall = await this.invokeAgentWithSession(paths, DEFAULT_AGENT_ID, {
|
|
216
|
-
...options,
|
|
217
|
-
message: plannerPrompt,
|
|
218
|
-
skillsPromptOverride: orchestratorSkillsSnapshot.prompt,
|
|
219
|
-
sessionRef: options.sessionRef,
|
|
220
|
-
forceNewSession: step === 1 ? options.forceNewSession : false
|
|
221
|
-
}, { silent: true, runId, step });
|
|
222
|
-
const plannerRawOutput = plannerCall.execution.stdout.trim() || plannerCall.execution.stderr.trim();
|
|
223
|
-
stepLogger.debug("Planner raw output payload.", {
|
|
224
|
-
output: plannerRawOutput
|
|
225
|
-
});
|
|
226
|
-
if (plannerCall.execution.code !== 0) {
|
|
227
|
-
const providerFailureMessage = renderPlannerProviderFailureMessage(plannerCall.execution.providerId, plannerCall.execution.code, plannerCall.execution.stderr || plannerCall.execution.stdout);
|
|
228
|
-
const plannerDecision = {
|
|
229
|
-
rationale: "Planner provider invocation failed.",
|
|
230
|
-
action: {
|
|
231
|
-
type: "respond_user",
|
|
232
|
-
mode: "direct",
|
|
233
|
-
reason: "planner_provider_failure",
|
|
234
|
-
message: providerFailureMessage
|
|
235
|
-
}
|
|
236
|
-
};
|
|
237
|
-
emitRunStatusEvent(options, {
|
|
238
|
-
stage: "planner_decision",
|
|
239
|
-
runId,
|
|
240
|
-
timestamp: this.nowIso(),
|
|
241
|
-
step,
|
|
242
|
-
agentId: DEFAULT_AGENT_ID,
|
|
243
|
-
actionType: "respond_user",
|
|
244
|
-
mode: "direct"
|
|
245
|
-
});
|
|
246
|
-
stepLogger.warn("Planner provider invocation failed.", {
|
|
247
|
-
providerId: plannerCall.execution.providerId,
|
|
248
|
-
code: plannerCall.execution.code,
|
|
249
|
-
stderr: plannerCall.execution.stderr,
|
|
250
|
-
stdout: plannerCall.execution.stdout
|
|
251
|
-
});
|
|
252
|
-
addSessionNode(sessionGraph, DEFAULT_AGENT_ID, plannerCall.session, plannerCall.execution);
|
|
253
|
-
const stepLog = {
|
|
254
|
-
step,
|
|
255
|
-
timestamp: this.nowIso(),
|
|
256
|
-
plannerRawOutput,
|
|
257
|
-
plannerDecision,
|
|
258
|
-
note: `Planner provider ${plannerCall.execution.providerId} failed with code ${plannerCall.execution.code}.`
|
|
259
|
-
};
|
|
260
|
-
steps.push(stepLog);
|
|
261
|
-
finalMessage = providerFailureMessage;
|
|
262
|
-
lastExecution = {
|
|
263
|
-
...plannerCall.execution,
|
|
264
|
-
stdout: ensureTrailingNewline(providerFailureMessage)
|
|
265
|
-
};
|
|
266
|
-
break;
|
|
267
|
-
}
|
|
268
|
-
const plannerDecision = this.plannerService.parseDecision(plannerRawOutput, "I could not complete orchestration due to planner output parsing issues.");
|
|
269
|
-
emitRunStatusEvent(options, {
|
|
270
|
-
stage: "planner_decision",
|
|
271
|
-
runId,
|
|
272
|
-
timestamp: this.nowIso(),
|
|
273
|
-
step,
|
|
274
|
-
agentId: DEFAULT_AGENT_ID,
|
|
275
|
-
actionType: plannerDecision.action.type,
|
|
276
|
-
targetAgentId: plannerDecision.action.type === "delegate_to_agent"
|
|
277
|
-
? normalizeAgentId(plannerDecision.action.targetAgentId)
|
|
278
|
-
: undefined,
|
|
279
|
-
mode: plannerDecision.action.mode
|
|
280
|
-
});
|
|
281
|
-
stepLogger.info("Planner decision parsed.", {
|
|
282
|
-
actionType: plannerDecision.action.type,
|
|
283
|
-
actionMode: plannerDecision.action.mode ?? "direct",
|
|
284
|
-
rationale: plannerDecision.rationale
|
|
285
|
-
});
|
|
286
|
-
addSessionNode(sessionGraph, DEFAULT_AGENT_ID, plannerCall.session, plannerCall.execution);
|
|
287
|
-
const stepLog = {
|
|
288
|
-
step,
|
|
289
|
-
timestamp: this.nowIso(),
|
|
290
|
-
plannerRawOutput,
|
|
291
|
-
plannerDecision
|
|
292
|
-
};
|
|
293
|
-
const actionResult = await this.executeAction({
|
|
294
|
-
paths,
|
|
295
|
-
runId,
|
|
296
|
-
step,
|
|
297
|
-
action: plannerDecision.action,
|
|
298
|
-
manifests,
|
|
299
|
-
options,
|
|
300
|
-
sessionGraph,
|
|
301
|
-
stepLog,
|
|
302
|
-
sharedNotes,
|
|
303
|
-
recentEvents,
|
|
304
|
-
taskThreads,
|
|
305
|
-
logger: stepLogger
|
|
306
|
-
});
|
|
307
|
-
steps.push(stepLog);
|
|
308
|
-
if (actionResult.finalMessage !== undefined) {
|
|
309
|
-
finalMessage = actionResult.finalMessage;
|
|
310
|
-
if (actionResult.execution) {
|
|
311
|
-
lastExecution = actionResult.execution;
|
|
312
|
-
}
|
|
313
|
-
break;
|
|
314
|
-
}
|
|
315
|
-
if (actionResult.execution) {
|
|
316
|
-
lastExecution = actionResult.execution;
|
|
317
|
-
}
|
|
318
|
-
if (plannerDecision.action.type === "delegate_to_agent") {
|
|
319
|
-
delegationCount += 1;
|
|
320
|
-
}
|
|
321
|
-
if (plannerDecision.action.type === "install_skill" &&
|
|
322
|
-
(normalizeAgentId(plannerDecision.action.targetAgentId ?? DEFAULT_AGENT_ID) || DEFAULT_AGENT_ID) ===
|
|
323
|
-
DEFAULT_AGENT_ID) {
|
|
324
|
-
orchestratorSkillsSnapshot = await this.skillService.buildSkillsPrompt(paths, DEFAULT_AGENT_ID);
|
|
325
|
-
orchestratorSkillsSummary = orchestratorSkillsSnapshot.skills.map((skill) => ({
|
|
326
|
-
id: skill.id,
|
|
327
|
-
name: skill.name,
|
|
328
|
-
description: skill.description,
|
|
329
|
-
source: skill.source
|
|
330
|
-
}));
|
|
331
|
-
}
|
|
332
|
-
if (delegationCount >= MAX_DELEGATION_STEPS) {
|
|
333
|
-
stepLogger.warn("Delegation safety limit reached.");
|
|
334
|
-
finalMessage = "Stopped orchestration after reaching delegation safety limit.";
|
|
335
|
-
break;
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
if (!finalMessage) {
|
|
339
|
-
finalMessage =
|
|
340
|
-
sharedNotes.length > 0
|
|
341
|
-
? `Orchestration reached step limit.\n\nCurrent synthesis:\n${clampText(sharedNotes.join("\n\n"), 2000)}`
|
|
342
|
-
: "Orchestration stopped at safety step limit without a final response.";
|
|
343
|
-
}
|
|
344
|
-
if (!lastExecution.stdout.trim()) {
|
|
345
|
-
lastExecution = {
|
|
346
|
-
...lastExecution,
|
|
347
|
-
code: 0,
|
|
348
|
-
stdout: ensureTrailingNewline(finalMessage),
|
|
349
|
-
stderr: lastExecution.stderr
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
return {
|
|
353
|
-
finalMessage,
|
|
354
|
-
execution: lastExecution,
|
|
355
|
-
steps,
|
|
356
|
-
sessionGraph,
|
|
357
|
-
taskThreads: summarizeTaskThreads(taskThreads)
|
|
358
|
-
};
|
|
359
|
-
}
|
|
360
|
-
async executeAction(params) {
|
|
361
|
-
const action = params.action;
|
|
362
|
-
if (action.type === "finish" || action.type === "respond_user") {
|
|
363
|
-
const message = action.message.trim() || "Completed.";
|
|
364
|
-
params.logger.info("Completing orchestration with direct response.", {
|
|
365
|
-
actionType: action.type
|
|
366
|
-
});
|
|
367
|
-
params.stepLog.note = action.reason;
|
|
368
|
-
this.addRecentEvent(params.recentEvents, `Step ${params.step}: ${action.type}`);
|
|
369
|
-
return {
|
|
370
|
-
finalMessage: message,
|
|
371
|
-
execution: {
|
|
372
|
-
...(await this.buildSyntheticExecution(params.paths, DEFAULT_AGENT_ID)),
|
|
373
|
-
code: 0,
|
|
374
|
-
stdout: ensureTrailingNewline(message)
|
|
375
|
-
}
|
|
376
|
-
};
|
|
377
|
-
}
|
|
378
|
-
if (action.type === "read_workspace_file") {
|
|
379
|
-
const resolvedPath = this.resolveWorkspacePath({
|
|
380
|
-
paths: params.paths,
|
|
381
|
-
requestedPath: action.path,
|
|
382
|
-
workingPathHint: params.options.cwd
|
|
383
|
-
});
|
|
384
|
-
params.logger.info("Reading workspace file for orchestration context.", {
|
|
385
|
-
path: resolvedPath
|
|
386
|
-
});
|
|
387
|
-
const exists = await this.fileSystem.exists(resolvedPath);
|
|
388
|
-
const content = exists ? await this.fileSystem.readFile(resolvedPath) : `[MISSING] ${resolvedPath}`;
|
|
389
|
-
params.sharedNotes.push(clampText(`Read ${action.path}:\n${content}`, 2500));
|
|
390
|
-
params.stepLog.artifactIO = { readPath: resolvedPath };
|
|
391
|
-
this.addRecentEvent(params.recentEvents, `Read file ${action.path}`);
|
|
392
|
-
return {};
|
|
393
|
-
}
|
|
394
|
-
if (action.type === "write_workspace_file") {
|
|
395
|
-
const resolvedPath = this.resolveWorkspacePath({
|
|
396
|
-
paths: params.paths,
|
|
397
|
-
requestedPath: action.path,
|
|
398
|
-
workingPathHint: params.options.cwd
|
|
399
|
-
});
|
|
400
|
-
params.logger.info("Writing workspace file for orchestration context.", {
|
|
401
|
-
path: resolvedPath
|
|
402
|
-
});
|
|
403
|
-
await this.fileSystem.ensureDir(path.dirname(resolvedPath));
|
|
404
|
-
await this.fileSystem.writeFile(resolvedPath, ensureTrailingNewline(action.content));
|
|
405
|
-
params.stepLog.artifactIO = { writePath: resolvedPath };
|
|
406
|
-
this.addRecentEvent(params.recentEvents, `Wrote file ${action.path}`);
|
|
407
|
-
return {};
|
|
408
|
-
}
|
|
409
|
-
if (action.type === "install_skill") {
|
|
410
|
-
const targetAgentId = normalizeAgentId(action.targetAgentId ?? DEFAULT_AGENT_ID) || DEFAULT_AGENT_ID;
|
|
411
|
-
params.logger.info("Installing skill requested by orchestrator action.", {
|
|
412
|
-
targetAgentId,
|
|
413
|
-
skillName: action.skillName
|
|
414
|
-
});
|
|
415
|
-
const result = await this.skillService.installSkill(params.paths, {
|
|
416
|
-
scope: "agent",
|
|
417
|
-
agentId: targetAgentId,
|
|
418
|
-
skillName: action.skillName,
|
|
419
|
-
sourcePath: action.sourcePath,
|
|
420
|
-
description: action.description,
|
|
421
|
-
content: action.content
|
|
422
|
-
});
|
|
423
|
-
const installedFor = result.agentId || targetAgentId;
|
|
424
|
-
params.stepLog.note = `Installed skill ${result.skillId} for ${installedFor} (${result.source}).`;
|
|
425
|
-
params.sharedNotes.push(`Skill installed: ${result.skillId} for ${installedFor} from ${result.source} at ${result.installedPath}`);
|
|
426
|
-
this.addRecentEvent(params.recentEvents, `Installed skill ${result.skillId} for ${installedFor} (${result.source})`);
|
|
427
|
-
return {};
|
|
428
|
-
}
|
|
429
|
-
const targetAgentId = normalizeAgentId(action.targetAgentId);
|
|
430
|
-
const targetManifest = params.manifests.find((manifest) => manifest.agentId === targetAgentId);
|
|
431
|
-
if (!targetManifest || !isDiscoverableByOrchestrator(targetManifest)) {
|
|
432
|
-
const note = `Invalid delegation target "${action.targetAgentId}" (missing, non-receivable, or non-discoverable).`;
|
|
433
|
-
params.logger.warn("Invalid delegation target.", {
|
|
434
|
-
requestedTargetAgentId: action.targetAgentId
|
|
435
|
-
});
|
|
436
|
-
params.sharedNotes.push(note);
|
|
437
|
-
params.stepLog.note = note;
|
|
438
|
-
this.addRecentEvent(params.recentEvents, note);
|
|
439
|
-
return {};
|
|
440
|
-
}
|
|
441
|
-
const taskKey = resolveTaskKey(action.taskKey, targetAgentId, params.step);
|
|
442
|
-
const requestedSessionPolicy = action.sessionPolicy ?? "auto";
|
|
443
|
-
const existingThread = params.taskThreads.get(taskKey);
|
|
444
|
-
const canReuseThread = Boolean(existingThread && existingThread.agentId === targetAgentId);
|
|
445
|
-
const effectiveSessionPolicy = requestedSessionPolicy === "reuse" ? (canReuseThread ? "reuse" : "new") : requestedSessionPolicy;
|
|
446
|
-
const forceNewTaskSession = effectiveSessionPolicy === "new" || !canReuseThread;
|
|
447
|
-
if (requestedSessionPolicy === "reuse" && !canReuseThread) {
|
|
448
|
-
const note = `Requested reuse for task "${taskKey}" but no matching thread exists; creating a new session.`;
|
|
449
|
-
params.sharedNotes.push(note);
|
|
450
|
-
this.addRecentEvent(params.recentEvents, note);
|
|
451
|
-
params.logger.warn("Requested task session reuse but no matching thread was found.", {
|
|
452
|
-
taskKey,
|
|
453
|
-
targetAgentId
|
|
454
|
-
});
|
|
455
|
-
}
|
|
456
|
-
const targetRuntime = await this.providerService.getAgentRuntimeProfile(params.paths, targetAgentId);
|
|
457
|
-
const mode = action.mode ?? "hybrid";
|
|
458
|
-
params.logger.info("Delegating task to agent.", {
|
|
459
|
-
fromAgentId: DEFAULT_AGENT_ID,
|
|
460
|
-
toAgentId: targetAgentId,
|
|
461
|
-
targetWorkspaceAccess: targetRuntime.workspaceAccess,
|
|
462
|
-
mode,
|
|
463
|
-
reason: action.reason,
|
|
464
|
-
taskKey,
|
|
465
|
-
sessionPolicy: effectiveSessionPolicy
|
|
466
|
-
});
|
|
467
|
-
emitRunStatusEvent(params.options, {
|
|
468
|
-
stage: "delegation_started",
|
|
469
|
-
runId: params.runId,
|
|
470
|
-
timestamp: this.nowIso(),
|
|
471
|
-
step: params.step,
|
|
472
|
-
agentId: DEFAULT_AGENT_ID,
|
|
473
|
-
targetAgentId,
|
|
474
|
-
providerId: targetRuntime.providerId,
|
|
475
|
-
mode,
|
|
476
|
-
detail: action.reason
|
|
477
|
-
});
|
|
478
|
-
const handoffBaseDir = this.pathPort.join(params.paths.sessionsDir, params.runId);
|
|
479
|
-
let outboundPath;
|
|
480
|
-
if (mode === "artifacts" || mode === "hybrid") {
|
|
481
|
-
await this.fileSystem.ensureDir(handoffBaseDir);
|
|
482
|
-
outboundPath = this.pathPort.join(handoffBaseDir, `step-${String(params.step).padStart(2, "0")}-to-${targetAgentId}.md`);
|
|
483
|
-
const handoffDocument = renderHandoffDocument({
|
|
484
|
-
step: params.step,
|
|
485
|
-
userMessage: params.options.message,
|
|
486
|
-
delegateMessage: action.message,
|
|
487
|
-
expectedOutput: action.expectedOutput,
|
|
488
|
-
sharedNotes: params.sharedNotes
|
|
489
|
-
});
|
|
490
|
-
await this.fileSystem.writeFile(outboundPath, ensureTrailingNewline(handoffDocument));
|
|
491
|
-
params.stepLog.artifactIO = {
|
|
492
|
-
...params.stepLog.artifactIO,
|
|
493
|
-
writePath: outboundPath
|
|
494
|
-
};
|
|
495
|
-
}
|
|
496
|
-
const delegateMessage = renderDelegateMessage({
|
|
497
|
-
step: params.step,
|
|
498
|
-
userMessage: params.options.message,
|
|
499
|
-
delegateMessage: action.message,
|
|
500
|
-
expectedOutput: action.expectedOutput,
|
|
501
|
-
mode,
|
|
502
|
-
outboundPath,
|
|
503
|
-
exposeArtifactPath: targetRuntime.workspaceAccess === "internal",
|
|
504
|
-
sharedNotes: params.sharedNotes
|
|
505
|
-
});
|
|
506
|
-
params.logger.debug("Delegation message payload.", {
|
|
507
|
-
fromAgentId: DEFAULT_AGENT_ID,
|
|
508
|
-
toAgentId: targetAgentId,
|
|
509
|
-
taskKey,
|
|
510
|
-
request: delegateMessage,
|
|
511
|
-
mode,
|
|
512
|
-
outboundPath
|
|
513
|
-
});
|
|
514
|
-
const providerSessionId = effectiveSessionPolicy !== "new" && existingThread?.agentId === targetAgentId
|
|
515
|
-
? existingThread.providerSessionId
|
|
516
|
-
: undefined;
|
|
517
|
-
const delegateCall = await this.invokeAgentWithSession(params.paths, targetAgentId, {
|
|
518
|
-
message: delegateMessage,
|
|
519
|
-
env: params.options.env,
|
|
520
|
-
cwd: params.options.cwd,
|
|
521
|
-
sessionRef: `agent:${targetAgentId}:task:${taskKey}`,
|
|
522
|
-
forceNewSession: forceNewTaskSession,
|
|
523
|
-
providerSessionId,
|
|
524
|
-
forceNewProviderSession: forceNewTaskSession
|
|
525
|
-
}, { silent: true, runId: params.runId, step: params.step });
|
|
526
|
-
const responseText = delegateCall.execution.stdout.trim() ||
|
|
527
|
-
(delegateCall.execution.stderr.trim() ? `[stderr] ${delegateCall.execution.stderr.trim()}` : "");
|
|
528
|
-
params.logger.debug("Delegation response payload.", {
|
|
529
|
-
fromAgentId: DEFAULT_AGENT_ID,
|
|
530
|
-
toAgentId: targetAgentId,
|
|
531
|
-
code: delegateCall.execution.code,
|
|
532
|
-
providerId: delegateCall.execution.providerId,
|
|
533
|
-
response: responseText
|
|
534
|
-
});
|
|
535
|
-
let inboundPath;
|
|
536
|
-
if (mode === "artifacts" || mode === "hybrid") {
|
|
537
|
-
await this.fileSystem.ensureDir(handoffBaseDir);
|
|
538
|
-
inboundPath = this.pathPort.join(handoffBaseDir, `step-${String(params.step).padStart(2, "0")}-from-${targetAgentId}.md`);
|
|
539
|
-
await this.fileSystem.writeFile(inboundPath, ensureTrailingNewline(responseText || "(empty response)"));
|
|
540
|
-
params.stepLog.artifactIO = {
|
|
541
|
-
...params.stepLog.artifactIO,
|
|
542
|
-
readPath: inboundPath
|
|
543
|
-
};
|
|
544
|
-
}
|
|
545
|
-
params.stepLog.agentCall = {
|
|
546
|
-
targetAgentId,
|
|
547
|
-
taskKey,
|
|
548
|
-
sessionPolicy: effectiveSessionPolicy,
|
|
549
|
-
request: delegateMessage,
|
|
550
|
-
response: responseText,
|
|
551
|
-
code: delegateCall.execution.code,
|
|
552
|
-
providerId: delegateCall.execution.providerId,
|
|
553
|
-
sessionKey: delegateCall.session?.sessionKey,
|
|
554
|
-
sessionId: delegateCall.session?.sessionId,
|
|
555
|
-
providerSessionId: delegateCall.execution.providerSessionId,
|
|
556
|
-
workingTreeEffect: delegateCall.workingTreeEffect
|
|
557
|
-
};
|
|
558
|
-
addSessionNode(params.sessionGraph, targetAgentId, delegateCall.session, delegateCall.execution);
|
|
559
|
-
upsertTaskThread(params.taskThreads, {
|
|
560
|
-
taskKey,
|
|
561
|
-
agentId: targetAgentId,
|
|
562
|
-
createdStep: params.step,
|
|
563
|
-
updatedStep: params.step,
|
|
564
|
-
providerId: delegateCall.execution.providerId,
|
|
565
|
-
providerSessionId: delegateCall.execution.providerSessionId,
|
|
566
|
-
sessionKey: delegateCall.session?.sessionKey,
|
|
567
|
-
sessionId: delegateCall.session?.sessionId,
|
|
568
|
-
lastResponse: summarizeText(responseText || "(no response)")
|
|
569
|
-
});
|
|
570
|
-
params.sessionGraph.edges.push({
|
|
571
|
-
fromAgentId: DEFAULT_AGENT_ID,
|
|
572
|
-
toAgentId: targetAgentId,
|
|
573
|
-
reason: action.reason || params.stepLog.plannerDecision.rationale
|
|
574
|
-
});
|
|
575
|
-
const delegationFailure = summarizeDelegationFailure({
|
|
576
|
-
targetAgentId,
|
|
577
|
-
providerId: delegateCall.execution.providerId,
|
|
578
|
-
code: delegateCall.execution.code,
|
|
579
|
-
responseText,
|
|
580
|
-
workingTreeEffect: delegateCall.workingTreeEffect
|
|
581
|
-
});
|
|
582
|
-
if (delegationFailure) {
|
|
583
|
-
params.stepLog.note = delegationFailure.message;
|
|
584
|
-
this.addRecentEvent(params.recentEvents, delegationFailure.message);
|
|
585
|
-
params.sharedNotes.push(clampText(delegationFailure.message, 1200));
|
|
586
|
-
params.logger.warn("Delegation failed; stopping orchestration loop.", {
|
|
587
|
-
targetAgentId,
|
|
588
|
-
providerId: delegateCall.execution.providerId,
|
|
589
|
-
code: delegateCall.execution.code,
|
|
590
|
-
failureReason: delegationFailure.reason
|
|
591
|
-
});
|
|
592
|
-
return {
|
|
593
|
-
finalMessage: delegationFailure.message,
|
|
594
|
-
execution: {
|
|
595
|
-
...delegateCall.execution,
|
|
596
|
-
code: delegateCall.execution.code !== 0 ? delegateCall.execution.code : 1,
|
|
597
|
-
stdout: ensureTrailingNewline(delegationFailure.message)
|
|
598
|
-
}
|
|
599
|
-
};
|
|
600
|
-
}
|
|
601
|
-
const note = `Delegated to ${targetAgentId} [task:${taskKey}]: ${summarizeText(responseText || "(no response)")}`;
|
|
602
|
-
params.sharedNotes.push(clampText(note, 2000));
|
|
603
|
-
this.addRecentEvent(params.recentEvents, note);
|
|
604
|
-
if (delegateCall.workingTreeEffect && delegateCall.workingTreeEffect.enabled) {
|
|
605
|
-
const effectNote = `Working tree effect (${targetAgentId}): ${delegateCall.workingTreeEffect.summary}`;
|
|
606
|
-
params.sharedNotes.push(clampText(effectNote, 1200));
|
|
607
|
-
this.addRecentEvent(params.recentEvents, effectNote);
|
|
608
|
-
}
|
|
609
|
-
return {
|
|
610
|
-
execution: delegateCall.execution
|
|
611
|
-
};
|
|
612
|
-
}
|
|
613
|
-
addRecentEvent(events, value) {
|
|
614
|
-
events.push(summarizeText(value));
|
|
615
|
-
while (events.length > RECENT_EVENTS_WINDOW) {
|
|
616
|
-
events.shift();
|
|
617
|
-
}
|
|
618
|
-
}
|
|
619
|
-
resolveWorkspacePath(input) {
|
|
620
|
-
const { requestedPath, workingPathHint } = input;
|
|
621
|
-
const normalized = requestedPath.replace(/\\/g, "/").trim();
|
|
622
|
-
const runWorkingPath = resolveInvocationWorkingPath(workingPathHint);
|
|
623
|
-
const unsafeSegments = normalized.split("/").filter((segment) => segment === "..");
|
|
624
|
-
if (unsafeSegments.length > 0) {
|
|
625
|
-
return this.pathPort.join(runWorkingPath, ".opengoat", "coordination", "unsafe-path-blocked.md");
|
|
626
|
-
}
|
|
627
|
-
const relative = normalized.replace(/^\/+/, "");
|
|
628
|
-
return this.pathPort.join(runWorkingPath, relative || ".opengoat/coordination/context.md");
|
|
629
81
|
}
|
|
630
82
|
async invokeAgentWithSession(paths, agentId, options, behavior = {}) {
|
|
631
83
|
const sessionAgentId = normalizeAgentId(behavior.sessionAgentId ?? agentId) || DEFAULT_AGENT_ID;
|
|
632
|
-
this.logger.debug("Preparing agent invocation with session context.", {
|
|
633
|
-
agentId,
|
|
634
|
-
sessionAgentId,
|
|
635
|
-
message: options.message,
|
|
636
|
-
sessionRef: options.sessionRef,
|
|
637
|
-
forceNewSession: options.forceNewSession,
|
|
638
|
-
disableSession: options.disableSession,
|
|
639
|
-
providerSessionId: options.providerSessionId,
|
|
640
|
-
forceNewProviderSession: options.forceNewProviderSession
|
|
641
|
-
});
|
|
642
84
|
const preparedSession = await this.sessionService.prepareRunSession(paths, sessionAgentId, {
|
|
643
85
|
sessionRef: options.sessionRef,
|
|
644
86
|
forceNew: options.forceNewSession,
|
|
645
87
|
disableSession: options.disableSession,
|
|
646
|
-
|
|
88
|
+
projectPath: options.cwd,
|
|
647
89
|
userMessage: options.message
|
|
648
90
|
});
|
|
649
|
-
const invokeOptions = sanitizeProviderInvokeOptions(
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
}
|
|
653
|
-
if (
|
|
654
|
-
|
|
655
|
-
|
|
91
|
+
const invokeOptions = sanitizeProviderInvokeOptions(options);
|
|
92
|
+
if (behavior.runId) {
|
|
93
|
+
invokeOptions.idempotencyKey = behavior.runId;
|
|
94
|
+
}
|
|
95
|
+
if (preparedSession.enabled) {
|
|
96
|
+
invokeOptions.providerSessionId = preparedSession.info.sessionId;
|
|
97
|
+
invokeOptions.cwd = resolveInvocationCwd(invokeOptions.cwd, preparedSession.info.projectPath);
|
|
98
|
+
const projectContextPrompt = buildProjectContextSystemPrompt(preparedSession.info);
|
|
99
|
+
if (projectContextPrompt) {
|
|
100
|
+
invokeOptions.systemPrompt = mergeSystemPrompts(invokeOptions.systemPrompt, projectContextPrompt);
|
|
101
|
+
}
|
|
656
102
|
}
|
|
657
|
-
const workingPath = preparedSession.enabled ? preparedSession.info.workingPath : resolveInvocationWorkingPath(options.cwd);
|
|
658
|
-
const beforeSnapshot = await this.captureWorkingTreeSnapshot(workingPath);
|
|
659
103
|
const execution = await this.providerService.invokeAgent(paths, agentId, invokeOptions, {
|
|
660
104
|
runId: behavior.runId,
|
|
661
105
|
step: behavior.step,
|
|
@@ -683,33 +127,19 @@ export class OrchestrationService {
|
|
|
683
127
|
}
|
|
684
128
|
}
|
|
685
129
|
});
|
|
686
|
-
const afterSnapshot = await this.captureWorkingTreeSnapshot(workingPath);
|
|
687
|
-
const workingTreeEffect = summarizeWorkingTreeEffect(beforeSnapshot, afterSnapshot);
|
|
688
|
-
this.logger.debug("Agent invocation execution returned.", {
|
|
689
|
-
agentId,
|
|
690
|
-
sessionAgentId,
|
|
691
|
-
providerId: execution.providerId,
|
|
692
|
-
code: execution.code,
|
|
693
|
-
stdout: execution.stdout,
|
|
694
|
-
stderr: execution.stderr,
|
|
695
|
-
providerSessionId: execution.providerSessionId,
|
|
696
|
-
workingTreeEffect: workingTreeEffect?.summary
|
|
697
|
-
});
|
|
698
130
|
if (!preparedSession.enabled) {
|
|
699
131
|
return {
|
|
700
132
|
execution,
|
|
701
|
-
workingTreeEffect,
|
|
702
133
|
session: undefined
|
|
703
134
|
};
|
|
704
135
|
}
|
|
705
136
|
const assistantContent = execution.stdout.trim() ||
|
|
706
137
|
(execution.stderr.trim()
|
|
707
|
-
? `[
|
|
708
|
-
: `[
|
|
138
|
+
? `[Runtime error code ${execution.code}] ${execution.stderr.trim()}`
|
|
139
|
+
: `[Runtime exited with code ${execution.code}]`);
|
|
709
140
|
const postRunCompaction = await this.sessionService.recordAssistantReply(paths, preparedSession.info, assistantContent);
|
|
710
141
|
return {
|
|
711
142
|
execution,
|
|
712
|
-
workingTreeEffect,
|
|
713
143
|
session: {
|
|
714
144
|
...preparedSession.info,
|
|
715
145
|
preRunCompactionApplied: preparedSession.compactionApplied,
|
|
@@ -725,7 +155,6 @@ export class OrchestrationService {
|
|
|
725
155
|
completedAt: params.completedAt,
|
|
726
156
|
entryAgentId: params.entryAgentId,
|
|
727
157
|
userMessage: params.userMessage,
|
|
728
|
-
routing: params.routing,
|
|
729
158
|
session: params.session
|
|
730
159
|
? {
|
|
731
160
|
...params.session,
|
|
@@ -740,110 +169,17 @@ export class OrchestrationService {
|
|
|
740
169
|
stdout: params.execution.stdout,
|
|
741
170
|
stderr: params.execution.stderr,
|
|
742
171
|
durationMs: params.durationMs
|
|
743
|
-
},
|
|
744
|
-
orchestration: params.orchestration
|
|
745
|
-
};
|
|
746
|
-
const tracePath = await this.writeTrace(params.paths, trace);
|
|
747
|
-
return { tracePath, trace };
|
|
748
|
-
}
|
|
749
|
-
async captureWorkingTreeSnapshot(workingPath) {
|
|
750
|
-
if (!this.commandRunner) {
|
|
751
|
-
return undefined;
|
|
752
|
-
}
|
|
753
|
-
if (!(await this.fileSystem.exists(workingPath))) {
|
|
754
|
-
return undefined;
|
|
755
|
-
}
|
|
756
|
-
try {
|
|
757
|
-
const result = await this.commandRunner.run({
|
|
758
|
-
command: "git",
|
|
759
|
-
args: ["status", "--porcelain=v1", "--untracked-files=all"],
|
|
760
|
-
cwd: workingPath
|
|
761
|
-
});
|
|
762
|
-
if (result.code !== 0) {
|
|
763
|
-
return undefined;
|
|
764
172
|
}
|
|
765
|
-
const entries = parsePorcelainEntries(result.stdout);
|
|
766
|
-
return {
|
|
767
|
-
enabled: true,
|
|
768
|
-
workingPath,
|
|
769
|
-
entries
|
|
770
|
-
};
|
|
771
|
-
}
|
|
772
|
-
catch {
|
|
773
|
-
return undefined;
|
|
774
|
-
}
|
|
775
|
-
}
|
|
776
|
-
async buildSyntheticExecution(paths, agentId) {
|
|
777
|
-
const binding = await this.providerService.getAgentProvider(paths, agentId);
|
|
778
|
-
return {
|
|
779
|
-
...binding,
|
|
780
|
-
code: 0,
|
|
781
|
-
stdout: "",
|
|
782
|
-
stderr: ""
|
|
783
173
|
};
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
await this.fileSystem.ensureDir(paths.runsDir);
|
|
787
|
-
const tracePath = this.pathPort.join(paths.runsDir, `${trace.runId}.json`);
|
|
174
|
+
await this.fileSystem.ensureDir(params.paths.runsDir);
|
|
175
|
+
const tracePath = this.pathPort.join(params.paths.runsDir, `${trace.runId}.json`);
|
|
788
176
|
await this.fileSystem.writeFile(tracePath, `${JSON.stringify(trace, null, 2)}\n`);
|
|
789
|
-
return tracePath;
|
|
177
|
+
return { tracePath, trace };
|
|
790
178
|
}
|
|
791
179
|
}
|
|
792
180
|
function generateRunId() {
|
|
793
181
|
return randomUUID().toLowerCase();
|
|
794
182
|
}
|
|
795
|
-
function resolveInvocationWorkingPath(cwd) {
|
|
796
|
-
const normalized = cwd?.trim();
|
|
797
|
-
if (normalized) {
|
|
798
|
-
return path.resolve(normalized);
|
|
799
|
-
}
|
|
800
|
-
return process.cwd();
|
|
801
|
-
}
|
|
802
|
-
function parsePorcelainEntries(stdout) {
|
|
803
|
-
const lines = stdout
|
|
804
|
-
.split("\n")
|
|
805
|
-
.map((line) => line.trimEnd())
|
|
806
|
-
.filter(Boolean);
|
|
807
|
-
return lines.map((line) => {
|
|
808
|
-
const status = line.slice(0, 2);
|
|
809
|
-
const rawPath = line.length > 3 ? line.slice(3).trim() : "";
|
|
810
|
-
const finalPath = rawPath.includes(" -> ") ? rawPath.split(" -> ").at(-1)?.trim() || rawPath : rawPath;
|
|
811
|
-
return {
|
|
812
|
-
raw: `${status} ${finalPath}`.trim(),
|
|
813
|
-
path: finalPath
|
|
814
|
-
};
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
function summarizeWorkingTreeEffect(beforeSnapshot, afterSnapshot) {
|
|
818
|
-
if (!beforeSnapshot || !afterSnapshot || !beforeSnapshot.enabled || !afterSnapshot.enabled) {
|
|
819
|
-
return undefined;
|
|
820
|
-
}
|
|
821
|
-
const beforeMap = new Map(beforeSnapshot.entries.map((entry) => [entry.path, entry.raw]));
|
|
822
|
-
const afterMap = new Map(afterSnapshot.entries.map((entry) => [entry.path, entry.raw]));
|
|
823
|
-
const touched = new Set();
|
|
824
|
-
for (const [path, raw] of afterMap.entries()) {
|
|
825
|
-
if (beforeMap.get(path) !== raw) {
|
|
826
|
-
touched.add(path);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
for (const [path, raw] of beforeMap.entries()) {
|
|
830
|
-
if (afterMap.get(path) !== raw) {
|
|
831
|
-
touched.add(path);
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
const touchedPaths = [...touched].sort((left, right) => left.localeCompare(right));
|
|
835
|
-
const summary = touchedPaths.length === 0
|
|
836
|
-
? "No tracked changes detected."
|
|
837
|
-
: `Touched ${touchedPaths.length} path(s): ${touchedPaths.slice(0, 8).join(", ")}${touchedPaths.length > 8 ? ", ..." : ""}`;
|
|
838
|
-
return {
|
|
839
|
-
enabled: true,
|
|
840
|
-
workingPath: afterSnapshot.workingPath,
|
|
841
|
-
beforeEntries: beforeSnapshot.entries.length,
|
|
842
|
-
afterEntries: afterSnapshot.entries.length,
|
|
843
|
-
touchedPaths,
|
|
844
|
-
summary
|
|
845
|
-
};
|
|
846
|
-
}
|
|
847
183
|
function resolveEntryAgentId(entryAgentId, manifests) {
|
|
848
184
|
const normalizedEntryAgentId = normalizeAgentId(entryAgentId) || DEFAULT_AGENT_ID;
|
|
849
185
|
if (manifests.some((manifest) => manifest.agentId === normalizedEntryAgentId)) {
|
|
@@ -862,183 +198,35 @@ function sanitizeProviderInvokeOptions(options) {
|
|
|
862
198
|
delete sanitized.sessionRef;
|
|
863
199
|
delete sanitized.forceNewSession;
|
|
864
200
|
delete sanitized.disableSession;
|
|
865
|
-
delete sanitized.directAgentSession;
|
|
866
201
|
delete sanitized.hooks;
|
|
867
202
|
return sanitized;
|
|
868
203
|
}
|
|
869
|
-
function
|
|
870
|
-
const
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
"Original user request:",
|
|
874
|
-
params.userMessage,
|
|
875
|
-
"",
|
|
876
|
-
"Delegation instruction:",
|
|
877
|
-
params.delegateMessage,
|
|
878
|
-
""
|
|
879
|
-
];
|
|
880
|
-
if (params.expectedOutput?.trim()) {
|
|
881
|
-
lines.push("Expected output:", params.expectedOutput.trim(), "");
|
|
882
|
-
}
|
|
883
|
-
if (params.sharedNotes.length > 0) {
|
|
884
|
-
lines.push("Shared notes from previous steps:", clampText(params.sharedNotes.join("\n\n"), 4000), "");
|
|
885
|
-
}
|
|
886
|
-
if ((params.mode === "artifacts" || params.mode === "hybrid") && params.outboundPath && params.exposeArtifactPath) {
|
|
887
|
-
lines.push(`Coordination file: ${params.outboundPath}`, "You may use this markdown artifact for durable handoff context.", "");
|
|
888
|
-
}
|
|
889
|
-
else if (params.mode === "artifacts" || params.mode === "hybrid") {
|
|
890
|
-
lines.push("Coordination artifacts are managed internally by the orchestrator.", "");
|
|
204
|
+
function resolveInvocationCwd(requestedCwd, sessionProjectPath) {
|
|
205
|
+
const normalizedRequested = requestedCwd?.trim();
|
|
206
|
+
if (normalizedRequested) {
|
|
207
|
+
return normalizedRequested;
|
|
891
208
|
}
|
|
892
|
-
|
|
893
|
-
return lines.join("\n");
|
|
209
|
+
return sessionProjectPath;
|
|
894
210
|
}
|
|
895
|
-
function
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
"## User Request",
|
|
900
|
-
params.userMessage,
|
|
901
|
-
"",
|
|
902
|
-
"## Delegation Instruction",
|
|
903
|
-
params.delegateMessage,
|
|
904
|
-
"",
|
|
905
|
-
"## Expected Output",
|
|
906
|
-
params.expectedOutput?.trim() || "(not specified)",
|
|
907
|
-
"",
|
|
908
|
-
"## Prior Notes",
|
|
909
|
-
params.sharedNotes.length > 0 ? clampText(params.sharedNotes.join("\n\n"), 4000) : "(none)"
|
|
910
|
-
].join("\n");
|
|
911
|
-
}
|
|
912
|
-
function addSessionNode(graph, agentId, session, execution) {
|
|
913
|
-
if (!session) {
|
|
914
|
-
return;
|
|
915
|
-
}
|
|
916
|
-
const exists = graph.nodes.some((node) => node.agentId === agentId &&
|
|
917
|
-
node.providerId === execution?.providerId &&
|
|
918
|
-
node.sessionKey === session.sessionKey &&
|
|
919
|
-
node.sessionId === session.sessionId &&
|
|
920
|
-
node.providerSessionId === execution?.providerSessionId);
|
|
921
|
-
if (exists) {
|
|
922
|
-
return;
|
|
923
|
-
}
|
|
924
|
-
graph.nodes.push({
|
|
925
|
-
agentId,
|
|
926
|
-
providerId: execution?.providerId,
|
|
927
|
-
sessionKey: session.sessionKey,
|
|
928
|
-
sessionId: session.sessionId,
|
|
929
|
-
providerSessionId: execution?.providerSessionId
|
|
930
|
-
});
|
|
931
|
-
}
|
|
932
|
-
function resolveTaskKey(actionTaskKey, targetAgentId, step) {
|
|
933
|
-
const explicit = actionTaskKey?.trim().toLowerCase();
|
|
934
|
-
if (explicit) {
|
|
935
|
-
return explicit;
|
|
936
|
-
}
|
|
937
|
-
return `${targetAgentId}-step-${String(step).padStart(2, "0")}`;
|
|
938
|
-
}
|
|
939
|
-
function upsertTaskThread(threads, next) {
|
|
940
|
-
const existing = threads.get(next.taskKey);
|
|
941
|
-
if (!existing) {
|
|
942
|
-
threads.set(next.taskKey, next);
|
|
943
|
-
return;
|
|
944
|
-
}
|
|
945
|
-
threads.set(next.taskKey, {
|
|
946
|
-
...existing,
|
|
947
|
-
...next,
|
|
948
|
-
createdStep: existing.createdStep,
|
|
949
|
-
updatedStep: next.updatedStep
|
|
950
|
-
});
|
|
951
|
-
}
|
|
952
|
-
function summarizeTaskThreads(threads) {
|
|
953
|
-
return [...threads.values()]
|
|
954
|
-
.sort((left, right) => left.createdStep - right.createdStep)
|
|
955
|
-
.map((thread) => ({
|
|
956
|
-
taskKey: thread.taskKey,
|
|
957
|
-
agentId: thread.agentId,
|
|
958
|
-
providerId: thread.providerId,
|
|
959
|
-
providerSessionId: thread.providerSessionId,
|
|
960
|
-
sessionKey: thread.sessionKey,
|
|
961
|
-
sessionId: thread.sessionId,
|
|
962
|
-
createdStep: thread.createdStep,
|
|
963
|
-
updatedStep: thread.updatedStep,
|
|
964
|
-
lastResponse: thread.lastResponse
|
|
965
|
-
}));
|
|
966
|
-
}
|
|
967
|
-
function summarizeText(value) {
|
|
968
|
-
const normalized = value.replace(/\s+/g, " ").trim();
|
|
969
|
-
if (normalized.length <= 180) {
|
|
970
|
-
return normalized;
|
|
971
|
-
}
|
|
972
|
-
return `${normalized.slice(0, 177)}...`;
|
|
973
|
-
}
|
|
974
|
-
function ensureTrailingNewline(value) {
|
|
975
|
-
return value.endsWith("\n") ? value : `${value}\n`;
|
|
976
|
-
}
|
|
977
|
-
function renderPlannerProviderFailureMessage(providerId, code, detailsRaw) {
|
|
978
|
-
const details = detailsRaw.trim();
|
|
979
|
-
const summary = details
|
|
980
|
-
? `\n\nProvider error details:\n${clampText(details, 1200)}`
|
|
981
|
-
: "";
|
|
982
|
-
return [
|
|
983
|
-
`The orchestrator provider (${providerId}) failed while planning (exit code ${code}).`,
|
|
984
|
-
"Open provider setup in the desktop app and verify credentials/model configuration.",
|
|
985
|
-
summary
|
|
986
|
-
]
|
|
987
|
-
.join("\n")
|
|
988
|
-
.trim();
|
|
989
|
-
}
|
|
990
|
-
function summarizeDelegationFailure(params) {
|
|
991
|
-
if (params.code !== 0) {
|
|
992
|
-
const detail = summarizeText(params.responseText || "(no provider details)");
|
|
993
|
-
return {
|
|
994
|
-
reason: "provider_error",
|
|
995
|
-
message: [
|
|
996
|
-
`The delegated agent "${params.targetAgentId}" failed via provider "${params.providerId}" (exit code ${params.code}).`,
|
|
997
|
-
`Details: ${detail}`
|
|
998
|
-
].join("\n")
|
|
999
|
-
};
|
|
1000
|
-
}
|
|
1001
|
-
const blockReason = extractBlockedNoProgressReason(params.responseText, params.workingTreeEffect);
|
|
1002
|
-
if (!blockReason) {
|
|
1003
|
-
return undefined;
|
|
1004
|
-
}
|
|
1005
|
-
return {
|
|
1006
|
-
reason: "blocked_no_progress",
|
|
1007
|
-
message: [
|
|
1008
|
-
`The delegated agent "${params.targetAgentId}" could not continue this request.`,
|
|
1009
|
-
blockReason
|
|
1010
|
-
].join("\n")
|
|
1011
|
-
};
|
|
1012
|
-
}
|
|
1013
|
-
function extractBlockedNoProgressReason(responseText, workingTreeEffect) {
|
|
1014
|
-
const normalized = responseText.toLowerCase();
|
|
1015
|
-
if (!normalized.trim()) {
|
|
1016
|
-
return undefined;
|
|
1017
|
-
}
|
|
1018
|
-
const toolUnavailableSignals = [
|
|
1019
|
-
/write_file/,
|
|
1020
|
-
/run_shell_command/,
|
|
1021
|
-
/tool(?:s)? (?:is|are)?\s*(?:not found|unavailable|missing|not listed|not available)/,
|
|
1022
|
-
/cannot create .* file/,
|
|
1023
|
-
/i(?:'| a)?m stuck/,
|
|
1024
|
-
/unable to proceed/
|
|
1025
|
-
];
|
|
1026
|
-
const hasToolSignal = toolUnavailableSignals.some((pattern) => pattern.test(normalized));
|
|
1027
|
-
if (!hasToolSignal) {
|
|
211
|
+
function buildProjectContextSystemPrompt(session) {
|
|
212
|
+
const projectPath = session.projectPath.trim();
|
|
213
|
+
const workspacePath = session.workspacePath.trim();
|
|
214
|
+
if (!projectPath || projectPath === workspacePath) {
|
|
1028
215
|
return undefined;
|
|
1029
216
|
}
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
217
|
+
return [
|
|
218
|
+
"OpenGoat session context:",
|
|
219
|
+
`Session project path: ${projectPath}`,
|
|
220
|
+
`Agent workspace path: ${workspacePath}`,
|
|
221
|
+
"Use the session project path for project files. Prefer absolute paths under that directory or `cd` into it before running commands.",
|
|
222
|
+
"Avoid creating task files in the agent workspace unless the user explicitly asks for it."
|
|
223
|
+
].join("\n");
|
|
1035
224
|
}
|
|
1036
|
-
function
|
|
1037
|
-
|
|
1038
|
-
|
|
225
|
+
function mergeSystemPrompts(current, extra) {
|
|
226
|
+
const normalizedCurrent = current?.trim();
|
|
227
|
+
if (!normalizedCurrent) {
|
|
228
|
+
return extra;
|
|
1039
229
|
}
|
|
1040
|
-
|
|
1041
|
-
const tail = value.slice(-(maxChars - head.length - 20));
|
|
1042
|
-
return `${head}\n...[truncated]...\n${tail}`;
|
|
230
|
+
return `${normalizedCurrent}\n\n${extra}`;
|
|
1043
231
|
}
|
|
1044
232
|
//# sourceMappingURL=orchestration.service.js.map
|