@opengoat/core 2026.2.9 → 2026.2.13

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.
Files changed (193) hide show
  1. package/README.md +3 -3
  2. package/dist/core/acp/application/acp-agent.js +4 -8
  3. package/dist/core/acp/application/acp-agent.js.map +1 -1
  4. package/dist/core/agents/application/agent-manifest.service.d.ts +1 -4
  5. package/dist/core/agents/application/agent-manifest.service.js +39 -52
  6. package/dist/core/agents/application/agent-manifest.service.js.map +1 -1
  7. package/dist/core/agents/application/agent.service.d.ts +42 -4
  8. package/dist/core/agents/application/agent.service.js +439 -55
  9. package/dist/core/agents/application/agent.service.js.map +1 -1
  10. package/dist/core/agents/domain/agent-manifest.d.ts +10 -4
  11. package/dist/core/agents/domain/agent-manifest.js +118 -25
  12. package/dist/core/agents/domain/agent-manifest.js.map +1 -1
  13. package/dist/core/agents/index.d.ts +1 -3
  14. package/dist/core/agents/index.js +1 -3
  15. package/dist/core/agents/index.js.map +1 -1
  16. package/dist/core/boards/application/board.service.d.ts +64 -0
  17. package/dist/core/boards/application/board.service.js +590 -0
  18. package/dist/core/boards/application/board.service.js.map +1 -0
  19. package/dist/core/boards/domain/board.d.ts +30 -0
  20. package/dist/core/boards/domain/board.js +2 -0
  21. package/dist/core/boards/domain/board.js.map +1 -0
  22. package/dist/core/boards/index.d.ts +2 -0
  23. package/dist/core/boards/index.js +2 -0
  24. package/dist/core/boards/index.js.map +1 -0
  25. package/dist/core/bootstrap/application/bootstrap.service.d.ts +1 -2
  26. package/dist/core/bootstrap/application/bootstrap.service.js +14 -19
  27. package/dist/core/bootstrap/application/bootstrap.service.js.map +1 -1
  28. package/dist/core/domain/agent-id.d.ts +1 -1
  29. package/dist/core/domain/agent-id.js +1 -1
  30. package/dist/core/domain/agent-id.js.map +1 -1
  31. package/dist/core/domain/agent.d.ts +31 -8
  32. package/dist/core/opengoat/application/opengoat.service.d.ts +106 -27
  33. package/dist/core/opengoat/application/opengoat.service.js +1006 -136
  34. package/dist/core/opengoat/application/opengoat.service.js.map +1 -1
  35. package/dist/core/opengoat/index.d.ts +1 -0
  36. package/dist/core/orchestration/application/orchestration.service.d.ts +8 -21
  37. package/dist/core/orchestration/application/orchestration.service.js +59 -871
  38. package/dist/core/orchestration/application/orchestration.service.js.map +1 -1
  39. package/dist/core/orchestration/application/routing.service.js +10 -8
  40. package/dist/core/orchestration/application/routing.service.js.map +1 -1
  41. package/dist/core/orchestration/domain/routing.d.ts +0 -17
  42. package/dist/core/orchestration/domain/run-events.d.ts +1 -1
  43. package/dist/core/orchestration/index.d.ts +0 -2
  44. package/dist/core/orchestration/index.js +0 -1
  45. package/dist/core/orchestration/index.js.map +1 -1
  46. package/dist/core/providers/application/provider.service.d.ts +15 -32
  47. package/dist/core/providers/application/provider.service.js +115 -201
  48. package/dist/core/providers/application/provider.service.js.map +1 -1
  49. package/dist/core/providers/cli-provider.d.ts +1 -0
  50. package/dist/core/providers/cli-provider.js +66 -1
  51. package/dist/core/providers/cli-provider.js.map +1 -1
  52. package/dist/core/providers/image-input.d.ts +16 -0
  53. package/dist/core/providers/image-input.js +158 -0
  54. package/dist/core/providers/image-input.js.map +1 -0
  55. package/dist/core/providers/index.d.ts +1 -7
  56. package/dist/core/providers/index.js +0 -13
  57. package/dist/core/providers/index.js.map +1 -1
  58. package/dist/core/providers/loader.js +1 -95
  59. package/dist/core/providers/loader.js.map +1 -1
  60. package/dist/core/providers/providers/openclaw/provider.js +213 -32
  61. package/dist/core/providers/providers/openclaw/provider.js.map +1 -1
  62. package/dist/core/providers/types.d.ts +8 -3
  63. package/dist/core/scenarios/application/scenario-runner.service.d.ts +0 -1
  64. package/dist/core/scenarios/application/scenario-runner.service.js +30 -87
  65. package/dist/core/scenarios/application/scenario-runner.service.js.map +1 -1
  66. package/dist/core/scenarios/domain/scenario.d.ts +0 -15
  67. package/dist/core/sessions/application/session.service.d.ts +10 -4
  68. package/dist/core/sessions/application/session.service.js +87 -89
  69. package/dist/core/sessions/application/session.service.js.map +1 -1
  70. package/dist/core/sessions/domain/session.d.ts +3 -3
  71. package/dist/core/sessions/domain/transcript.d.ts +1 -1
  72. package/dist/core/sessions/index.d.ts +1 -1
  73. package/dist/core/sessions/index.js.map +1 -1
  74. package/dist/core/skills/application/skill.service.d.ts +2 -3
  75. package/dist/core/skills/application/skill.service.js +153 -56
  76. package/dist/core/skills/application/skill.service.js.map +1 -1
  77. package/dist/core/skills/domain/skill.d.ts +2 -2
  78. package/dist/core/skills/domain/skill.js +4 -2
  79. package/dist/core/skills/domain/skill.js.map +1 -1
  80. package/dist/core/templates/assets/ceo/AGENTS.md +20 -0
  81. package/dist/core/templates/assets/ceo/ROLE.md +13 -0
  82. package/dist/core/templates/assets/ceo/SOUL.md +15 -0
  83. package/dist/core/templates/assets/skills/og-board-individual/SKILL.md +148 -0
  84. package/dist/core/templates/assets/skills/og-board-manager/SKILL.md +140 -0
  85. package/dist/core/templates/default-templates.d.ts +12 -14
  86. package/dist/core/templates/default-templates.js +81 -213
  87. package/dist/core/templates/default-templates.js.map +1 -1
  88. package/dist/index.d.ts +1 -4
  89. package/dist/index.js +1 -4
  90. package/dist/index.js.map +1 -1
  91. package/package.json +16 -13
  92. package/dist/core/agents/application/workspace-context.service.d.ts +0 -28
  93. package/dist/core/agents/application/workspace-context.service.js +0 -157
  94. package/dist/core/agents/application/workspace-context.service.js.map +0 -1
  95. package/dist/core/agents/domain/workspace-context.d.ts +0 -13
  96. package/dist/core/agents/domain/workspace-context.js +0 -14
  97. package/dist/core/agents/domain/workspace-context.js.map +0 -1
  98. package/dist/core/gateway/domain/protocol.d.ts +0 -113
  99. package/dist/core/gateway/domain/protocol.js +0 -394
  100. package/dist/core/gateway/domain/protocol.js.map +0 -1
  101. package/dist/core/gateway/index.d.ts +0 -2
  102. package/dist/core/gateway/index.js +0 -2
  103. package/dist/core/gateway/index.js.map +0 -1
  104. package/dist/core/llm/application/vercel-ai-text-runtime.d.ts +0 -26
  105. package/dist/core/llm/application/vercel-ai-text-runtime.js +0 -223
  106. package/dist/core/llm/application/vercel-ai-text-runtime.js.map +0 -1
  107. package/dist/core/llm/domain/text-runtime.d.ts +0 -22
  108. package/dist/core/llm/domain/text-runtime.js +0 -2
  109. package/dist/core/llm/domain/text-runtime.js.map +0 -1
  110. package/dist/core/llm/index.d.ts +0 -2
  111. package/dist/core/llm/index.js +0 -2
  112. package/dist/core/llm/index.js.map +0 -1
  113. package/dist/core/orchestration/application/orchestration-planner.service.d.ts +0 -28
  114. package/dist/core/orchestration/application/orchestration-planner.service.js +0 -279
  115. package/dist/core/orchestration/application/orchestration-planner.service.js.map +0 -1
  116. package/dist/core/orchestration/domain/loop.d.ts +0 -119
  117. package/dist/core/orchestration/domain/loop.js +0 -2
  118. package/dist/core/orchestration/domain/loop.js.map +0 -1
  119. package/dist/core/plugins/application/plugin.service.d.ts +0 -32
  120. package/dist/core/plugins/application/plugin.service.js +0 -236
  121. package/dist/core/plugins/application/plugin.service.js.map +0 -1
  122. package/dist/core/plugins/domain/openclaw-compat.d.ts +0 -60
  123. package/dist/core/plugins/domain/openclaw-compat.js +0 -9
  124. package/dist/core/plugins/domain/openclaw-compat.js.map +0 -1
  125. package/dist/core/plugins/index.d.ts +0 -3
  126. package/dist/core/plugins/index.js +0 -3
  127. package/dist/core/plugins/index.js.map +0 -1
  128. package/dist/core/providers/onboarding.d.ts +0 -13
  129. package/dist/core/providers/onboarding.js +0 -149
  130. package/dist/core/providers/onboarding.js.map +0 -1
  131. package/dist/core/providers/providers/claude/index.d.ts +0 -4
  132. package/dist/core/providers/providers/claude/index.js +0 -19
  133. package/dist/core/providers/providers/claude/index.js.map +0 -1
  134. package/dist/core/providers/providers/claude/provider.d.ts +0 -8
  135. package/dist/core/providers/providers/claude/provider.js +0 -106
  136. package/dist/core/providers/providers/claude/provider.js.map +0 -1
  137. package/dist/core/providers/providers/codex/index.d.ts +0 -4
  138. package/dist/core/providers/providers/codex/index.js +0 -19
  139. package/dist/core/providers/providers/codex/index.js.map +0 -1
  140. package/dist/core/providers/providers/codex/provider.d.ts +0 -7
  141. package/dist/core/providers/providers/codex/provider.js +0 -31
  142. package/dist/core/providers/providers/codex/provider.js.map +0 -1
  143. package/dist/core/providers/providers/cursor/index.d.ts +0 -4
  144. package/dist/core/providers/providers/cursor/index.js +0 -19
  145. package/dist/core/providers/providers/cursor/index.js.map +0 -1
  146. package/dist/core/providers/providers/cursor/provider.d.ts +0 -11
  147. package/dist/core/providers/providers/cursor/provider.js +0 -90
  148. package/dist/core/providers/providers/cursor/provider.js.map +0 -1
  149. package/dist/core/providers/providers/extended-http/catalog.d.ts +0 -40
  150. package/dist/core/providers/providers/extended-http/catalog.js +0 -728
  151. package/dist/core/providers/providers/extended-http/catalog.js.map +0 -1
  152. package/dist/core/providers/providers/extended-http/index.d.ts +0 -5
  153. package/dist/core/providers/providers/extended-http/index.js +0 -13
  154. package/dist/core/providers/providers/extended-http/index.js.map +0 -1
  155. package/dist/core/providers/providers/extended-http/provider.d.ts +0 -31
  156. package/dist/core/providers/providers/extended-http/provider.js +0 -580
  157. package/dist/core/providers/providers/extended-http/provider.js.map +0 -1
  158. package/dist/core/providers/providers/gemini/index.d.ts +0 -4
  159. package/dist/core/providers/providers/gemini/index.js +0 -37
  160. package/dist/core/providers/providers/gemini/index.js.map +0 -1
  161. package/dist/core/providers/providers/gemini/provider.d.ts +0 -7
  162. package/dist/core/providers/providers/gemini/provider.js +0 -59
  163. package/dist/core/providers/providers/gemini/provider.js.map +0 -1
  164. package/dist/core/providers/providers/grok/index.d.ts +0 -4
  165. package/dist/core/providers/providers/grok/index.js +0 -41
  166. package/dist/core/providers/providers/grok/index.js.map +0 -1
  167. package/dist/core/providers/providers/grok/provider.d.ts +0 -13
  168. package/dist/core/providers/providers/grok/provider.js +0 -95
  169. package/dist/core/providers/providers/grok/provider.js.map +0 -1
  170. package/dist/core/providers/providers/openai/index.d.ts +0 -4
  171. package/dist/core/providers/providers/openai/index.js +0 -45
  172. package/dist/core/providers/providers/openai/index.js.map +0 -1
  173. package/dist/core/providers/providers/openai/provider.d.ts +0 -14
  174. package/dist/core/providers/providers/openai/provider.js +0 -203
  175. package/dist/core/providers/providers/openai/provider.js.map +0 -1
  176. package/dist/core/providers/providers/opencode/index.d.ts +0 -4
  177. package/dist/core/providers/providers/opencode/index.js +0 -23
  178. package/dist/core/providers/providers/opencode/index.js.map +0 -1
  179. package/dist/core/providers/providers/opencode/provider.d.ts +0 -11
  180. package/dist/core/providers/providers/opencode/provider.js +0 -215
  181. package/dist/core/providers/providers/opencode/provider.js.map +0 -1
  182. package/dist/core/providers/providers/openrouter/index.d.ts +0 -4
  183. package/dist/core/providers/providers/openrouter/index.js +0 -37
  184. package/dist/core/providers/providers/openrouter/index.js.map +0 -1
  185. package/dist/core/providers/providers/openrouter/provider.d.ts +0 -13
  186. package/dist/core/providers/providers/openrouter/provider.js +0 -80
  187. package/dist/core/providers/providers/openrouter/provider.js.map +0 -1
  188. package/dist/platform/node/opengoat-gateway-client.d.ts +0 -19
  189. package/dist/platform/node/opengoat-gateway-client.js +0 -194
  190. package/dist/platform/node/opengoat-gateway-client.js.map +0 -1
  191. package/dist/platform/node/opengoat-gateway-server.d.ts +0 -53
  192. package/dist/platform/node/opengoat-gateway-server.js +0 -906
  193. 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: "orchestration-service" });
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
- if (resolvedEntryAgentId !== DEFAULT_AGENT_ID) {
63
- runLogger.info("Running direct non-orchestrator invocation.", {
64
- targetAgentId: resolvedEntryAgentId
65
- });
66
- const sessionAgentId = options.directAgentSession ? resolvedEntryAgentId : DEFAULT_AGENT_ID;
67
- const direct = await this.invokeAgentWithSession(paths, resolvedEntryAgentId, {
68
- ...options,
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: DEFAULT_AGENT_ID,
57
+ entryAgentId: resolvedEntryAgentId,
143
58
  userMessage: options.message,
144
- routing,
145
- execution: loopResult.execution,
59
+ execution: direct.execution,
146
60
  durationMs,
147
- orchestration: {
148
- mode: "ai-loop",
149
- finalMessage: loopResult.finalMessage,
150
- steps: loopResult.steps,
151
- sessionGraph: loopResult.sessionGraph,
152
- taskThreads: loopResult.taskThreads
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: DEFAULT_AGENT_ID
73
+ agentId: resolvedEntryAgentId
160
74
  });
161
75
  return {
162
- ...loopResult.execution,
163
- entryAgentId: DEFAULT_AGENT_ID,
164
- routing,
76
+ ...direct.execution,
77
+ entryAgentId: resolvedEntryAgentId,
165
78
  tracePath: trace.tracePath,
166
- orchestration: trace.trace.orchestration
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
- workingPath: options.cwd,
88
+ projectPath: options.cwd,
647
89
  userMessage: options.message
648
90
  });
649
- const invokeOptions = sanitizeProviderInvokeOptions({
650
- ...options,
651
- sessionContext: preparedSession.enabled ? preparedSession.contextPrompt : undefined
652
- });
653
- if (behavior.silent) {
654
- delete invokeOptions.onStdout;
655
- delete invokeOptions.onStderr;
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
- ? `[Provider error code ${execution.code}] ${execution.stderr.trim()}`
708
- : `[Provider exited with code ${execution.code}]`);
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
- async writeTrace(paths, trace) {
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 renderDelegateMessage(params) {
870
- const lines = [
871
- `Delegation step: ${params.step}`,
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
- lines.push("Return a concise result for the orchestrator.");
893
- return lines.join("\n");
209
+ return sessionProjectPath;
894
210
  }
895
- function renderHandoffDocument(params) {
896
- return [
897
- `# Delegation Step ${params.step}`,
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
- const noTrackedChanges = !workingTreeEffect?.enabled || workingTreeEffect.touchedPaths.length === 0;
1031
- if (!noTrackedChanges) {
1032
- return undefined;
1033
- }
1034
- return "It reported missing runtime tools/permissions and made no tracked workspace changes. Check provider capabilities or switch to a compatible agent provider for file-editing tasks.";
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 clampText(value, maxChars) {
1037
- if (value.length <= maxChars) {
1038
- return value;
225
+ function mergeSystemPrompts(current, extra) {
226
+ const normalizedCurrent = current?.trim();
227
+ if (!normalizedCurrent) {
228
+ return extra;
1039
229
  }
1040
- const head = value.slice(0, Math.floor(maxChars * 0.7));
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