@intent-systems/nexus 2026.1.5-3 → 2026.1.5-5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (144) hide show
  1. package/dist/agents/agent-id.js +41 -0
  2. package/dist/agents/auth-profiles.js +114 -25
  3. package/dist/agents/identity-state.js +79 -0
  4. package/dist/agents/model-auth.js +1 -0
  5. package/dist/agents/model-fallback.js +15 -9
  6. package/dist/agents/model-selection.js +1 -1
  7. package/dist/agents/models-config.js +17 -11
  8. package/dist/agents/pi-embedded-runner.js +101 -9
  9. package/dist/agents/sandbox.js +12 -3
  10. package/dist/agents/skill-runner.js +29 -4
  11. package/dist/agents/skill-usage.js +114 -11
  12. package/dist/agents/skills-status.js +4 -4
  13. package/dist/agents/skills.js +18 -7
  14. package/dist/agents/subagent-registry.js +25 -11
  15. package/dist/agents/system-prompt.js +16 -0
  16. package/dist/agents/tool-policy.js +19 -3
  17. package/dist/agents/tools/browser-tool.js +5 -2
  18. package/dist/agents/tools/image-tool.js +93 -8
  19. package/dist/agents/tools/sessions-announce-target.js +5 -1
  20. package/dist/agents/workspace.js +55 -46
  21. package/dist/auto-reply/command-detection.js +2 -1
  22. package/dist/auto-reply/reply/directive-handling.js +153 -28
  23. package/dist/auto-reply/reply/directives.js +17 -2
  24. package/dist/auto-reply/reply/model-selection.js +8 -3
  25. package/dist/auto-reply/reply/queue.js +2 -2
  26. package/dist/auto-reply/reply.js +1 -1
  27. package/dist/auto-reply/thinking.js +15 -0
  28. package/dist/browser/chrome.js +1 -1
  29. package/dist/browser/client.js +2 -0
  30. package/dist/browser/config.js +6 -2
  31. package/dist/browser/pw-tools-core.js +3 -0
  32. package/dist/browser/routes/agent.js +14 -0
  33. package/dist/canvas-host/server.js +1 -1
  34. package/dist/capabilities/detector.js +245 -0
  35. package/dist/capabilities/registry.js +99 -0
  36. package/dist/channels/location.js +44 -0
  37. package/dist/channels/web/index.js +2 -0
  38. package/dist/cli/cloud-cli.js +12 -7
  39. package/dist/cli/credential-cli.js +139 -17
  40. package/dist/cli/gateway-cli.js +1 -1
  41. package/dist/cli/log-cli.js +25 -0
  42. package/dist/cli/pairing-cli.js +1 -1
  43. package/dist/cli/program.js +58 -6
  44. package/dist/cli/run-main.js +1 -1
  45. package/dist/cli/skills-cli.js +144 -21
  46. package/dist/cli/skills-hub-cli.js +59 -29
  47. package/dist/cli/tool-connector-cli.js +99 -24
  48. package/dist/cli/upstream-sync-cli.js +253 -96
  49. package/dist/cli/usage-cli.js +14 -0
  50. package/dist/commands/auth-choice-options.js +6 -1
  51. package/dist/commands/auth-choice.js +157 -5
  52. package/dist/commands/bootstrap-preset.js +10 -6
  53. package/dist/commands/capabilities.js +33 -6
  54. package/dist/commands/claude-md.js +3 -2
  55. package/dist/commands/config-view.js +1 -1
  56. package/dist/commands/configure.js +4 -4
  57. package/dist/commands/credential.js +497 -36
  58. package/dist/commands/cursor-rules.js +39 -19
  59. package/dist/commands/doctor.js +5 -4
  60. package/dist/commands/identity.js +28 -31
  61. package/dist/commands/init.js +15 -18
  62. package/dist/commands/log.js +134 -0
  63. package/dist/commands/models/fallbacks.js +1 -1
  64. package/dist/commands/models/image-fallbacks.js +1 -1
  65. package/dist/commands/models/list.js +1 -1
  66. package/dist/commands/models/scan.js +1 -1
  67. package/dist/commands/onboard-auth.js +27 -2
  68. package/dist/commands/onboard-eve-identity.js +7 -8
  69. package/dist/commands/onboard-non-interactive.js +4 -2
  70. package/dist/commands/onboard-quickstart.js +18 -11
  71. package/dist/commands/quest-state.js +271 -0
  72. package/dist/commands/quest.js +53 -13
  73. package/dist/commands/reset.js +1 -1
  74. package/dist/commands/sessions-ingest.js +5 -4
  75. package/dist/commands/setup.js +4 -2
  76. package/dist/commands/skills-manifest.js +2 -2
  77. package/dist/commands/status.js +179 -61
  78. package/dist/commands/suggestions.js +1 -1
  79. package/dist/commands/usage-tracking.js +32 -0
  80. package/dist/commands/usage-upload.js +6 -1
  81. package/dist/config/defaults.js +1 -3
  82. package/dist/config/includes.js +5 -7
  83. package/dist/config/io.js +88 -16
  84. package/dist/config/legacy.js +4 -2
  85. package/dist/config/paths.js +16 -0
  86. package/dist/config/sessions.js +9 -5
  87. package/dist/config/zod-schema.js +4 -3
  88. package/dist/control-plane/broker/broker.js +1022 -0
  89. package/dist/control-plane/compaction.js +282 -0
  90. package/dist/control-plane/factory.js +31 -0
  91. package/dist/control-plane/index.js +10 -0
  92. package/dist/control-plane/odu/agents.js +192 -0
  93. package/dist/control-plane/odu/interaction-tools.js +208 -0
  94. package/dist/control-plane/odu/prompt-loader.js +95 -0
  95. package/dist/control-plane/odu/runtime.js +479 -0
  96. package/dist/control-plane/odu/types.js +6 -0
  97. package/dist/control-plane/odu-control-plane.js +316 -0
  98. package/dist/control-plane/single-agent.js +249 -0
  99. package/dist/control-plane/types.js +11 -0
  100. package/dist/credentials/store.js +449 -0
  101. package/dist/gateway/server-browser.js +5 -4
  102. package/dist/gateway/server-methods/cron.js +11 -1
  103. package/dist/gateway/server.js +14 -7
  104. package/dist/infra/bonjour.js +1 -1
  105. package/dist/infra/event-log.js +8 -2
  106. package/dist/infra/path-env.js +1 -2
  107. package/dist/infra/provider-usage.auth.js +5 -3
  108. package/dist/infra/provider-usage.fetch.claude.js +16 -6
  109. package/dist/infra/provider-usage.fetch.minimax.js +8 -3
  110. package/dist/infra/provider-usage.js +9 -5
  111. package/dist/infra/restart.js +2 -2
  112. package/dist/infra/usage-settings.js +78 -0
  113. package/dist/infra/usage-suggestions.js +17 -5
  114. package/dist/infra/usage-upload.js +38 -1
  115. package/dist/infra/voicewake.js +2 -2
  116. package/dist/logging/redact.js +109 -0
  117. package/dist/markdown/fences.js +58 -0
  118. package/dist/media/image-ops.js +3 -1
  119. package/dist/memory/embeddings.js +146 -0
  120. package/dist/memory/index.js +3 -0
  121. package/dist/memory/internal.js +163 -0
  122. package/dist/pairing/pairing-store.js +218 -0
  123. package/dist/plugins/cli.js +42 -0
  124. package/dist/plugins/discovery.js +253 -0
  125. package/dist/plugins/install.js +181 -0
  126. package/dist/plugins/loader.js +290 -0
  127. package/dist/plugins/registry.js +105 -0
  128. package/dist/plugins/status.js +29 -0
  129. package/dist/plugins/tools.js +39 -0
  130. package/dist/plugins/types.js +1 -0
  131. package/dist/providers/github-copilot-auth.js +1 -1
  132. package/dist/routing/resolve-route.js +144 -0
  133. package/dist/routing/session-key.js +65 -0
  134. package/dist/sessions/send-policy.js +5 -5
  135. package/dist/slack/monitor.js +22 -1
  136. package/dist/telegram/reaction-level.js +2 -1
  137. package/dist/utils/provider-utils.js +28 -0
  138. package/dist/utils.js +4 -3
  139. package/dist/wizard/onboarding.js +29 -7
  140. package/package.json +4 -29
  141. package/patches/@mariozechner__pi-ai.patch +215 -0
  142. package/patches/playwright-core@1.57.0.patch +13 -0
  143. package/patches/qrcode-terminal.patch +12 -0
  144. package/scripts/postinstall.js +202 -0
