@phronesis-io/openclaw-eigenflux 0.0.3 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +15 -161
- package/dist/agent-prompt-templates.d.ts +14 -11
- package/dist/agent-prompt-templates.d.ts.map +1 -1
- package/dist/agent-prompt-templates.js +27 -38
- package/dist/agent-prompt-templates.js.map +1 -1
- package/dist/cli-executor.d.ts +32 -0
- package/dist/cli-executor.d.ts.map +1 -0
- package/dist/cli-executor.js +75 -0
- package/dist/cli-executor.js.map +1 -0
- package/dist/config.d.ts +41 -126
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +94 -229
- package/dist/config.js.map +1 -1
- package/dist/credentials-loader.d.ts +6 -5
- package/dist/credentials-loader.d.ts.map +1 -1
- package/dist/credentials-loader.js +17 -21
- package/dist/credentials-loader.js.map +1 -1
- package/dist/index.d.ts +3 -73
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +212 -276
- package/dist/index.js.map +1 -1
- package/dist/notification-route-resolver.d.ts +24 -2
- package/dist/notification-route-resolver.d.ts.map +1 -1
- package/dist/notification-route-resolver.js +257 -43
- package/dist/notification-route-resolver.js.map +1 -1
- package/dist/notifier.d.ts +9 -17
- package/dist/notifier.d.ts.map +1 -1
- package/dist/notifier.js +133 -66
- package/dist/notifier.js.map +1 -1
- package/dist/polling-client.d.ts +31 -19
- package/dist/polling-client.d.ts.map +1 -1
- package/dist/polling-client.js +102 -127
- package/dist/polling-client.js.map +1 -1
- package/dist/reply-target.d.ts +8 -0
- package/dist/reply-target.d.ts.map +1 -0
- package/dist/reply-target.js +104 -0
- package/dist/reply-target.js.map +1 -0
- package/dist/session-route-memory.d.ts +12 -3
- package/dist/session-route-memory.d.ts.map +1 -1
- package/dist/session-route-memory.js +83 -80
- package/dist/session-route-memory.js.map +1 -1
- package/dist/stream-client.d.ts +48 -0
- package/dist/stream-client.d.ts.map +1 -0
- package/dist/stream-client.js +168 -0
- package/dist/stream-client.js.map +1 -0
- package/openclaw.plugin.json +5 -75
- package/package.json +6 -8
- package/skills/ef-broadcast/SKILL.md +84 -0
- package/skills/ef-broadcast/references/feed.md +127 -0
- package/skills/ef-broadcast/references/publish.md +119 -0
- package/skills/ef-communication/SKILL.md +95 -0
- package/skills/ef-communication/references/message.md +132 -0
- package/skills/ef-communication/references/relations.md +215 -0
- package/skills/ef-communication/references/stream.md +66 -0
- package/skills/ef-profile/SKILL.md +138 -0
- package/skills/ef-profile/references/auth.md +103 -0
- package/skills/ef-profile/references/config.md +54 -0
- package/skills/ef-profile/references/onboarding.md +172 -0
- package/skills/ef-profile/references/server-management.md +67 -0
- package/dist/gateway-rpc-client.d.ts +0 -26
- package/dist/gateway-rpc-client.d.ts.map +0 -1
- package/dist/gateway-rpc-client.js +0 -288
- package/dist/gateway-rpc-client.js.map +0 -1
- package/dist/pm-polling-client.d.ts +0 -52
- package/dist/pm-polling-client.d.ts.map +0 -1
- package/dist/pm-polling-client.js +0 -182
- package/dist/pm-polling-client.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,130 +1,179 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const polling_client_1 = require("./polling-client");
|
|
4
|
-
const
|
|
4
|
+
const stream_client_1 = require("./stream-client");
|
|
5
|
+
const cli_executor_1 = require("./cli-executor");
|
|
5
6
|
const logger_1 = require("./logger");
|
|
6
7
|
const credentials_loader_1 = require("./credentials-loader");
|
|
7
8
|
const config_1 = require("./config");
|
|
8
9
|
const notification_route_resolver_1 = require("./notification-route-resolver");
|
|
9
10
|
const agent_prompt_templates_1 = require("./agent-prompt-templates");
|
|
10
11
|
const notifier_1 = require("./notifier");
|
|
12
|
+
const reply_target_1 = require("./reply-target");
|
|
11
13
|
const session_route_memory_1 = require("./session-route-memory");
|
|
12
14
|
const COMMAND_NAMES = ['auth', 'profile', 'servers', 'feed', 'pm', 'here'];
|
|
13
15
|
const COMMAND_NAME_SET = new Set(COMMAND_NAMES);
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
const DEFAULT_ROUTING = {
|
|
17
|
+
sessionKey: config_1.PLUGIN_CONFIG.DEFAULT_SESSION_KEY,
|
|
18
|
+
agentId: config_1.PLUGIN_CONFIG.DEFAULT_AGENT_ID,
|
|
19
|
+
routeOverrides: {
|
|
20
|
+
sessionKey: false,
|
|
21
|
+
agentId: false,
|
|
22
|
+
replyChannel: false,
|
|
23
|
+
replyTo: false,
|
|
24
|
+
replyAccountId: false,
|
|
25
|
+
},
|
|
26
|
+
};
|
|
18
27
|
function register(api) {
|
|
19
|
-
const logger = new logger_1.Logger(api
|
|
20
|
-
|
|
21
|
-
const
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
const logger = new logger_1.Logger(resolvePluginLogger(api));
|
|
29
|
+
const pluginConfig = (0, config_1.resolvePluginConfig)(api.pluginConfig, logger);
|
|
30
|
+
const eigenfluxHome = (0, config_1.resolveEigenfluxHome)();
|
|
31
|
+
let runtimes = [];
|
|
32
|
+
let notInstalledPromptDelivered = false;
|
|
33
|
+
// Register a single meta-service that discovers servers on start
|
|
34
|
+
api.registerService({
|
|
35
|
+
id: 'eigenflux:discovery',
|
|
36
|
+
start: async () => {
|
|
37
|
+
logger.info('Starting EigenFlux discovery service...');
|
|
38
|
+
const discovery = await (0, config_1.discoverServers)(pluginConfig.eigenfluxBin, logger);
|
|
39
|
+
if (discovery.kind === 'not_installed') {
|
|
40
|
+
logger.warn(`EigenFlux CLI not installed (bin=${discovery.bin}); delivering install prompt to user`);
|
|
41
|
+
if (!notInstalledPromptDelivered) {
|
|
42
|
+
notInstalledPromptDelivered = true;
|
|
43
|
+
await deliverNotInstalledPrompt(api, logger, pluginConfig, eigenfluxHome, discovery.bin);
|
|
44
|
+
}
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const servers = discovery.servers;
|
|
48
|
+
if (servers.length === 0) {
|
|
49
|
+
logger.warn('No EigenFlux servers discovered; services will not start');
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
logger.info(`Discovered ${servers.length} server(s): ${servers.map((s) => s.name).join(', ')}`);
|
|
53
|
+
runtimes = servers.map((server) => createServerRuntime(api, logger, pluginConfig, server, eigenfluxHome));
|
|
54
|
+
for (const runtime of runtimes) {
|
|
55
|
+
logger.info(`Starting services for server=${runtime.server.name}`);
|
|
56
|
+
await runtime.feedPoller.start();
|
|
57
|
+
await runtime.streamClient.start();
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
stop: async () => {
|
|
61
|
+
logger.info('Stopping EigenFlux discovery service...');
|
|
62
|
+
for (const runtime of runtimes) {
|
|
63
|
+
logger.info(`Stopping services for server=${runtime.server.name}`);
|
|
64
|
+
runtime.feedPoller.stop();
|
|
65
|
+
await runtime.streamClient.stop();
|
|
66
|
+
}
|
|
67
|
+
runtimes = [];
|
|
68
|
+
notInstalledPromptDelivered = false;
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
registerCommand(api, logger, pluginConfig, eigenfluxHome, () => runtimes);
|
|
72
|
+
}
|
|
73
|
+
function resolvePluginLogger(api) {
|
|
74
|
+
const runtimeLogging = api.runtime?.logging;
|
|
75
|
+
if (runtimeLogging && typeof runtimeLogging.getChildLogger === 'function') {
|
|
76
|
+
try {
|
|
77
|
+
const child = runtimeLogging.getChildLogger({ plugin: 'eigenflux' });
|
|
78
|
+
if (child) {
|
|
79
|
+
return child;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
// fall through to api.logger
|
|
84
|
+
}
|
|
29
85
|
}
|
|
30
|
-
|
|
31
|
-
registerCommand(api, logger, runtimes);
|
|
32
|
-
logger.info(`EigenFlux activated with ${enabledRuntimes.length}/${runtimes.length} enabled server(s)`);
|
|
86
|
+
return api.logger;
|
|
33
87
|
}
|
|
34
88
|
const plugin = {
|
|
35
89
|
id: 'openclaw-eigenflux',
|
|
36
90
|
name: 'EigenFlux',
|
|
37
|
-
description: 'OpenClaw extension for EigenFlux
|
|
91
|
+
description: 'OpenClaw extension for EigenFlux with CLI-based feed polling and PM streaming',
|
|
38
92
|
configSchema: config_1.PLUGIN_CONFIG_SCHEMA,
|
|
39
93
|
register,
|
|
40
94
|
};
|
|
41
95
|
exports.default = plugin;
|
|
42
|
-
|
|
43
|
-
|
|
96
|
+
const INSTALL_COMMAND = 'curl -fsSL https://eigenflux.ai/install.sh | bash';
|
|
97
|
+
async function deliverNotInstalledPrompt(api, logger, pluginConfig, _eigenfluxHome, bin) {
|
|
98
|
+
// Intentionally no workdir: the bootstrap notifier must not read or persist
|
|
99
|
+
// any remembered session route under <eigenfluxHome>/bootstrap.
|
|
100
|
+
const notifier = new notifier_1.EigenFluxNotifier(api, logger, {
|
|
101
|
+
sessionKey: DEFAULT_ROUTING.sessionKey,
|
|
102
|
+
agentId: DEFAULT_ROUTING.agentId,
|
|
103
|
+
replyChannel: DEFAULT_ROUTING.replyChannel,
|
|
104
|
+
replyTo: DEFAULT_ROUTING.replyTo,
|
|
105
|
+
replyAccountId: DEFAULT_ROUTING.replyAccountId,
|
|
106
|
+
openclawCliBin: pluginConfig.openclawCliBin,
|
|
107
|
+
routeOverrides: DEFAULT_ROUTING.routeOverrides,
|
|
108
|
+
});
|
|
109
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildNotInstalledPromptTemplate)({ bin, installCommand: INSTALL_COMMAND }));
|
|
110
|
+
}
|
|
111
|
+
function createServerRuntime(api, logger, pluginConfig, server, eigenfluxHome) {
|
|
112
|
+
const routing = pluginConfig.serverRouting[server.name] ?? DEFAULT_ROUTING;
|
|
113
|
+
const credentialsLoader = new credentials_loader_1.CredentialsLoader(logger, eigenfluxHome, server.name);
|
|
44
114
|
const notifier = new notifier_1.EigenFluxNotifier(api, logger, {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
replyAccountId: server.replyAccountId,
|
|
115
|
+
eigenfluxBin: pluginConfig.eigenfluxBin,
|
|
116
|
+
serverName: server.name,
|
|
117
|
+
sessionKey: routing.sessionKey,
|
|
118
|
+
agentId: routing.agentId,
|
|
119
|
+
replyChannel: routing.replyChannel,
|
|
120
|
+
replyTo: routing.replyTo,
|
|
121
|
+
replyAccountId: routing.replyAccountId,
|
|
53
122
|
openclawCliBin: pluginConfig.openclawCliBin,
|
|
54
|
-
|
|
55
|
-
routeOverrides: server.routeOverrides,
|
|
123
|
+
routeOverrides: routing.routeOverrides,
|
|
56
124
|
});
|
|
57
125
|
const getPromptContext = () => ({
|
|
58
126
|
serverName: server.name,
|
|
59
|
-
|
|
60
|
-
skillPath: (0, config_1.resolveServerSkillPath)(server),
|
|
127
|
+
eigenfluxHome,
|
|
61
128
|
});
|
|
62
129
|
let lastAuthPromptKey = null;
|
|
63
130
|
const resetAuthPromptGate = () => {
|
|
64
131
|
lastAuthPromptKey = null;
|
|
65
132
|
};
|
|
66
133
|
const notifyAuthRequired = async (authEvent) => {
|
|
67
|
-
const promptKey =
|
|
134
|
+
const promptKey = `auth_required:${server.name}`;
|
|
68
135
|
if (lastAuthPromptKey === promptKey) {
|
|
69
|
-
logger.debug(`Skipping duplicate auth prompt for server=${server.name}
|
|
136
|
+
logger.debug(`Skipping duplicate auth prompt for server=${server.name}`);
|
|
70
137
|
return;
|
|
71
138
|
}
|
|
72
139
|
lastAuthPromptKey = promptKey;
|
|
73
|
-
|
|
74
|
-
await notifier.deliver(buildAuthRequiredMessage(getPromptContext(), {
|
|
75
|
-
authEvent,
|
|
76
|
-
authState,
|
|
77
|
-
}));
|
|
140
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({ context: getPromptContext() }));
|
|
78
141
|
};
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
142
|
+
const feedPoller = new polling_client_1.EigenFluxPollingClient({
|
|
143
|
+
serverName: server.name,
|
|
144
|
+
eigenfluxBin: pluginConfig.eigenfluxBin,
|
|
145
|
+
resolvePollIntervalSec: () => (0, polling_client_1.readPollIntervalSec)(pluginConfig.eigenfluxBin, server.name, logger),
|
|
83
146
|
logger,
|
|
84
147
|
onFeedPolled: async (payload) => {
|
|
85
148
|
resetAuthPromptGate();
|
|
86
|
-
await notifier.deliver(
|
|
149
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildFeedPayloadPromptTemplate)(payload, getPromptContext()));
|
|
87
150
|
},
|
|
88
151
|
onAuthRequired: notifyAuthRequired,
|
|
89
152
|
});
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
pollIntervalSec: server.pmPollIntervalSec,
|
|
153
|
+
const streamClient = new stream_client_1.EigenFluxStreamClient({
|
|
154
|
+
serverName: server.name,
|
|
155
|
+
eigenfluxBin: pluginConfig.eigenfluxBin,
|
|
94
156
|
logger,
|
|
95
|
-
|
|
157
|
+
onPmEvent: async (event) => {
|
|
96
158
|
resetAuthPromptGate();
|
|
97
|
-
await notifier.deliver(
|
|
159
|
+
await notifier.deliver((0, agent_prompt_templates_1.buildPmStreamEventPromptTemplate)(event, getPromptContext()));
|
|
160
|
+
},
|
|
161
|
+
onAuthRequired: async () => {
|
|
162
|
+
await notifyAuthRequired({ reason: 'auth_required' });
|
|
98
163
|
},
|
|
99
|
-
onAuthRequired: notifyAuthRequired,
|
|
100
164
|
});
|
|
101
165
|
return {
|
|
102
166
|
server,
|
|
167
|
+
routing,
|
|
103
168
|
credentialsLoader,
|
|
104
169
|
notifier,
|
|
105
|
-
|
|
106
|
-
|
|
170
|
+
feedPoller,
|
|
171
|
+
streamClient,
|
|
107
172
|
getPromptContext,
|
|
108
173
|
};
|
|
109
174
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
api.registerService({
|
|
113
|
-
id: `eigenflux:${toServiceIdSegment(runtime.server.name)}`,
|
|
114
|
-
start: async () => {
|
|
115
|
-
logger.info(`Starting EigenFlux polling services for server=${runtime.server.name}`);
|
|
116
|
-
await runtime.pollingClient.start();
|
|
117
|
-
await runtime.pmPollingClient.start();
|
|
118
|
-
},
|
|
119
|
-
stop: async () => {
|
|
120
|
-
logger.info(`Stopping EigenFlux polling services for server=${runtime.server.name}`);
|
|
121
|
-
runtime.pollingClient.stop();
|
|
122
|
-
runtime.pmPollingClient.stop();
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
function registerCommand(api, logger, runtimes) {
|
|
175
|
+
// ─── Command Handler ────────────────────────────────────────────────────────
|
|
176
|
+
function registerCommand(api, logger, pluginConfig, eigenfluxHome, getRuntimes) {
|
|
128
177
|
if (!api.registerCommand) {
|
|
129
178
|
logger.warn('registerCommand API unavailable; skipping /eigenflux command registration');
|
|
130
179
|
return;
|
|
@@ -135,6 +184,7 @@ function registerCommand(api, logger, runtimes) {
|
|
|
135
184
|
acceptsArgs: true,
|
|
136
185
|
handler: async (ctx) => {
|
|
137
186
|
const parsed = parseCommandArgs(ctx.args);
|
|
187
|
+
const runtimes = getRuntimes();
|
|
138
188
|
if (parsed.command === 'servers') {
|
|
139
189
|
return {
|
|
140
190
|
text: buildServersText(runtimes),
|
|
@@ -147,27 +197,27 @@ function registerCommand(api, logger, runtimes) {
|
|
|
147
197
|
};
|
|
148
198
|
}
|
|
149
199
|
const runtime = selection.runtime;
|
|
150
|
-
await rememberCurrentCommandRouteIfPossible(ctx, runtime.
|
|
200
|
+
await rememberCurrentCommandRouteIfPossible(ctx, runtime, pluginConfig.eigenfluxBin, logger);
|
|
151
201
|
switch (parsed.command) {
|
|
152
202
|
case 'auth':
|
|
153
203
|
return {
|
|
154
|
-
text: buildAuthStatusText(runtime
|
|
204
|
+
text: buildAuthStatusText(runtime),
|
|
155
205
|
};
|
|
156
206
|
case 'profile':
|
|
157
207
|
return {
|
|
158
|
-
text: await buildProfileText(runtime,
|
|
208
|
+
text: await buildProfileText(runtime, pluginConfig.eigenfluxBin),
|
|
159
209
|
};
|
|
160
210
|
case 'feed':
|
|
161
211
|
return {
|
|
162
|
-
text: await buildFeedText(runtime
|
|
212
|
+
text: await buildFeedText(runtime),
|
|
163
213
|
};
|
|
164
214
|
case 'pm':
|
|
165
215
|
return {
|
|
166
|
-
text:
|
|
216
|
+
text: buildPmStatusText(runtime),
|
|
167
217
|
};
|
|
168
218
|
case 'here':
|
|
169
219
|
return {
|
|
170
|
-
text: await buildHereText(ctx, runtime.
|
|
220
|
+
text: await buildHereText(ctx, runtime, pluginConfig.eigenfluxBin, logger),
|
|
171
221
|
};
|
|
172
222
|
default:
|
|
173
223
|
return {
|
|
@@ -199,7 +249,7 @@ function parseCommandArgs(args) {
|
|
|
199
249
|
function selectServerRuntime(runtimes, requestedServerName) {
|
|
200
250
|
if (runtimes.length === 0) {
|
|
201
251
|
return {
|
|
202
|
-
error: 'No EigenFlux servers
|
|
252
|
+
error: 'No EigenFlux servers discovered. Ensure eigenflux CLI is configured with at least one server.',
|
|
203
253
|
};
|
|
204
254
|
}
|
|
205
255
|
if (!requestedServerName) {
|
|
@@ -221,19 +271,19 @@ function selectServerRuntime(runtimes, requestedServerName) {
|
|
|
221
271
|
}
|
|
222
272
|
function buildServersText(runtimes) {
|
|
223
273
|
if (runtimes.length === 0) {
|
|
224
|
-
return 'No EigenFlux servers
|
|
274
|
+
return 'No EigenFlux servers discovered.';
|
|
225
275
|
}
|
|
226
|
-
const defaultRuntime = runtimes[0];
|
|
227
276
|
return [
|
|
228
|
-
'EigenFlux servers:',
|
|
277
|
+
'EigenFlux servers (discovered via CLI):',
|
|
229
278
|
...runtimes.map((runtime) => {
|
|
230
279
|
const flags = [
|
|
231
|
-
runtime.server.
|
|
232
|
-
|
|
280
|
+
runtime.server.current ? 'default' : null,
|
|
281
|
+
runtime.streamClient.isRunning() ? 'streaming' : null,
|
|
233
282
|
]
|
|
234
283
|
.filter(Boolean)
|
|
235
284
|
.join(', ');
|
|
236
|
-
|
|
285
|
+
const suffix = flags ? ` (${flags})` : '';
|
|
286
|
+
return `- ${runtime.server.name}: endpoint=${runtime.server.endpoint}${suffix}`;
|
|
237
287
|
}),
|
|
238
288
|
].join('\n');
|
|
239
289
|
}
|
|
@@ -247,23 +297,12 @@ function buildHelpText(runtimes) {
|
|
|
247
297
|
? `Available servers: ${runtimes.map((runtime) => runtime.server.name).join(', ')}`
|
|
248
298
|
: undefined,
|
|
249
299
|
'',
|
|
250
|
-
'/eigenflux auth',
|
|
251
|
-
'
|
|
252
|
-
'',
|
|
253
|
-
'/eigenflux
|
|
254
|
-
'
|
|
255
|
-
'',
|
|
256
|
-
'/eigenflux servers',
|
|
257
|
-
'List configured EigenFlux servers.',
|
|
258
|
-
'',
|
|
259
|
-
'/eigenflux feed',
|
|
260
|
-
'Run one feed refresh and return the raw feed payload.',
|
|
261
|
-
'',
|
|
262
|
-
'/eigenflux pm',
|
|
263
|
-
'Run one PM fetch and return the raw PM payload.',
|
|
264
|
-
'',
|
|
265
|
-
'/eigenflux here',
|
|
266
|
-
'Remember the current conversation as the default delivery route for the selected server.',
|
|
300
|
+
'/eigenflux auth — Show credential status',
|
|
301
|
+
'/eigenflux profile — Fetch agent profile',
|
|
302
|
+
'/eigenflux servers — List discovered servers',
|
|
303
|
+
'/eigenflux feed — Run one feed refresh',
|
|
304
|
+
'/eigenflux pm — Show PM stream status',
|
|
305
|
+
'/eigenflux here — Remember current conversation as delivery route',
|
|
267
306
|
]
|
|
268
307
|
.filter(Boolean)
|
|
269
308
|
.join('\n');
|
|
@@ -286,98 +325,51 @@ function isInternalAgentSessionKey(value) {
|
|
|
286
325
|
const parts = trimmed.split(':').filter((part) => part.length > 0);
|
|
287
326
|
return parts[0]?.toLowerCase() === 'agent' && parts[2]?.toLowerCase() === 'main';
|
|
288
327
|
}
|
|
289
|
-
function
|
|
290
|
-
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
if (!trimmed) {
|
|
295
|
-
return undefined;
|
|
296
|
-
}
|
|
297
|
-
if (isNormalizedConversationTarget(trimmed)) {
|
|
298
|
-
return trimmed;
|
|
299
|
-
}
|
|
300
|
-
if (channel && trimmed.startsWith(`${channel}:`)) {
|
|
301
|
-
const inner = trimmed.slice(channel.length + 1).trim();
|
|
302
|
-
if (isNormalizedConversationTarget(inner)) {
|
|
303
|
-
return inner;
|
|
304
|
-
}
|
|
305
|
-
return fallbackKind ? `${fallbackKind}:${inner}` : inner;
|
|
306
|
-
}
|
|
307
|
-
return fallbackKind ? `${fallbackKind}:${trimmed}` : trimmed;
|
|
308
|
-
}
|
|
309
|
-
async function resolveCurrentCommandRoute(ctx, serverConfig, logger) {
|
|
310
|
-
const channel = normalizeChannel(ctx.channel);
|
|
311
|
-
const accountId = readNonEmptyString(ctx.accountId);
|
|
312
|
-
let replyChannel = channel;
|
|
313
|
-
let replyTo = normalizeReplyTarget(ctx.to, channel) ?? normalizeReplyTarget(ctx.from, channel, 'user');
|
|
314
|
-
let replyAccountId = accountId;
|
|
328
|
+
async function resolveCurrentCommandRoute(ctx, runtime, logger) {
|
|
329
|
+
let channel = normalizeChannel(ctx.channel);
|
|
330
|
+
let to = (0, reply_target_1.normalizeReplyTarget)(ctx.to, { channel }) ??
|
|
331
|
+
(0, reply_target_1.normalizeReplyTarget)(ctx.from, { channel, fallbackKind: 'user' });
|
|
332
|
+
let accountId = readNonEmptyString(ctx.accountId);
|
|
315
333
|
if (typeof ctx.getCurrentConversationBinding === 'function') {
|
|
316
334
|
try {
|
|
317
335
|
const binding = await ctx.getCurrentConversationBinding();
|
|
318
336
|
if (binding) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
normalizeReplyTarget(binding.conversationId,
|
|
322
|
-
normalizeReplyTarget(binding.parentConversationId,
|
|
323
|
-
|
|
324
|
-
|
|
337
|
+
channel = normalizeChannel(binding.channel) ?? channel;
|
|
338
|
+
to =
|
|
339
|
+
(0, reply_target_1.normalizeReplyTarget)(binding.conversationId, { channel }) ??
|
|
340
|
+
(0, reply_target_1.normalizeReplyTarget)(binding.parentConversationId, { channel }) ??
|
|
341
|
+
to;
|
|
342
|
+
accountId = readNonEmptyString(binding.accountId) ?? accountId;
|
|
325
343
|
}
|
|
326
344
|
}
|
|
327
345
|
catch (error) {
|
|
328
346
|
logger.debug(`Failed to read current conversation binding: ${error instanceof Error ? error.message : String(error)}`);
|
|
329
347
|
}
|
|
330
348
|
}
|
|
331
|
-
if (!
|
|
349
|
+
if (!channel || !to) {
|
|
332
350
|
return undefined;
|
|
333
351
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
replyAccountId,
|
|
340
|
-
sessionStorePath: readServerSessionStorePath(serverConfig),
|
|
341
|
-
workdir: serverConfig.workdir,
|
|
342
|
-
routeOverrides: {
|
|
343
|
-
sessionKey: false,
|
|
344
|
-
agentId: false,
|
|
345
|
-
replyChannel: true,
|
|
346
|
-
replyTo: true,
|
|
347
|
-
replyAccountId: replyAccountId !== undefined,
|
|
348
|
-
},
|
|
352
|
+
return (0, notification_route_resolver_1.findSessionRouteForBinding)({
|
|
353
|
+
agentId: runtime.routing.agentId,
|
|
354
|
+
channel,
|
|
355
|
+
to,
|
|
356
|
+
accountId,
|
|
349
357
|
}, logger);
|
|
350
|
-
if (!route.replyChannel || !route.replyTo) {
|
|
351
|
-
return undefined;
|
|
352
|
-
}
|
|
353
|
-
if (isInternalAgentSessionKey(route.sessionKey)) {
|
|
354
|
-
const configuredSessionKey = readNonEmptyString(serverConfig.sessionKey);
|
|
355
|
-
if (configuredSessionKey && !isInternalAgentSessionKey(configuredSessionKey)) {
|
|
356
|
-
return {
|
|
357
|
-
sessionKey: configuredSessionKey,
|
|
358
|
-
agentId: readNonEmptyString(serverConfig.agentId) ?? route.agentId,
|
|
359
|
-
replyChannel: route.replyChannel,
|
|
360
|
-
replyTo: route.replyTo,
|
|
361
|
-
replyAccountId: route.replyAccountId,
|
|
362
|
-
};
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
return route;
|
|
366
358
|
}
|
|
367
|
-
async function buildHereText(ctx,
|
|
368
|
-
const route = await resolveCurrentCommandRoute(ctx,
|
|
359
|
+
async function buildHereText(ctx, runtime, eigenfluxBin, logger) {
|
|
360
|
+
const route = await resolveCurrentCommandRoute(ctx, runtime, logger);
|
|
369
361
|
if (!route || route.sessionKey === 'main' || route.sessionKey.endsWith(':main')) {
|
|
370
362
|
return [
|
|
371
|
-
`Unable to resolve the current external session for server=${
|
|
363
|
+
`Unable to resolve the current external session for server=${runtime.server.name}.`,
|
|
372
364
|
'Run `/eigenflux here` inside the target conversation after OpenClaw has already created a session for it.',
|
|
373
365
|
].join('\n');
|
|
374
366
|
}
|
|
375
|
-
const saved = (0, session_route_memory_1.writeStoredNotificationRoute)(
|
|
367
|
+
const saved = await (0, session_route_memory_1.writeStoredNotificationRoute)(eigenfluxBin, runtime.server.name, route, logger);
|
|
376
368
|
if (!saved) {
|
|
377
|
-
return `Failed to persist the current EigenFlux route for server=${
|
|
369
|
+
return `Failed to persist the current EigenFlux route for server=${runtime.server.name}; check plugin logs for details.`;
|
|
378
370
|
}
|
|
379
371
|
return [
|
|
380
|
-
`EigenFlux server ${
|
|
372
|
+
`EigenFlux server ${runtime.server.name} will deliver to this conversation by default:`,
|
|
381
373
|
`sessionKey: ${route.sessionKey}`,
|
|
382
374
|
`agentId: ${route.agentId}`,
|
|
383
375
|
`channel: ${route.replyChannel ?? 'unknown'}`,
|
|
@@ -387,42 +379,52 @@ async function buildHereText(ctx, serverConfig, logger) {
|
|
|
387
379
|
.filter(Boolean)
|
|
388
380
|
.join('\n');
|
|
389
381
|
}
|
|
390
|
-
async function rememberCurrentCommandRouteIfPossible(ctx,
|
|
391
|
-
const route = await resolveCurrentCommandRoute(ctx,
|
|
382
|
+
async function rememberCurrentCommandRouteIfPossible(ctx, runtime, eigenfluxBin, logger) {
|
|
383
|
+
const route = await resolveCurrentCommandRoute(ctx, runtime, logger);
|
|
392
384
|
if (!route || route.sessionKey === 'main' || route.sessionKey.endsWith(':main')) {
|
|
393
385
|
return;
|
|
394
386
|
}
|
|
395
|
-
if ((0, session_route_memory_1.writeStoredNotificationRoute)(
|
|
396
|
-
logger.debug(`Remembered current command route for server=${
|
|
387
|
+
if (await (0, session_route_memory_1.writeStoredNotificationRoute)(eigenfluxBin, runtime.server.name, route, logger)) {
|
|
388
|
+
logger.debug(`Remembered current command route for server=${runtime.server.name}: session_key=${route.sessionKey}, channel=${route.replyChannel ?? 'unknown'}, to=${route.replyTo ?? 'unknown'}`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
// ─── Command Handlers ───────────────────────────────────────────────────────
|
|
392
|
+
function buildAuthStatusText(runtime) {
|
|
393
|
+
const authState = runtime.credentialsLoader.loadAuthState();
|
|
394
|
+
const lines = [`EigenFlux auth status (server=${runtime.server.name}):`];
|
|
395
|
+
lines.push(`- credentials_path: ${authState.credentialsPath}`);
|
|
396
|
+
lines.push(`- status: ${authState.status}`);
|
|
397
|
+
if (authState.expiresAt) {
|
|
398
|
+
lines.push(`- expires_at: ${authState.expiresAt}`);
|
|
399
|
+
}
|
|
400
|
+
if (authState.status === 'available') {
|
|
401
|
+
lines.push(`- token: ${maskToken(authState.accessToken)}`);
|
|
397
402
|
}
|
|
403
|
+
else {
|
|
404
|
+
lines.push('- token: unavailable');
|
|
405
|
+
}
|
|
406
|
+
return lines.join('\n');
|
|
398
407
|
}
|
|
399
|
-
async function buildProfileText(runtime,
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
reason: authState.status === 'expired' ? 'expired_token' : 'missing_token',
|
|
404
|
-
credentialsPath: authState.credentialsPath,
|
|
405
|
-
source: authState.source,
|
|
406
|
-
expiresAt: authState.expiresAt,
|
|
407
|
-
},
|
|
408
|
-
authState,
|
|
409
|
-
});
|
|
408
|
+
async function buildProfileText(runtime, eigenfluxBin) {
|
|
409
|
+
const result = await (0, cli_executor_1.execEigenflux)(eigenfluxBin, ['profile', 'show', '-s', runtime.server.name, '-f', 'json']);
|
|
410
|
+
if (result.kind === 'auth_required') {
|
|
411
|
+
return (0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({ context: runtime.getPromptContext() });
|
|
410
412
|
}
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
return [
|
|
414
|
-
`EigenFlux profile (server=${runtime.server.name}):`,
|
|
415
|
-
'```json',
|
|
416
|
-
safeJsonStringify(payload),
|
|
417
|
-
'```',
|
|
418
|
-
].join('\n');
|
|
413
|
+
if (result.kind === 'not_installed') {
|
|
414
|
+
return `EigenFlux CLI not installed (bin=${result.bin}). Install with: ${INSTALL_COMMAND}`;
|
|
419
415
|
}
|
|
420
|
-
|
|
421
|
-
return `Failed to fetch profile for server ${runtime.server.name}: ${error
|
|
416
|
+
if (result.kind === 'error') {
|
|
417
|
+
return `Failed to fetch profile for server ${runtime.server.name}: ${result.error.message}`;
|
|
422
418
|
}
|
|
419
|
+
return [
|
|
420
|
+
`EigenFlux profile (server=${runtime.server.name}):`,
|
|
421
|
+
'```json',
|
|
422
|
+
safeJsonStringify(result.data),
|
|
423
|
+
'```',
|
|
424
|
+
].join('\n');
|
|
423
425
|
}
|
|
424
|
-
async function buildFeedText(runtime
|
|
425
|
-
const result = await runtime.
|
|
426
|
+
async function buildFeedText(runtime) {
|
|
427
|
+
const result = await runtime.feedPoller.pollOnce({
|
|
426
428
|
notifyFeed: false,
|
|
427
429
|
notifyAuthRequired: false,
|
|
428
430
|
});
|
|
@@ -435,89 +437,27 @@ async function buildFeedText(runtime, authState) {
|
|
|
435
437
|
'```',
|
|
436
438
|
].join('\n');
|
|
437
439
|
case 'auth_required':
|
|
438
|
-
return
|
|
439
|
-
authEvent: result.authEvent,
|
|
440
|
-
authState,
|
|
441
|
-
});
|
|
440
|
+
return (0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({ context: runtime.getPromptContext() });
|
|
442
441
|
case 'error':
|
|
443
442
|
return `EigenFlux feed failed for server ${runtime.server.name}: ${result.error.message}`;
|
|
444
443
|
default:
|
|
445
444
|
return `EigenFlux feed finished with an unknown result for server ${runtime.server.name}.`;
|
|
446
445
|
}
|
|
447
446
|
}
|
|
448
|
-
|
|
449
|
-
const
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
return [
|
|
456
|
-
`EigenFlux PM poll result (server=${runtime.server.name}):`,
|
|
457
|
-
'```json',
|
|
458
|
-
safeJsonStringify(result.payload),
|
|
459
|
-
'```',
|
|
460
|
-
].join('\n');
|
|
461
|
-
case 'auth_required':
|
|
462
|
-
return buildAuthRequiredMessage(runtime.getPromptContext(), {
|
|
463
|
-
authEvent: result.authEvent,
|
|
464
|
-
authState,
|
|
465
|
-
});
|
|
466
|
-
case 'error':
|
|
467
|
-
return `EigenFlux PM poll failed for server ${runtime.server.name}: ${result.error.message}`;
|
|
468
|
-
default:
|
|
469
|
-
return `EigenFlux PM poll finished with an unknown result for server ${runtime.server.name}.`;
|
|
470
|
-
}
|
|
471
|
-
}
|
|
472
|
-
async function fetchJson(url, accessToken) {
|
|
473
|
-
const response = await fetch(url, {
|
|
474
|
-
method: 'GET',
|
|
475
|
-
headers: (0, config_1.buildEigenFluxRequestHeaders)(accessToken),
|
|
476
|
-
});
|
|
477
|
-
if (response.status === 401) {
|
|
478
|
-
throw new Error('HTTP 401: unauthorized');
|
|
479
|
-
}
|
|
480
|
-
if (!response.ok) {
|
|
481
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
482
|
-
}
|
|
483
|
-
const payload = (await response.json());
|
|
484
|
-
if (payload.code !== 0) {
|
|
485
|
-
throw new Error(`API error: ${payload.msg}`);
|
|
486
|
-
}
|
|
487
|
-
return payload;
|
|
488
|
-
}
|
|
489
|
-
function buildAuthStatusText(serverConfig, authState) {
|
|
490
|
-
const lines = [`EigenFlux auth status (server=${serverConfig.name}):`];
|
|
491
|
-
lines.push(`- workdir: ${serverConfig.workdir}`);
|
|
492
|
-
lines.push(`- credentials_path: ${authState.credentialsPath}`);
|
|
493
|
-
lines.push(`- status: ${authState.status}`);
|
|
494
|
-
if (authState.source) {
|
|
495
|
-
lines.push(`- source: ${authState.source}`);
|
|
496
|
-
}
|
|
497
|
-
if (authState.expiresAt) {
|
|
498
|
-
lines.push(`- expires_at: ${authState.expiresAt}`);
|
|
499
|
-
}
|
|
500
|
-
if (authState.status === 'available') {
|
|
501
|
-
lines.push(`- token: ${maskToken(authState.accessToken)}`);
|
|
447
|
+
function buildPmStatusText(runtime) {
|
|
448
|
+
const running = runtime.streamClient.isRunning();
|
|
449
|
+
const cursor = runtime.streamClient.getLastCursor();
|
|
450
|
+
const lines = [`EigenFlux PM stream status (server=${runtime.server.name}):`];
|
|
451
|
+
lines.push(`- streaming: ${running ? 'active' : 'inactive'}`);
|
|
452
|
+
if (cursor) {
|
|
453
|
+
lines.push(`- last_cursor: ${cursor}`);
|
|
502
454
|
}
|
|
503
|
-
|
|
504
|
-
lines.push('
|
|
455
|
+
if (!running) {
|
|
456
|
+
lines.push('PM stream is not running. Check auth status or restart the service.');
|
|
505
457
|
}
|
|
506
458
|
return lines.join('\n');
|
|
507
459
|
}
|
|
508
|
-
|
|
509
|
-
return (0, agent_prompt_templates_1.buildAuthRequiredPromptTemplate)({
|
|
510
|
-
...promptContext,
|
|
511
|
-
authEvent,
|
|
512
|
-
maskedToken: authState?.status === 'available' ? maskToken(authState.accessToken) : undefined,
|
|
513
|
-
});
|
|
514
|
-
}
|
|
515
|
-
function buildFeedPayloadMessage(promptContext, payload) {
|
|
516
|
-
return (0, agent_prompt_templates_1.buildFeedPayloadPromptTemplate)(payload, promptContext);
|
|
517
|
-
}
|
|
518
|
-
function buildPmPayloadMessage(promptContext, payload) {
|
|
519
|
-
return (0, agent_prompt_templates_1.buildPmPayloadPromptTemplate)(payload, promptContext);
|
|
520
|
-
}
|
|
460
|
+
// ─── Utilities ──────────────────────────────────────────────────────────────
|
|
521
461
|
function maskToken(token) {
|
|
522
462
|
const trimmed = token.trim();
|
|
523
463
|
if (trimmed.length <= 10) {
|
|
@@ -533,8 +473,4 @@ function safeJsonStringify(value) {
|
|
|
533
473
|
return String(value);
|
|
534
474
|
}
|
|
535
475
|
}
|
|
536
|
-
function toServiceIdSegment(name) {
|
|
537
|
-
const sanitized = name.trim().toLowerCase().replace(/[^a-z0-9._-]+/gu, '-');
|
|
538
|
-
return sanitized || 'default';
|
|
539
|
-
}
|
|
540
476
|
//# sourceMappingURL=index.js.map
|