@intent-systems/nexus 2026.1.5-4 → 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.
- package/dist/agents/agent-id.js +41 -0
- package/dist/agents/auth-profiles.js +114 -25
- package/dist/agents/identity-state.js +79 -0
- package/dist/agents/model-auth.js +1 -0
- package/dist/agents/model-fallback.js +15 -9
- package/dist/agents/model-selection.js +1 -1
- package/dist/agents/models-config.js +17 -11
- package/dist/agents/pi-embedded-runner.js +101 -9
- package/dist/agents/sandbox.js +12 -3
- package/dist/agents/skill-runner.js +29 -4
- package/dist/agents/skill-usage.js +114 -11
- package/dist/agents/skills-status.js +4 -4
- package/dist/agents/skills.js +18 -7
- package/dist/agents/subagent-registry.js +25 -11
- package/dist/agents/system-prompt.js +16 -0
- package/dist/agents/tool-policy.js +19 -3
- package/dist/agents/tools/browser-tool.js +5 -2
- package/dist/agents/tools/image-tool.js +93 -8
- package/dist/agents/tools/sessions-announce-target.js +5 -1
- package/dist/agents/workspace.js +55 -46
- package/dist/auto-reply/command-detection.js +2 -1
- package/dist/auto-reply/reply/directive-handling.js +153 -28
- package/dist/auto-reply/reply/directives.js +17 -2
- package/dist/auto-reply/reply/model-selection.js +8 -3
- package/dist/auto-reply/reply/queue.js +2 -2
- package/dist/auto-reply/reply.js +1 -1
- package/dist/auto-reply/thinking.js +15 -0
- package/dist/browser/chrome.js +1 -1
- package/dist/browser/client.js +2 -0
- package/dist/browser/config.js +6 -2
- package/dist/browser/pw-tools-core.js +3 -0
- package/dist/browser/routes/agent.js +14 -0
- package/dist/canvas-host/server.js +1 -1
- package/dist/capabilities/detector.js +46 -15
- package/dist/capabilities/registry.js +2 -1
- package/dist/cli/cloud-cli.js +12 -7
- package/dist/cli/credential-cli.js +139 -17
- package/dist/cli/gateway-cli.js +1 -1
- package/dist/cli/log-cli.js +25 -0
- package/dist/cli/pairing-cli.js +1 -1
- package/dist/cli/program.js +58 -6
- package/dist/cli/run-main.js +1 -1
- package/dist/cli/skills-cli.js +144 -21
- package/dist/cli/skills-hub-cli.js +59 -29
- package/dist/cli/tool-connector-cli.js +99 -24
- package/dist/cli/upstream-sync-cli.js +253 -96
- package/dist/cli/usage-cli.js +14 -0
- package/dist/commands/auth-choice-options.js +6 -1
- package/dist/commands/auth-choice.js +157 -5
- package/dist/commands/bootstrap-preset.js +10 -6
- package/dist/commands/capabilities.js +33 -6
- package/dist/commands/claude-md.js +3 -2
- package/dist/commands/config-view.js +1 -1
- package/dist/commands/configure.js +4 -4
- package/dist/commands/credential.js +497 -36
- package/dist/commands/cursor-rules.js +39 -19
- package/dist/commands/doctor.js +5 -4
- package/dist/commands/identity.js +28 -31
- package/dist/commands/init.js +15 -18
- package/dist/commands/log.js +134 -0
- package/dist/commands/models/fallbacks.js +1 -1
- package/dist/commands/models/image-fallbacks.js +1 -1
- package/dist/commands/models/list.js +1 -1
- package/dist/commands/models/scan.js +1 -1
- package/dist/commands/onboard-auth.js +27 -2
- package/dist/commands/onboard-eve-identity.js +7 -8
- package/dist/commands/onboard-non-interactive.js +4 -2
- package/dist/commands/onboard-quickstart.js +18 -11
- package/dist/commands/quest-state.js +271 -0
- package/dist/commands/quest.js +53 -13
- package/dist/commands/reset.js +1 -1
- package/dist/commands/sessions-ingest.js +5 -4
- package/dist/commands/setup.js +4 -2
- package/dist/commands/skills-manifest.js +2 -2
- package/dist/commands/status.js +179 -61
- package/dist/commands/suggestions.js +1 -1
- package/dist/commands/usage-tracking.js +32 -0
- package/dist/commands/usage-upload.js +6 -1
- package/dist/config/defaults.js +1 -3
- package/dist/config/includes.js +5 -7
- package/dist/config/io.js +88 -16
- package/dist/config/legacy.js +4 -2
- package/dist/config/paths.js +16 -0
- package/dist/config/sessions.js +9 -5
- package/dist/config/zod-schema.js +4 -3
- package/dist/control-plane/broker/broker.js +131 -78
- package/dist/control-plane/compaction.js +3 -5
- package/dist/control-plane/factory.js +2 -2
- package/dist/control-plane/index.js +2 -2
- package/dist/control-plane/odu/agents.js +28 -23
- package/dist/control-plane/odu/interaction-tools.js +62 -50
- package/dist/control-plane/odu/prompt-loader.js +8 -8
- package/dist/control-plane/odu/runtime.js +87 -75
- package/dist/control-plane/odu-control-plane.js +14 -12
- package/dist/control-plane/single-agent.js +13 -13
- package/dist/credentials/store.js +133 -7
- package/dist/gateway/server-browser.js +5 -4
- package/dist/gateway/server-methods/cron.js +11 -1
- package/dist/gateway/server.js +14 -7
- package/dist/infra/bonjour.js +1 -1
- package/dist/infra/event-log.js +8 -2
- package/dist/infra/path-env.js +1 -2
- package/dist/infra/provider-usage.auth.js +5 -3
- package/dist/infra/provider-usage.fetch.claude.js +16 -6
- package/dist/infra/provider-usage.fetch.minimax.js +8 -3
- package/dist/infra/provider-usage.js +9 -5
- package/dist/infra/restart.js +2 -2
- package/dist/infra/usage-settings.js +78 -0
- package/dist/infra/usage-suggestions.js +17 -5
- package/dist/infra/usage-upload.js +38 -1
- package/dist/infra/voicewake.js +2 -2
- package/dist/media/image-ops.js +3 -1
- package/dist/memory/index.js +2 -381
- package/dist/pairing/pairing-store.js +24 -0
- package/dist/providers/github-copilot-auth.js +1 -1
- package/dist/routing/resolve-route.js +6 -6
- package/dist/routing/session-key.js +3 -1
- package/dist/sessions/send-policy.js +5 -5
- package/dist/slack/monitor.js +22 -1
- package/dist/telegram/reaction-level.js +2 -1
- package/dist/utils.js +4 -3
- package/dist/wizard/onboarding.js +29 -7
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import Anthropic from "@anthropic-ai/sdk";
|
|
2
1
|
import fs from "node:fs";
|
|
3
2
|
import os from "node:os";
|
|
4
3
|
import path from "node:path";
|
|
4
|
+
import Anthropic from "@anthropic-ai/sdk";
|
|
5
5
|
import { compactEmbeddedPiSession, } from "../agents/pi-embedded-runner.js";
|
|
6
6
|
import { archiveHistory, loadHistory, resolveSessionDir, writeSummary, } from "../config/sessions.js";
|
|
7
7
|
import { createSubsystemLogger } from "../logging.js";
|
|
@@ -133,9 +133,7 @@ function partitionHistory(history, keepRecentMessages, keepRecentTokens) {
|
|
|
133
133
|
for (let i = history.length - 1; i >= 0; i--) {
|
|
134
134
|
const turn = history[i];
|
|
135
135
|
const estimatedTokens = Math.ceil((turn.content?.length ?? 0) / 4 +
|
|
136
|
-
(turn.tool_calls
|
|
137
|
-
? JSON.stringify(turn.tool_calls).length / 4
|
|
138
|
-
: 0));
|
|
136
|
+
(turn.tool_calls ? JSON.stringify(turn.tool_calls).length / 4 : 0));
|
|
139
137
|
tokenCount += estimatedTokens;
|
|
140
138
|
if (tokenCount > keepRecentTokens) {
|
|
141
139
|
// Found the split point
|
|
@@ -251,7 +249,7 @@ ${summaryText}
|
|
|
251
249
|
log.debug(`Cleaned up temp history file: ${tmpFilePath}`);
|
|
252
250
|
}
|
|
253
251
|
catch (error) {
|
|
254
|
-
log.warn(`Failed to clean up temp history file ${tmpFilePath}: ${error}`);
|
|
252
|
+
log.warn(`Failed to clean up temp history file ${tmpFilePath}: ${String(error)}`);
|
|
255
253
|
}
|
|
256
254
|
}
|
|
257
255
|
}
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Factory for creating the appropriate AgentControlPlane implementation
|
|
3
3
|
* based on configuration.
|
|
4
4
|
*/
|
|
5
|
-
import { SingleAgentControlPlane } from "./single-agent.js";
|
|
6
5
|
import { ODUControlPlane } from "./odu-control-plane.js";
|
|
6
|
+
import { SingleAgentControlPlane } from "./single-agent.js";
|
|
7
7
|
/**
|
|
8
8
|
* Creates an AgentControlPlane instance based on the config.
|
|
9
9
|
*
|
|
@@ -26,6 +26,6 @@ export function createControlPlane(options) {
|
|
|
26
26
|
workspaceDir: options?.workspaceDir,
|
|
27
27
|
});
|
|
28
28
|
default:
|
|
29
|
-
throw new Error(`Unknown control plane mode: ${mode}. Valid modes: 'single', 'odu'`);
|
|
29
|
+
throw new Error(`Unknown control plane mode: ${String(mode)}. Valid modes: 'single', 'odu'`);
|
|
30
30
|
}
|
|
31
31
|
}
|
|
@@ -5,6 +5,6 @@
|
|
|
5
5
|
* and routing messages. It allows switching between different orchestration
|
|
6
6
|
* strategies without changing the Gateway (Access Plane) code.
|
|
7
7
|
*/
|
|
8
|
-
export {
|
|
8
|
+
export { createControlPlane, } from "./factory.js";
|
|
9
9
|
export { ODUControlPlane } from "./odu-control-plane.js";
|
|
10
|
-
export {
|
|
10
|
+
export { SingleAgentControlPlane } from "./single-agent.js";
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Adapted from magic-toolbox for Nexus
|
|
5
5
|
* Wraps Nexus pi-coding-agent session API
|
|
6
6
|
*/
|
|
7
|
-
import { createSubsystemLogger } from
|
|
7
|
+
import { createSubsystemLogger } from "../../logging.js";
|
|
8
8
|
/**
|
|
9
9
|
* Base Interaction Agent
|
|
10
10
|
*
|
|
@@ -26,26 +26,26 @@ export class InteractionAgent {
|
|
|
26
26
|
isProcessing = false;
|
|
27
27
|
isStreaming = false;
|
|
28
28
|
shouldInterrupt = false;
|
|
29
|
-
accumulatedResponse =
|
|
29
|
+
accumulatedResponse = "";
|
|
30
30
|
constructor(config) {
|
|
31
31
|
this.userId = config.userId;
|
|
32
|
-
this.agentId = config.agentId || `${config.oduPath ||
|
|
32
|
+
this.agentId = config.agentId || `${config.oduPath || "nexus"}-ia`;
|
|
33
33
|
this.sessionId = config.sessionId || this.agentId;
|
|
34
|
-
this.oduPath = config.oduPath ||
|
|
34
|
+
this.oduPath = config.oduPath || "~/nexus/home";
|
|
35
35
|
this.config = config.config;
|
|
36
|
-
this.model = config.model ||
|
|
36
|
+
this.model = config.model || "claude-sonnet-4-5-20250929";
|
|
37
37
|
this.maxTurns = config.maxTurns || 20;
|
|
38
38
|
// Initialize ODU config (will be set by subclass)
|
|
39
39
|
this.oduConfig = {
|
|
40
|
-
name:
|
|
41
|
-
purpose:
|
|
40
|
+
name: "nexus",
|
|
41
|
+
purpose: "Nexus Interaction Agent",
|
|
42
42
|
};
|
|
43
43
|
this.log = createSubsystemLogger(`odu/${this.agentId}`);
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Queue a message for processing
|
|
47
47
|
*/
|
|
48
|
-
queueMessage(content, priority =
|
|
48
|
+
queueMessage(content, priority = "normal", from) {
|
|
49
49
|
this.messageQueue.push({
|
|
50
50
|
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
51
51
|
content,
|
|
@@ -61,26 +61,26 @@ export class InteractionAgent {
|
|
|
61
61
|
* Returns IMMEDIATE acknowledgment, then processes async in background
|
|
62
62
|
*/
|
|
63
63
|
async processQueue() {
|
|
64
|
-
this.log.info(
|
|
64
|
+
this.log.info("processQueue() called", {
|
|
65
65
|
queueLength: this.messageQueue.length,
|
|
66
66
|
isProcessing: this.isProcessing,
|
|
67
67
|
});
|
|
68
68
|
// If already processing, return early
|
|
69
69
|
if (this.isProcessing) {
|
|
70
|
-
return
|
|
70
|
+
return "IA is currently processing another request";
|
|
71
71
|
}
|
|
72
72
|
// If no messages queued, return early
|
|
73
73
|
if (this.messageQueue.length === 0) {
|
|
74
|
-
return
|
|
74
|
+
return "No messages to process";
|
|
75
75
|
}
|
|
76
76
|
// Peek at first message to generate acknowledgment
|
|
77
77
|
const firstMessage = this.messageQueue[0];
|
|
78
78
|
const ackMessage = firstMessage.from
|
|
79
79
|
? `Acknowledged request from ${firstMessage.from}. Processing now...`
|
|
80
|
-
:
|
|
80
|
+
: "Acknowledged. Processing...";
|
|
81
81
|
// Start processing in background (don't await!)
|
|
82
82
|
this.processQueueAsync().catch((error) => {
|
|
83
|
-
this.log.error(
|
|
83
|
+
this.log.error("Background processing error", { error });
|
|
84
84
|
});
|
|
85
85
|
// Return acknowledgment immediately
|
|
86
86
|
return ackMessage;
|
|
@@ -91,7 +91,7 @@ export class InteractionAgent {
|
|
|
91
91
|
async processQueueAsync() {
|
|
92
92
|
this.isProcessing = true;
|
|
93
93
|
try {
|
|
94
|
-
let finalResponse =
|
|
94
|
+
let finalResponse = "";
|
|
95
95
|
// Process all queued messages
|
|
96
96
|
while (this.messageQueue.length > 0) {
|
|
97
97
|
// Dequeue all current messages
|
|
@@ -110,13 +110,15 @@ export class InteractionAgent {
|
|
|
110
110
|
// Combine messages
|
|
111
111
|
const combinedMessage = messages.length === 1
|
|
112
112
|
? messages[0].content
|
|
113
|
-
: messages
|
|
113
|
+
: messages
|
|
114
|
+
.map((m, i) => `Message ${i + 1}:\n${m.content}`)
|
|
115
|
+
.join("\n\n---\n\n");
|
|
114
116
|
// Reset interrupt flag
|
|
115
117
|
this.shouldInterrupt = false;
|
|
116
118
|
// Process the combined message with sender context
|
|
117
119
|
finalResponse = await this.processSingleMessage(combinedMessage, from);
|
|
118
120
|
}
|
|
119
|
-
this.log.info(
|
|
121
|
+
this.log.info("Async processing complete", {
|
|
120
122
|
responseLength: finalResponse.length,
|
|
121
123
|
});
|
|
122
124
|
}
|
|
@@ -130,7 +132,7 @@ export class InteractionAgent {
|
|
|
130
132
|
*/
|
|
131
133
|
interrupt() {
|
|
132
134
|
if (this.isStreaming) {
|
|
133
|
-
this.log.info(
|
|
135
|
+
this.log.info("Interrupting mid-stream", {
|
|
134
136
|
accumulatedLength: this.accumulatedResponse.length,
|
|
135
137
|
});
|
|
136
138
|
this.shouldInterrupt = true;
|
|
@@ -164,17 +166,20 @@ export class ExecutionAgent {
|
|
|
164
166
|
constructor(config) {
|
|
165
167
|
this.userId = config.userId;
|
|
166
168
|
this.task = config.task;
|
|
167
|
-
this.agentId =
|
|
168
|
-
|
|
169
|
+
this.agentId =
|
|
170
|
+
config.agentId ||
|
|
171
|
+
`${config.oduPath || "nexus"}-ea-${this.task.taskName || "task"}`;
|
|
172
|
+
this.oduPath = config.oduPath || "~/nexus/home";
|
|
169
173
|
this.config = config.config;
|
|
170
174
|
// Support model override: task.model > config.model > default Haiku 4.5
|
|
171
|
-
this.model =
|
|
175
|
+
this.model =
|
|
176
|
+
config.task.model || config.model || "claude-haiku-4-5-20251001";
|
|
172
177
|
this.maxTurns = config.maxTurns || 50;
|
|
173
178
|
this.history = config.history || [];
|
|
174
179
|
// Initialize ODU config (will be set by subclass)
|
|
175
180
|
this.oduConfig = {
|
|
176
|
-
name:
|
|
177
|
-
purpose:
|
|
181
|
+
name: "nexus",
|
|
182
|
+
purpose: "Nexus Execution Agent",
|
|
178
183
|
};
|
|
179
184
|
this.log = createSubsystemLogger(`odu/${this.agentId}`);
|
|
180
185
|
}
|
|
@@ -182,6 +187,6 @@ export class ExecutionAgent {
|
|
|
182
187
|
* Build initial prompt for the task
|
|
183
188
|
*/
|
|
184
189
|
buildInitialPrompt() {
|
|
185
|
-
return this.task.description ||
|
|
190
|
+
return this.task.description || "Complete the task";
|
|
186
191
|
}
|
|
187
192
|
}
|
|
@@ -4,63 +4,63 @@
|
|
|
4
4
|
* Creates tools for IAs to delegate to EAs and manage specialist agents.
|
|
5
5
|
* Ported from magic-toolbox/agentkit/tools/interaction-tools.ts
|
|
6
6
|
*/
|
|
7
|
-
import { listAgentSessions, loadSessionMetadata } from
|
|
7
|
+
import { listAgentSessions, loadSessionMetadata, } from "../../config/sessions.js";
|
|
8
8
|
/**
|
|
9
9
|
* Create all interaction agent tools
|
|
10
10
|
*
|
|
11
11
|
* Returns tool definitions in the format expected by pi-coding-agent
|
|
12
12
|
*/
|
|
13
|
-
export function createInteractionTools(
|
|
13
|
+
export function createInteractionTools(_context) {
|
|
14
14
|
return [
|
|
15
15
|
{
|
|
16
|
-
name:
|
|
17
|
-
description:
|
|
16
|
+
name: "list_my_agents",
|
|
17
|
+
description: "List all agents you can message: your own specialist agents (by short name) and external agents that have contacted you (by full name).",
|
|
18
18
|
input_schema: {
|
|
19
|
-
type:
|
|
19
|
+
type: "object",
|
|
20
20
|
properties: {
|
|
21
21
|
limit: {
|
|
22
|
-
type:
|
|
23
|
-
description:
|
|
22
|
+
type: "number",
|
|
23
|
+
description: "Maximum number of agents to return (default: 20)",
|
|
24
24
|
},
|
|
25
25
|
},
|
|
26
26
|
},
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
|
-
name:
|
|
29
|
+
name: "send_message_to_agent",
|
|
30
30
|
description: 'Send a message to an EA. If task_name matches an existing EA, it will be resumed with full history. If not, a new EA will be created with that name. Use priority to control urgency: "urgent"/"high" will interrupt running EA immediately, "normal" will queue the message.',
|
|
31
31
|
input_schema: {
|
|
32
|
-
type:
|
|
32
|
+
type: "object",
|
|
33
33
|
properties: {
|
|
34
34
|
task_name: {
|
|
35
|
-
type:
|
|
35
|
+
type: "string",
|
|
36
36
|
description: 'Unique descriptive name for the EA (e.g., "magic-toolbox-worktrees", "merge-feature-branches")',
|
|
37
37
|
},
|
|
38
38
|
task: {
|
|
39
|
-
type:
|
|
40
|
-
description:
|
|
39
|
+
type: "string",
|
|
40
|
+
description: "Task description or message for the EA",
|
|
41
41
|
},
|
|
42
42
|
priority: {
|
|
43
|
-
type:
|
|
44
|
-
enum: [
|
|
43
|
+
type: "string",
|
|
44
|
+
enum: ["normal", "high", "urgent"],
|
|
45
45
|
description: 'Message priority: "normal" = queue (default), "high"/"urgent" = interrupt running EA immediately. Use high/urgent when: user says "stop/wait", new info invalidates current work, critical correction needed.',
|
|
46
|
-
default:
|
|
46
|
+
default: "normal",
|
|
47
47
|
},
|
|
48
48
|
},
|
|
49
|
-
required: [
|
|
49
|
+
required: ["task_name", "task"],
|
|
50
50
|
},
|
|
51
51
|
},
|
|
52
52
|
{
|
|
53
|
-
name:
|
|
54
|
-
description:
|
|
53
|
+
name: "inspect_agent",
|
|
54
|
+
description: "Get detailed info about a specific agent (for tie-breaking when multiple agents might match)",
|
|
55
55
|
input_schema: {
|
|
56
|
-
type:
|
|
56
|
+
type: "object",
|
|
57
57
|
properties: {
|
|
58
58
|
task_name: {
|
|
59
|
-
type:
|
|
60
|
-
description:
|
|
59
|
+
type: "string",
|
|
60
|
+
description: "The task_name of the EA to inspect",
|
|
61
61
|
},
|
|
62
62
|
},
|
|
63
|
-
required: [
|
|
63
|
+
required: ["task_name"],
|
|
64
64
|
},
|
|
65
65
|
},
|
|
66
66
|
];
|
|
@@ -71,13 +71,14 @@ export function createInteractionTools(context) {
|
|
|
71
71
|
* Called when a tool is invoked by the IA
|
|
72
72
|
*/
|
|
73
73
|
export async function handleToolInvocation(toolName, args, context) {
|
|
74
|
+
const payload = args && typeof args === "object" ? args : {};
|
|
74
75
|
switch (toolName) {
|
|
75
|
-
case
|
|
76
|
-
return await handleListMyAgents(
|
|
77
|
-
case
|
|
78
|
-
return await handleSendMessageToAgent(
|
|
79
|
-
case
|
|
80
|
-
return await handleInspectAgent(
|
|
76
|
+
case "list_my_agents":
|
|
77
|
+
return await handleListMyAgents(payload, context);
|
|
78
|
+
case "send_message_to_agent":
|
|
79
|
+
return await handleSendMessageToAgent(payload, context);
|
|
80
|
+
case "inspect_agent":
|
|
81
|
+
return await handleInspectAgent(payload, context);
|
|
81
82
|
default:
|
|
82
83
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
83
84
|
}
|
|
@@ -86,16 +87,18 @@ export async function handleToolInvocation(toolName, args, context) {
|
|
|
86
87
|
* Handle list_my_agents tool
|
|
87
88
|
*/
|
|
88
89
|
async function handleListMyAgents(args, context) {
|
|
89
|
-
const limit = args.limit
|
|
90
|
+
const limit = typeof args.limit === "number" && Number.isFinite(args.limit)
|
|
91
|
+
? Math.max(1, Math.trunc(args.limit))
|
|
92
|
+
: 20;
|
|
90
93
|
// Get own EAs from session storage
|
|
91
94
|
// EAs are stored as sessions with agentType: "execution" and parentSession set
|
|
92
|
-
const agentId = context.agentId.replace(
|
|
95
|
+
const agentId = context.agentId.replace("-ia", ""); // Convert 'toolbox-ia' to 'toolbox'
|
|
93
96
|
const allSessions = await listAgentSessions(agentId);
|
|
94
97
|
// Load metadata for each session to check agentType
|
|
95
98
|
const eaSessions = [];
|
|
96
99
|
for (const sessionKey of allSessions.slice(0, limit)) {
|
|
97
100
|
const metadata = await loadSessionMetadata(agentId, sessionKey);
|
|
98
|
-
if (metadata && metadata.agentType ===
|
|
101
|
+
if (metadata && metadata.agentType === "execution") {
|
|
99
102
|
eaSessions.push({
|
|
100
103
|
sessionKey,
|
|
101
104
|
metadata,
|
|
@@ -108,36 +111,39 @@ async function handleListMyAgents(args, context) {
|
|
|
108
111
|
const ownFormatted = eaSessions
|
|
109
112
|
.map((ea) => {
|
|
110
113
|
const updated = ea.metadata.updated; // New format uses 'updated' (ISO string)
|
|
111
|
-
const lastActiveDate = updated
|
|
114
|
+
const lastActiveDate = updated
|
|
115
|
+
? new Date(updated).toLocaleString()
|
|
116
|
+
: "Never";
|
|
112
117
|
const taskName = ea.sessionKey; // sessionKey is the task name
|
|
113
118
|
const displayName = ea.metadata.displayName || taskName;
|
|
114
119
|
const isActive = context.broker.isAgentActive(`${context.oduName}-ea-${taskName}`);
|
|
115
|
-
const status = isActive ?
|
|
120
|
+
const status = isActive ? "🟢 active" : "⚪ idle";
|
|
116
121
|
return `• ${displayName} (${status})\n Last active: ${lastActiveDate}`;
|
|
117
122
|
})
|
|
118
|
-
.join(
|
|
123
|
+
.join("\n\n");
|
|
119
124
|
// Format external callers (show full names)
|
|
120
125
|
const externalFormatted = externalAgentIds.length > 0
|
|
121
126
|
? externalAgentIds
|
|
122
127
|
.map((agentId) => {
|
|
123
128
|
const isActive = context.broker.isAgentActive(agentId);
|
|
124
|
-
const status = isActive ?
|
|
129
|
+
const status = isActive ? "🟢 active" : "⚪ idle";
|
|
125
130
|
return `• ${agentId} (${status})\n External agent - has sent you messages`;
|
|
126
131
|
})
|
|
127
|
-
.join(
|
|
128
|
-
:
|
|
132
|
+
.join("\n\n")
|
|
133
|
+
: "";
|
|
129
134
|
// Build response
|
|
130
|
-
let text =
|
|
135
|
+
let text = "";
|
|
131
136
|
if (eaSessions.length > 0) {
|
|
132
137
|
text += `Your Specialist Agents (${eaSessions.length}):\n\n${ownFormatted}`;
|
|
133
138
|
}
|
|
134
139
|
if (externalFormatted) {
|
|
135
140
|
if (text)
|
|
136
|
-
text +=
|
|
141
|
+
text += "\n\n---\n\n";
|
|
137
142
|
text += `External Agents (${externalAgentIds.length}):\n\n${externalFormatted}`;
|
|
138
143
|
}
|
|
139
144
|
if (!text) {
|
|
140
|
-
text =
|
|
145
|
+
text =
|
|
146
|
+
"No agents found. You can create a new one with send_message_to_agent.";
|
|
141
147
|
}
|
|
142
148
|
return text;
|
|
143
149
|
}
|
|
@@ -145,9 +151,12 @@ async function handleListMyAgents(args, context) {
|
|
|
145
151
|
* Handle send_message_to_agent tool
|
|
146
152
|
*/
|
|
147
153
|
async function handleSendMessageToAgent(args, context) {
|
|
148
|
-
const taskName = args.task_name;
|
|
149
|
-
const task = args.task;
|
|
150
|
-
|
|
154
|
+
const taskName = typeof args.task_name === "string" ? args.task_name : "";
|
|
155
|
+
const task = typeof args.task === "string" ? args.task : "";
|
|
156
|
+
if (!taskName || !task) {
|
|
157
|
+
throw new Error("Invalid arguments: task_name and task are required.");
|
|
158
|
+
}
|
|
159
|
+
const priority = typeof args.priority === "string" ? args.priority : "normal";
|
|
151
160
|
// Convert task_name to fully-qualified EA agent ID
|
|
152
161
|
const eaId = `${context.oduName}-ea-${taskName}`;
|
|
153
162
|
// Send message via broker
|
|
@@ -159,7 +168,7 @@ async function handleSendMessageToAgent(args, context) {
|
|
|
159
168
|
priority: priority,
|
|
160
169
|
timestamp: Date.now(),
|
|
161
170
|
metadata: {
|
|
162
|
-
source:
|
|
171
|
+
source: "ia",
|
|
163
172
|
taskName,
|
|
164
173
|
},
|
|
165
174
|
});
|
|
@@ -169,8 +178,11 @@ async function handleSendMessageToAgent(args, context) {
|
|
|
169
178
|
* Handle inspect_agent tool
|
|
170
179
|
*/
|
|
171
180
|
async function handleInspectAgent(args, context) {
|
|
172
|
-
const taskName = args.task_name;
|
|
173
|
-
|
|
181
|
+
const taskName = typeof args.task_name === "string" ? args.task_name : "";
|
|
182
|
+
if (!taskName) {
|
|
183
|
+
throw new Error("Invalid arguments: task_name is required.");
|
|
184
|
+
}
|
|
185
|
+
const agentId = context.agentId.replace("-ia", ""); // Convert 'toolbox-ia' to 'toolbox'
|
|
174
186
|
// Load session metadata
|
|
175
187
|
const metadata = await loadSessionMetadata(agentId, taskName);
|
|
176
188
|
if (!metadata) {
|
|
@@ -178,13 +190,13 @@ async function handleInspectAgent(args, context) {
|
|
|
178
190
|
}
|
|
179
191
|
const updated = metadata.updated; // New format uses 'updated' (ISO string)
|
|
180
192
|
const created = metadata.created; // New format uses 'created' (ISO string)
|
|
181
|
-
const lastActiveDate = updated ? new Date(updated).toLocaleString() :
|
|
182
|
-
const createdDate = created ? new Date(created).toLocaleString() :
|
|
193
|
+
const lastActiveDate = updated ? new Date(updated).toLocaleString() : "Never";
|
|
194
|
+
const createdDate = created ? new Date(created).toLocaleString() : "Unknown";
|
|
183
195
|
const displayName = metadata.displayName || taskName;
|
|
184
196
|
// Check if agent is currently active
|
|
185
197
|
const eaId = `${context.oduName}-ea-${taskName}`;
|
|
186
198
|
const isActive = context.broker.isAgentActive(eaId);
|
|
187
|
-
const status = isActive ?
|
|
199
|
+
const status = isActive ? "🟢 active" : "⚪ idle";
|
|
188
200
|
return `EA: ${displayName} (${status})
|
|
189
201
|
|
|
190
202
|
Task Name: ${taskName}
|
|
@@ -192,5 +204,5 @@ Created: ${createdDate}
|
|
|
192
204
|
Last Active: ${lastActiveDate}
|
|
193
205
|
Compactions: ${metadata.compactionCount || 0}
|
|
194
206
|
|
|
195
|
-
This EA specializes in: ${metadata.displayName ||
|
|
207
|
+
This EA specializes in: ${metadata.displayName || "general tasks"}`;
|
|
196
208
|
}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* Loads prompt templates from files and substitutes {{variable}} patterns.
|
|
5
5
|
* Similar to magic-toolbox/agentkit/prompts/loader.ts
|
|
6
6
|
*/
|
|
7
|
-
import fs from
|
|
8
|
-
import path from
|
|
9
|
-
import { resolveUserPath } from
|
|
7
|
+
import fs from "node:fs/promises";
|
|
8
|
+
import path from "node:path";
|
|
9
|
+
import { resolveUserPath } from "../../utils.js";
|
|
10
10
|
/**
|
|
11
11
|
* Cache for loaded prompts (performance optimization)
|
|
12
12
|
*/
|
|
@@ -29,7 +29,7 @@ export async function loadPrompt(promptPath, variables = {}) {
|
|
|
29
29
|
let template = promptCache.get(cacheKey);
|
|
30
30
|
if (!template) {
|
|
31
31
|
// Load from file
|
|
32
|
-
template = await fs.readFile(resolvedPath,
|
|
32
|
+
template = await fs.readFile(resolvedPath, "utf-8");
|
|
33
33
|
// Cache the template
|
|
34
34
|
promptCache.set(cacheKey, template);
|
|
35
35
|
}
|
|
@@ -51,7 +51,7 @@ async function resolvePromptPath(promptPath) {
|
|
|
51
51
|
return promptPath;
|
|
52
52
|
}
|
|
53
53
|
// Try workspace prompts/ directory first
|
|
54
|
-
const workspacePath = path.join(resolveUserPath(
|
|
54
|
+
const workspacePath = path.join(resolveUserPath("~/nexus/home"), "prompts", promptPath);
|
|
55
55
|
try {
|
|
56
56
|
await fs.access(workspacePath);
|
|
57
57
|
return workspacePath;
|
|
@@ -61,8 +61,8 @@ async function resolvePromptPath(promptPath) {
|
|
|
61
61
|
}
|
|
62
62
|
// Try nexus bundled prompts/ directory
|
|
63
63
|
// (Resolve relative to this file's directory)
|
|
64
|
-
const nexusRootPath = path.resolve(new URL(import.meta.url).pathname,
|
|
65
|
-
const bundledPath = path.join(nexusRootPath,
|
|
64
|
+
const nexusRootPath = path.resolve(new URL(import.meta.url).pathname, "../../../..");
|
|
65
|
+
const bundledPath = path.join(nexusRootPath, "prompts", promptPath);
|
|
66
66
|
try {
|
|
67
67
|
await fs.access(bundledPath);
|
|
68
68
|
return bundledPath;
|
|
@@ -82,7 +82,7 @@ function substituteVariables(template, variables) {
|
|
|
82
82
|
let result = template;
|
|
83
83
|
// Replace all {{variable}} patterns
|
|
84
84
|
for (const [key, value] of Object.entries(variables)) {
|
|
85
|
-
const pattern = new RegExp(`\\{\\{${key}\\}\\}`,
|
|
85
|
+
const pattern = new RegExp(`\\{\\{${key}\\}\\}`, "g");
|
|
86
86
|
result = result.replace(pattern, value);
|
|
87
87
|
}
|
|
88
88
|
return result;
|