@@ -0,0 +1,479 @@
1
+ /**
2
+ * Unified ODU Runtime
3
+ *
4
+ * Convention-driven agent runtime that works for any ODU.
5
+ * Adapted from magic-toolbox for Nexus.
6
+ */
7
+ import path from "node:path";
8
+ import { DEFAULT_MODEL } from "../../agents/defaults.js";
9
+ import { appendToHistory, loadHistory, } from "../../config/sessions.js";
10
+ import { DEFAULT_AGENT_ID } from "../../routing/session-key.js";
11
+ import { resolveUserPath } from "../../utils.js";
12
+ import { ExecutionAgent, InteractionAgent } from "./agents.js";
13
+ import { loadPrompt } from "./prompt-loader.js";
14
+ /**
15
+ * Unified Interaction Agent Runtime
16
+ *
17
+ * Convention-driven IA that works for any ODU.
18
+ * Wraps Nexus embedded agent system.
19
+ */
20
+ export class ODUInteractionAgent extends InteractionAgent {
21
+ // Static registry of all ODU IA singletons (fractal architecture support)
22
+ static instances = new Map();
23
+ static getOrCreate(config) {
24
+ const key = `${config.oduPath}:${config.userId}`;
25
+ const existing = ODUInteractionAgent.instances.get(key);
26
+ if (existing) {
27
+ return existing;
28
+ }
29
+ const instance = new ODUInteractionAgent(config);
30
+ ODUInteractionAgent.instances.set(key, instance);
31
+ return instance;
32
+ }
33
+ conversationHistory = [];
34
+ broker;
35
+ constructor(config) {
36
+ // Singleton key: oduPath + userId (supports nested ODUs)
37
+ const key = `${config.oduPath}:${config.userId}`;
38
+ // Create new instance
39
+ super(config);
40
+ this.oduConfig = config.oduConfig;
41
+ this.broker = config.broker;
42
+ // Register this singleton
43
+ ODUInteractionAgent.instances.set(key, this);
44
+ // Load conversation history asynchronously
45
+ // (constructors can't be async, so we do this in the background)
46
+ if (config.sessionId) {
47
+ this.loadConversationHistory(config.sessionId).catch((error) => {
48
+ this.log.warn("Failed to load conversation history", { error });
49
+ });
50
+ }
51
+ // Register ODU with broker
52
+ const agentFactory = (agentId, taskDescription, history) => {
53
+ return new ODUExecutionAgent({
54
+ agentId,
55
+ userId: this.userId,
56
+ task: {
57
+ userId: this.userId,
58
+ type: this.oduConfig.name,
59
+ description: taskDescription,
60
+ taskName: agentId,
61
+ },
62
+ oduPath: this.oduPath,
63
+ config: this.config,
64
+ history,
65
+ broker: this.broker,
66
+ });
67
+ };
68
+ // Register ODU (EA factory) with broker
69
+ this.broker.registerODU(this.oduConfig.name, path.join(resolveUserPath(this.oduPath), "../state"), agentFactory);
70
+ // Register THIS IA with broker so it can receive messages
71
+ const iaId = `${this.oduConfig.name}-ia`;
72
+ this.broker.registerIA(iaId, this);
73
+ this.log.info("IA registered with broker", { iaId });
74
+ }
75
+ /**
76
+ * Resolve the model to use for IA from config
77
+ * Priority: controlPlane.odu.iaModel.primary > agent.model.primary > DEFAULT_MODEL
78
+ */
79
+ resolveIAModel() {
80
+ const oduConfig = this.config?.controlPlane?.odu;
81
+ const agentConfig = this.config?.agent;
82
+ // Check ODU-specific IA model first
83
+ if (oduConfig?.iaModel?.primary) {
84
+ // Extract just the model name from provider/model format
85
+ const parts = oduConfig.iaModel.primary.split("/");
86
+ return parts.length > 1 ? parts[1] : parts[0];
87
+ }
88
+ // Fall back to agent.model
89
+ if (agentConfig?.model?.primary) {
90
+ const parts = agentConfig.model.primary.split("/");
91
+ return parts.length > 1 ? parts[1] : parts[0];
92
+ }
93
+ // Default to opus
94
+ return DEFAULT_MODEL;
95
+ }
96
+ /**
97
+ * Load conversation history from new session format
98
+ */
99
+ async loadConversationHistory(sessionId) {
100
+ try {
101
+ // Use DEFAULT_AGENT_ID and sessionId as the sessionKey
102
+ const agentId = DEFAULT_AGENT_ID;
103
+ const sessionKey = sessionId;
104
+ // Load history from new format
105
+ const history = await loadHistory(agentId, sessionKey);
106
+ if (history && history.length > 0) {
107
+ // Convert HistoryTurn[] to conversation history format
108
+ this.conversationHistory = history.map((turn) => ({
109
+ turn_id: turn.turn_id,
110
+ role: turn.role,
111
+ content: turn.content,
112
+ tool_calls: turn.tool_calls,
113
+ tool_call_id: turn.tool_call_id,
114
+ timestamp: turn.timestamp,
115
+ }));
116
+ this.log.info("Loaded conversation history", {
117
+ turns: this.conversationHistory.length,
118
+ });
119
+ }
120
+ }
121
+ catch (error) {
122
+ this.log.error("Failed to load conversation history", { error });
123
+ }
124
+ }
125
+ /**
126
+ * Handle a user message and return complete response
127
+ */
128
+ async chatSync(userMessage) {
129
+ // ALWAYS interrupt if currently streaming
130
+ if (this.isStreaming) {
131
+ this.log.info("New message received while streaming, interrupting");
132
+ this.interrupt();
133
+ // Wait a tiny bit for stream to stop
134
+ await new Promise((resolve) => setTimeout(resolve, 50));
135
+ }
136
+ // Add message to queue
137
+ this.queueMessage(userMessage);
138
+ // If already processing (but not streaming), return queued message
139
+ if (this.isProcessing && !this.isStreaming) {
140
+ return "Message queued. Processing...";
141
+ }
142
+ this.isProcessing = true;
143
+ try {
144
+ let finalResponse = "";
145
+ // Process all queued messages
146
+ while (this.messageQueue.length > 0) {
147
+ // Dequeue all current messages
148
+ const messages = this.messageQueue.splice(0);
149
+ // Sort by priority (high priority first)
150
+ messages.sort((a, b) => {
151
+ const priorityOrder = { urgent: 0, high: 1, normal: 2, low: 3 };
152
+ const aPriority = priorityOrder[a.priority] || 2;
153
+ const bPriority = priorityOrder[b.priority] || 2;
154
+ if (aPriority !== bPriority)
155
+ return aPriority - bPriority;
156
+ return a.timestamp - b.timestamp;
157
+ });
158
+ // Extract sender from first message
159
+ const from = messages[0].from;
160
+ // Combine messages into single prompt
161
+ const combinedMessage = messages.length === 1
162
+ ? messages[0].content
163
+ : messages
164
+ .map((m, i) => `Message ${i + 1}:\n${m.content}`)
165
+ .join("\n\n---\n\n");
166
+ // Reset interrupt flag for new processing
167
+ this.shouldInterrupt = false;
168
+ // Process the combined message with sender context (with streaming + interrupt support)
169
+ finalResponse = await this.processSingleMessage(combinedMessage, from);
170
+ // If interrupted, accumulated response is preserved
171
+ // New messages will be in the queue for next iteration
172
+ }
173
+ return finalResponse;
174
+ }
175
+ finally {
176
+ this.isProcessing = false;
177
+ this.isStreaming = false;
178
+ }
179
+ }
180
+ /**
181
+ * Process a single message (extracted for queue handling)
182
+ */
183
+ async processSingleMessage(userMessage, from) {
184
+ // If message from another agent, prepend context so IA knows who to respond to
185
+ if (from && from !== "user" && from !== "system") {
186
+ userMessage = `[Message from agent: ${from}]\n\n${userMessage}`;
187
+ }
188
+ this.log.info("Processing message", {
189
+ messageLength: userMessage.length,
190
+ from,
191
+ });
192
+ // Import dependencies dynamically
193
+ const { default: Anthropic } = await import("@anthropic-ai/sdk");
194
+ const { createInteractionTools, handleToolInvocation } = await import("./interaction-tools.js");
195
+ // Get API key from environment
196
+ const apiKey = process.env.ANTHROPIC_API_KEY;
197
+ if (!apiKey) {
198
+ throw new Error("ANTHROPIC_API_KEY environment variable is required for ODU interaction agent");
199
+ }
200
+ // Create Anthropic client
201
+ const client = new Anthropic({ apiKey });
202
+ // Build system prompt
203
+ const systemPrompt = await this.buildSystemPrompt();
204
+ // Create interaction tools context
205
+ const toolsContext = {
206
+ broker: this.broker,
207
+ userId: this.userId,
208
+ oduName: this.oduConfig.name,
209
+ oduPurpose: this.oduConfig.purpose,
210
+ agentId: `${this.oduConfig.name}-ia`,
211
+ };
212
+ // Get tool definitions
213
+ const tools = createInteractionTools(toolsContext);
214
+ // Build conversation history in Anthropic format
215
+ const messages = [];
216
+ // Add conversation history
217
+ for (const turn of this.conversationHistory) {
218
+ if (turn.role === "user") {
219
+ messages.push({ role: "user", content: turn.content });
220
+ }
221
+ else if (turn.role === "assistant") {
222
+ // Build assistant message with tool calls if present
223
+ const content = [];
224
+ if (turn.content) {
225
+ content.push({ type: "text", text: turn.content });
226
+ }
227
+ if (turn.tool_calls && turn.tool_calls.length > 0) {
228
+ for (const toolCall of turn.tool_calls) {
229
+ content.push({
230
+ type: "tool_use",
231
+ id: toolCall.id,
232
+ name: toolCall.function.name,
233
+ input: JSON.parse(toolCall.function.arguments),
234
+ });
235
+ }
236
+ }
237
+ messages.push({ role: "assistant", content });
238
+ }
239
+ else if (turn.role === "tool") {
240
+ }
241
+ }
242
+ // Add current user message
243
+ messages.push({ role: "user", content: userMessage });
244
+ // Resolve model from config (IA uses controlPlane.odu.iaModel or agent.model)
245
+ const iaModel = this.resolveIAModel();
246
+ // Call Claude API with tool support
247
+ let response = await client.messages.create({
248
+ model: iaModel,
249
+ max_tokens: 4096,
250
+ system: systemPrompt,
251
+ messages: messages,
252
+ tools,
253
+ });
254
+ // Handle tool calls in a loop (agent may make multiple tool calls)
255
+ let iterationCount = 0;
256
+ const maxIterations = 10; // Prevent infinite loops
257
+ while (response.stop_reason === "tool_use" &&
258
+ iterationCount < maxIterations) {
259
+ iterationCount++;
260
+ // Extract tool calls from response
261
+ const toolUseBlocks = response.content.filter((block) => block.type === "tool_use");
262
+ // Execute each tool and collect results
263
+ const toolResults = [];
264
+ for (const toolBlock of toolUseBlocks) {
265
+ try {
266
+ const result = await handleToolInvocation(toolBlock.name, toolBlock.input, toolsContext);
267
+ toolResults.push({
268
+ type: "tool_result",
269
+ tool_use_id: toolBlock.id,
270
+ content: result,
271
+ });
272
+ }
273
+ catch (error) {
274
+ const errorMessage = error instanceof Error ? error.message : String(error);
275
+ toolResults.push({
276
+ type: "tool_result",
277
+ tool_use_id: toolBlock.id,
278
+ content: `Error: ${errorMessage}`,
279
+ is_error: true,
280
+ });
281
+ }
282
+ }
283
+ // Add assistant response to messages
284
+ messages.push({ role: "assistant", content: response.content });
285
+ // Add tool results as user message
286
+ messages.push({ role: "user", content: toolResults });
287
+ // Continue conversation
288
+ response = await client.messages.create({
289
+ model: "claude-sonnet-4-20250514",
290
+ max_tokens: 4096,
291
+ system: systemPrompt,
292
+ messages: messages,
293
+ tools,
294
+ });
295
+ }
296
+ // Extract final text response
297
+ const textBlocks = response.content.filter((block) => block.type === "text");
298
+ const finalResponse = textBlocks.map((block) => block.text).join("\n");
299
+ // Save conversation history (both in-memory and to disk)
300
+ const userTurn = {
301
+ turn_id: `turn-${Date.now()}-user`,
302
+ role: "user",
303
+ content: userMessage,
304
+ timestamp: new Date().toISOString(),
305
+ };
306
+ const assistantTurn = {
307
+ turn_id: `turn-${Date.now()}-assistant`,
308
+ role: "assistant",
309
+ content: finalResponse,
310
+ timestamp: new Date().toISOString(),
311
+ };
312
+ // Update in-memory history
313
+ this.conversationHistory.push(userTurn);
314
+ this.conversationHistory.push(assistantTurn);
315
+ // Persist to disk using the IA's session
316
+ const agentId = DEFAULT_AGENT_ID;
317
+ const sessionKey = this.sessionId;
318
+ try {
319
+ await appendToHistory(agentId, sessionKey, userTurn);
320
+ await appendToHistory(agentId, sessionKey, assistantTurn);
321
+ this.log.debug("Persisted conversation to history.jsonl", { sessionKey });
322
+ }
323
+ catch (error) {
324
+ this.log.warn("Failed to persist conversation history", {
325
+ error,
326
+ sessionKey,
327
+ });
328
+ }
329
+ return finalResponse;
330
+ }
331
+ /**
332
+ * Build system prompt for the IA
333
+ */
334
+ async buildSystemPrompt() {
335
+ // Load InteractionAgent.md prompt with template variables
336
+ const prompt = await loadPrompt("InteractionAgent.md", {
337
+ oduName: this.oduConfig.name,
338
+ oduPurpose: this.oduConfig.purpose,
339
+ oduPath: this.oduPath,
340
+ });
341
+ return prompt;
342
+ }
343
+ }
344
+ /**
345
+ * Unified Execution Agent Runtime
346
+ *
347
+ * Convention-driven EA that works for any ODU.
348
+ * Wraps Nexus embedded agent system with isolated workspace.
349
+ */
350
+ export class ODUExecutionAgent extends ExecutionAgent {
351
+ broker;
352
+ constructor(config) {
353
+ super(config);
354
+ this.broker = config.broker;
355
+ if (config.oduConfig) {
356
+ this.oduConfig = config.oduConfig;
357
+ }
358
+ else {
359
+ // Derive ODU name from path
360
+ const oduName = path.basename(resolveUserPath(config.oduPath || "~/nexus/home"));
361
+ this.oduConfig = {
362
+ name: oduName,
363
+ purpose: `Execute tasks for ${oduName} ODU`,
364
+ };
365
+ }
366
+ }
367
+ /**
368
+ * Execute the task using Nexus embedded agent
369
+ */
370
+ async execute() {
371
+ this.log.info("Starting EA execution", {
372
+ taskType: this.task.type,
373
+ taskDescription: (this.task.description || "").substring(0, 200),
374
+ historyLength: this.history.length,
375
+ });
376
+ try {
377
+ // Import runEmbeddedPiAgent dynamically
378
+ const { runEmbeddedPiAgent } = await import("../../agents/pi-embedded-runner.js");
379
+ const { resolveNexusAgentDir } = await import("../../agents/agent-paths.js");
380
+ const { randomUUID } = await import("node:crypto");
381
+ const path = await import("node:path");
382
+ // Build initial task prompt
383
+ const taskPrompt = this.buildInitialPrompt();
384
+ // Resolve workspace directory for this EA
385
+ // Use shared workspace (~/nexus/home) - all EAs share the same workspace
386
+ // This aligns with Cursor and single-agent mode behavior
387
+ const workspaceDir = resolveUserPath(this.oduPath);
388
+ // Resolve session file path
389
+ const agentDir = resolveNexusAgentDir();
390
+ const sessionFile = path.join(workspaceDir, ".agent-session.json");
391
+ // Build system prompt with EA template
392
+ const systemPrompt = await this.buildSystemPrompt();
393
+ // Run embedded pi-agent with full coding tools
394
+ const result = await runEmbeddedPiAgent({
395
+ sessionId: this.agentId,
396
+ sessionKey: this.agentId,
397
+ sessionFile,
398
+ workspaceDir,
399
+ agentDir,
400
+ config: this.config,
401
+ prompt: taskPrompt,
402
+ // Use default provider/model if not configured
403
+ provider: undefined, // Will use defaults from config
404
+ model: undefined, // Will use defaults from config
405
+ thinkLevel: this.config?.agent?.thinkingDefault,
406
+ verboseLevel: this.config?.agent?.verboseDefault,
407
+ timeoutMs: (this.config?.agent?.timeoutSeconds || 300) * 1000,
408
+ runId: randomUUID(),
409
+ extraSystemPrompt: systemPrompt,
410
+ });
411
+ // Extract final response from payloads
412
+ const finalResponse = result.payloads
413
+ ?.map((p) => p.text)
414
+ .filter(Boolean)
415
+ .join("\n\n") || "Task completed";
416
+ this.log.info("EA execution complete", {
417
+ responseLength: finalResponse.length,
418
+ usage: result.meta.agentMeta?.usage,
419
+ });
420
+ // Send result back to IA via broker
421
+ const oduName = this.oduConfig.name;
422
+ const iaId = `${oduName}-ia`;
423
+ await this.broker.send({
424
+ id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
425
+ from: this.agentId,
426
+ to: iaId,
427
+ content: finalResponse,
428
+ priority: "normal",
429
+ timestamp: Date.now(),
430
+ metadata: {
431
+ source: "ea",
432
+ completionResult: true,
433
+ usage: result.meta.agentMeta?.usage,
434
+ },
435
+ });
436
+ return finalResponse;
437
+ }
438
+ catch (error) {
439
+ this.log.error("EA execution failed", { error });
440
+ // Send error back to IA
441
+ const oduName = this.oduConfig.name;
442
+ const iaId = `${oduName}-ia`;
443
+ const errorMessage = error instanceof Error ? error.message : String(error);
444
+ await this.broker.send({
445
+ id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
446
+ from: this.agentId,
447
+ to: iaId,
448
+ content: `Task failed: ${errorMessage}`,
449
+ priority: "normal",
450
+ timestamp: Date.now(),
451
+ metadata: {
452
+ source: "ea",
453
+ completionResult: true,
454
+ error: true,
455
+ },
456
+ });
457
+ throw error;
458
+ }
459
+ }
460
+ /**
461
+ * Build system prompt for the EA
462
+ */
463
+ async buildSystemPrompt() {
464
+ // Load ExecutionAgent.md prompt with template variables
465
+ const prompt = await loadPrompt("ExecutionAgent.md", {
466
+ oduName: this.oduConfig.name,
467
+ oduPurpose: this.oduConfig.purpose,
468
+ oduPath: this.oduPath,
469
+ task: this.task.description || "Execute the assigned task",
470
+ taskName: this.task.taskName || "task",
471
+ agentId: this.agentId,
472
+ // For now, leave skills and capabilities empty
473
+ // These will be populated when we implement skill/capability loading
474
+ availableSkills: "(Skills will be listed here)",
475
+ availableCapabilities: "(Capabilities will be listed here)",
476
+ });
477
+ return prompt;
478
+ }
479
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * ODU (Orchestration Domain Unit) Types
3
+ *
4
+ * Adapted from magic-toolbox for Nexus
5
+ */
6
+ export {};