@nordbyte/nordrelay 0.3.1 → 0.4.1
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/.env.example +45 -2
- package/README.md +221 -35
- package/dist/access-control.js +3 -0
- package/dist/agent-activity.js +300 -0
- package/dist/agent-adapter.js +17 -30
- package/dist/agent-factory.js +27 -0
- package/dist/agent-feature-matrix.js +42 -0
- package/dist/agent-updates.js +294 -0
- package/dist/agent.js +123 -9
- package/dist/artifacts.js +1 -1
- package/dist/audit-log.js +1 -1
- package/dist/bot-ui.js +1 -1
- package/dist/bot.js +483 -354
- package/dist/channel-actions.js +372 -0
- package/dist/claude-code-auth.js +121 -0
- package/dist/claude-code-cli.js +19 -0
- package/dist/claude-code-launch.js +73 -0
- package/dist/claude-code-session.js +660 -0
- package/dist/claude-code-state.js +590 -0
- package/dist/codex-session.js +12 -1
- package/dist/config.js +113 -9
- package/dist/hermes-api.js +150 -0
- package/dist/hermes-auth.js +96 -0
- package/dist/hermes-cli.js +19 -0
- package/dist/hermes-launch.js +57 -0
- package/dist/hermes-session.js +477 -0
- package/dist/hermes-state.js +609 -0
- package/dist/index.js +51 -8
- package/dist/openclaw-auth.js +27 -0
- package/dist/openclaw-cli.js +19 -0
- package/dist/openclaw-gateway.js +285 -0
- package/dist/openclaw-launch.js +65 -0
- package/dist/openclaw-session.js +549 -0
- package/dist/openclaw-state.js +409 -0
- package/dist/operations.js +115 -9
- package/dist/pi-auth.js +59 -0
- package/dist/pi-launch.js +61 -0
- package/dist/pi-rpc.js +18 -0
- package/dist/pi-session.js +103 -15
- package/dist/pi-state.js +253 -0
- package/dist/relay-runtime.js +798 -72
- package/dist/session-format.js +98 -19
- package/dist/session-registry.js +40 -15
- package/dist/settings-service.js +35 -4
- package/dist/web-dashboard-assets.js +2 -0
- package/dist/web-dashboard-client.js +275 -0
- package/dist/web-dashboard-style.js +9 -0
- package/dist/web-dashboard-ui.js +18 -0
- package/dist/web-dashboard.js +296 -196
- package/package.json +8 -3
- package/plugins/nordrelay/.codex-plugin/plugin.json +7 -4
- package/plugins/nordrelay/commands/remote.md +2 -2
- package/plugins/nordrelay/scripts/nordrelay.mjs +187 -12
- package/plugins/nordrelay/skills/telegram-remote/SKILL.md +2 -2
- package/CHANGELOG.md +0 -26
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
import { CODEX_AGENT_CAPABILITIES, } from "./agent.js";
|
|
2
|
+
import { getThreadActivity, getThreadActivityLog, getThreadRolloutSnapshot, } from "./codex-state.js";
|
|
3
|
+
import { getClaudeCodeSessionActivity, getClaudeCodeSessionActivityLog, getClaudeCodeSessionDiagnostics, getClaudeCodeSessionSnapshot, } from "./claude-code-state.js";
|
|
4
|
+
import { getHermesSessionActivity, getHermesSessionActivityLog, getHermesSessionDiagnostics, getHermesSessionSnapshot, } from "./hermes-state.js";
|
|
5
|
+
import { getOpenClawSessionActivity, getOpenClawSessionActivityLog, getOpenClawSessionDiagnostics, getOpenClawSessionSnapshot, } from "./openclaw-state.js";
|
|
6
|
+
import { getPiSessionActivity, getPiSessionActivityLog, getPiSessionDiagnostics, getPiSessionSnapshot, } from "./pi-state.js";
|
|
7
|
+
export function getExternalActivityForSession(session, config) {
|
|
8
|
+
const info = session?.getInfo();
|
|
9
|
+
if (!info || !(info.capabilities ?? CODEX_AGENT_CAPABILITIES).externalActivity) {
|
|
10
|
+
return null;
|
|
11
|
+
}
|
|
12
|
+
const threadId = session?.getActiveThreadId();
|
|
13
|
+
if (!threadId) {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
if (info.agentId === "pi") {
|
|
17
|
+
return getPiSessionActivity(info.sessionPath ?? threadId, {
|
|
18
|
+
sessionDir: config.piSessionDir,
|
|
19
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (info.agentId === "hermes") {
|
|
23
|
+
return getHermesSessionActivity(threadId, {
|
|
24
|
+
hermesHome: config.hermesHome,
|
|
25
|
+
stateDbPath: config.hermesStateDbPath,
|
|
26
|
+
workspace: info.workspace,
|
|
27
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (info.agentId === "openclaw") {
|
|
31
|
+
return getOpenClawSessionActivity(threadId, {
|
|
32
|
+
cliPath: config.openClawCliPath,
|
|
33
|
+
openClawHome: config.openClawHome,
|
|
34
|
+
stateDir: config.openClawStateDir,
|
|
35
|
+
workspace: info.workspace,
|
|
36
|
+
openClawAgentId: config.openClawAgentId,
|
|
37
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
if (info.agentId === "claude-code") {
|
|
41
|
+
return getClaudeCodeSessionActivity(threadId, {
|
|
42
|
+
configDir: config.claudeCodeConfigDir,
|
|
43
|
+
workspace: info.workspace,
|
|
44
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const activity = getThreadActivity(threadId, {
|
|
48
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
49
|
+
});
|
|
50
|
+
if (!activity) {
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
return {
|
|
54
|
+
agentId: "codex",
|
|
55
|
+
agentLabel: "Codex",
|
|
56
|
+
threadId: activity.threadId,
|
|
57
|
+
sourcePath: activity.rolloutPath,
|
|
58
|
+
sourceLabel: "Codex rollout",
|
|
59
|
+
active: activity.active,
|
|
60
|
+
stale: activity.stale,
|
|
61
|
+
turnId: activity.turnId,
|
|
62
|
+
startedAt: activity.startedAt,
|
|
63
|
+
updatedAt: activity.updatedAt,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export function getExternalSnapshotForSession(session, config, options = {}) {
|
|
67
|
+
const info = session.getInfo();
|
|
68
|
+
const threadId = session.getActiveThreadId();
|
|
69
|
+
if (!(info.capabilities ?? CODEX_AGENT_CAPABILITIES).externalActivity || !threadId) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
if (info.agentId === "pi") {
|
|
73
|
+
return getPiSessionSnapshot(info.sessionPath ?? threadId, {
|
|
74
|
+
sessionDir: config.piSessionDir,
|
|
75
|
+
afterLine: options.afterLine,
|
|
76
|
+
maxEvents: options.maxEvents,
|
|
77
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
if (info.agentId === "hermes") {
|
|
81
|
+
return getHermesSessionSnapshot(threadId, {
|
|
82
|
+
hermesHome: config.hermesHome,
|
|
83
|
+
stateDbPath: config.hermesStateDbPath,
|
|
84
|
+
workspace: info.workspace,
|
|
85
|
+
afterLine: options.afterLine,
|
|
86
|
+
maxEvents: options.maxEvents,
|
|
87
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
if (info.agentId === "openclaw") {
|
|
91
|
+
return getOpenClawSessionSnapshot(threadId, {
|
|
92
|
+
cliPath: config.openClawCliPath,
|
|
93
|
+
openClawHome: config.openClawHome,
|
|
94
|
+
stateDir: config.openClawStateDir,
|
|
95
|
+
workspace: info.workspace,
|
|
96
|
+
openClawAgentId: config.openClawAgentId,
|
|
97
|
+
afterLine: options.afterLine,
|
|
98
|
+
maxEvents: options.maxEvents,
|
|
99
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
if (info.agentId === "claude-code") {
|
|
103
|
+
return getClaudeCodeSessionSnapshot(threadId, {
|
|
104
|
+
configDir: config.claudeCodeConfigDir,
|
|
105
|
+
workspace: info.workspace,
|
|
106
|
+
afterLine: options.afterLine,
|
|
107
|
+
maxEvents: options.maxEvents,
|
|
108
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
const snapshot = getThreadRolloutSnapshot(threadId, {
|
|
112
|
+
afterLine: options.afterLine,
|
|
113
|
+
maxEvents: options.maxEvents,
|
|
114
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
115
|
+
});
|
|
116
|
+
return snapshot ? codexSnapshotToAgentSnapshot(snapshot) : null;
|
|
117
|
+
}
|
|
118
|
+
export function getAgentActivityLog(session, config, limit) {
|
|
119
|
+
const info = session.getInfo();
|
|
120
|
+
const threadId = session.getActiveThreadId();
|
|
121
|
+
if (!threadId) {
|
|
122
|
+
return [];
|
|
123
|
+
}
|
|
124
|
+
if (info.agentId === "pi") {
|
|
125
|
+
return getPiSessionActivityLog(info.sessionPath ?? threadId, limit, { sessionDir: config.piSessionDir });
|
|
126
|
+
}
|
|
127
|
+
if (info.agentId === "hermes") {
|
|
128
|
+
return getHermesSessionActivityLog(threadId, limit, {
|
|
129
|
+
hermesHome: config.hermesHome,
|
|
130
|
+
stateDbPath: config.hermesStateDbPath,
|
|
131
|
+
workspace: info.workspace,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
if (info.agentId === "openclaw") {
|
|
135
|
+
return getOpenClawSessionActivityLog(threadId, limit, {
|
|
136
|
+
cliPath: config.openClawCliPath,
|
|
137
|
+
openClawHome: config.openClawHome,
|
|
138
|
+
stateDir: config.openClawStateDir,
|
|
139
|
+
workspace: info.workspace,
|
|
140
|
+
openClawAgentId: config.openClawAgentId,
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
if (info.agentId === "claude-code") {
|
|
144
|
+
return getClaudeCodeSessionActivityLog(threadId, limit, {
|
|
145
|
+
configDir: config.claudeCodeConfigDir,
|
|
146
|
+
workspace: info.workspace,
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
return getThreadActivityLog(threadId, limit).map(codexEventToAgentEvent);
|
|
150
|
+
}
|
|
151
|
+
export function getAgentDiagnostics(session, config) {
|
|
152
|
+
const info = session.getInfo();
|
|
153
|
+
if (info.agentId === "pi") {
|
|
154
|
+
const diagnostics = getPiSessionDiagnostics(info.sessionPath ?? info.threadId, {
|
|
155
|
+
sessionDir: config.piSessionDir,
|
|
156
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
157
|
+
});
|
|
158
|
+
return {
|
|
159
|
+
agentId: "pi",
|
|
160
|
+
agentLabel: "Pi",
|
|
161
|
+
lines: [
|
|
162
|
+
{ label: "Pi session dir", value: diagnostics.sessionDir },
|
|
163
|
+
{ label: "Pi session file", value: diagnostics.sessionPath ?? "-" },
|
|
164
|
+
{ label: "Pi session status", value: diagnostics.status },
|
|
165
|
+
{ label: "Pi status reason", value: diagnostics.reason },
|
|
166
|
+
{ label: "Pi JSONL lines", value: String(diagnostics.lineCount) },
|
|
167
|
+
{ label: "Pi updated", value: diagnostics.updatedAt?.toISOString() ?? "-" },
|
|
168
|
+
{ label: "Pi RPC active", value: session.isProcessing() ? "yes" : "idle" },
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
if (info.agentId === "hermes") {
|
|
173
|
+
const diagnostics = getHermesSessionDiagnostics(info.threadId, {
|
|
174
|
+
hermesHome: config.hermesHome,
|
|
175
|
+
stateDbPath: config.hermesStateDbPath,
|
|
176
|
+
workspace: info.workspace,
|
|
177
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
178
|
+
});
|
|
179
|
+
return {
|
|
180
|
+
agentId: "hermes",
|
|
181
|
+
agentLabel: "Hermes",
|
|
182
|
+
lines: [
|
|
183
|
+
{ label: "Hermes API", value: config.hermesApiBaseUrl },
|
|
184
|
+
{ label: "Hermes state DB", value: diagnostics.stateDbPath },
|
|
185
|
+
{ label: "Hermes session status", value: diagnostics.status },
|
|
186
|
+
{ label: "Hermes status reason", value: diagnostics.reason },
|
|
187
|
+
{ label: "Hermes messages", value: String(diagnostics.lineCount) },
|
|
188
|
+
{ label: "Hermes updated", value: diagnostics.updatedAt?.toISOString() ?? "-" },
|
|
189
|
+
{ label: "Hermes API run active", value: session.isProcessing() ? "yes" : "idle" },
|
|
190
|
+
],
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
if (info.agentId === "openclaw") {
|
|
194
|
+
const diagnostics = getOpenClawSessionDiagnostics(info.threadId, {
|
|
195
|
+
cliPath: config.openClawCliPath,
|
|
196
|
+
openClawHome: config.openClawHome,
|
|
197
|
+
stateDir: config.openClawStateDir,
|
|
198
|
+
workspace: info.workspace,
|
|
199
|
+
openClawAgentId: config.openClawAgentId,
|
|
200
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
201
|
+
});
|
|
202
|
+
return {
|
|
203
|
+
agentId: "openclaw",
|
|
204
|
+
agentLabel: "OpenClaw",
|
|
205
|
+
lines: [
|
|
206
|
+
{ label: "OpenClaw Gateway", value: config.openClawGatewayUrl },
|
|
207
|
+
{ label: "OpenClaw sessions", value: diagnostics.sourcePath },
|
|
208
|
+
{ label: "OpenClaw session status", value: diagnostics.status },
|
|
209
|
+
{ label: "OpenClaw status reason", value: diagnostics.reason },
|
|
210
|
+
{ label: "OpenClaw events", value: String(diagnostics.lineCount) },
|
|
211
|
+
{ label: "OpenClaw updated", value: diagnostics.updatedAt?.toISOString() ?? "-" },
|
|
212
|
+
{ label: "OpenClaw Gateway run active", value: session.isProcessing() ? "yes" : "idle" },
|
|
213
|
+
],
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
if (info.agentId === "claude-code") {
|
|
217
|
+
const diagnostics = getClaudeCodeSessionDiagnostics(info.threadId, {
|
|
218
|
+
configDir: config.claudeCodeConfigDir,
|
|
219
|
+
workspace: info.workspace,
|
|
220
|
+
staleAfterMs: config.codexExternalBusyStaleMs,
|
|
221
|
+
});
|
|
222
|
+
return {
|
|
223
|
+
agentId: "claude-code",
|
|
224
|
+
agentLabel: "Claude Code",
|
|
225
|
+
lines: [
|
|
226
|
+
{ label: "Claude projects dir", value: diagnostics.projectsDir },
|
|
227
|
+
{ label: "Claude session file", value: diagnostics.sessionPath ?? "-" },
|
|
228
|
+
{ label: "Claude session status", value: diagnostics.status },
|
|
229
|
+
{ label: "Claude status reason", value: diagnostics.reason },
|
|
230
|
+
{ label: "Claude JSONL lines", value: String(diagnostics.lineCount) },
|
|
231
|
+
{ label: "Claude updated", value: diagnostics.updatedAt?.toISOString() ?? "-" },
|
|
232
|
+
{ label: "Claude SDK run active", value: session.isProcessing() ? "yes" : "idle" },
|
|
233
|
+
],
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
const snapshot = info.threadId
|
|
237
|
+
? getThreadRolloutSnapshot(info.threadId, { staleAfterMs: config.codexExternalBusyStaleMs, maxEvents: 0 })
|
|
238
|
+
: null;
|
|
239
|
+
const status = !info.threadId ? "unavailable" : snapshot?.activity.active ? "active" : snapshot?.activity.stale ? "stale" : snapshot ? "idle" : "unavailable";
|
|
240
|
+
const reason = !info.threadId
|
|
241
|
+
? "no active thread"
|
|
242
|
+
: snapshot?.activity.active
|
|
243
|
+
? "open task without terminal event"
|
|
244
|
+
: snapshot?.activity.stale
|
|
245
|
+
? "open task exceeded stale timeout"
|
|
246
|
+
: snapshot
|
|
247
|
+
? "no open task"
|
|
248
|
+
: "rollout unavailable";
|
|
249
|
+
return {
|
|
250
|
+
agentId: "codex",
|
|
251
|
+
agentLabel: "Codex",
|
|
252
|
+
lines: [
|
|
253
|
+
{ label: "Rollout path", value: snapshot?.rolloutPath ?? "-" },
|
|
254
|
+
{ label: "Rollout status", value: status },
|
|
255
|
+
{ label: "Rollout reason", value: reason },
|
|
256
|
+
{ label: "Rollout turn", value: snapshot?.activity.turnId ?? "-" },
|
|
257
|
+
{ label: "Rollout lines", value: String(snapshot?.lineCount ?? 0) },
|
|
258
|
+
{ label: "Rollout updated", value: snapshot?.activity.updatedAt?.toISOString() ?? "-" },
|
|
259
|
+
],
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function codexSnapshotToAgentSnapshot(snapshot) {
|
|
263
|
+
return {
|
|
264
|
+
agentId: "codex",
|
|
265
|
+
agentLabel: "Codex",
|
|
266
|
+
threadId: snapshot.threadId,
|
|
267
|
+
sourcePath: snapshot.rolloutPath,
|
|
268
|
+
sourceLabel: "Codex rollout",
|
|
269
|
+
lineCount: snapshot.lineCount,
|
|
270
|
+
activity: {
|
|
271
|
+
agentId: "codex",
|
|
272
|
+
agentLabel: "Codex",
|
|
273
|
+
threadId: snapshot.threadId,
|
|
274
|
+
sourcePath: snapshot.rolloutPath,
|
|
275
|
+
sourceLabel: "Codex rollout",
|
|
276
|
+
active: snapshot.activity.active,
|
|
277
|
+
stale: snapshot.activity.stale,
|
|
278
|
+
turnId: snapshot.activity.turnId,
|
|
279
|
+
startedAt: snapshot.activity.startedAt,
|
|
280
|
+
updatedAt: snapshot.activity.updatedAt,
|
|
281
|
+
},
|
|
282
|
+
events: snapshot.events.map(codexEventToAgentEvent),
|
|
283
|
+
latestAgentMessage: snapshot.latestAgentMessage,
|
|
284
|
+
latestUserMessage: snapshot.latestUserMessage,
|
|
285
|
+
latestToolName: snapshot.latestToolName,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
function codexEventToAgentEvent(event) {
|
|
289
|
+
return {
|
|
290
|
+
lineNumber: event.lineNumber,
|
|
291
|
+
kind: event.kind,
|
|
292
|
+
timestamp: event.timestamp,
|
|
293
|
+
type: event.type,
|
|
294
|
+
turnId: event.turnId,
|
|
295
|
+
status: event.status,
|
|
296
|
+
text: event.text,
|
|
297
|
+
toolName: event.toolName,
|
|
298
|
+
phase: event.phase,
|
|
299
|
+
};
|
|
300
|
+
}
|
package/dist/agent-adapter.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CODEX_AGENT_CAPABILITIES, PI_AGENT_CAPABILITIES, } from "./agent.js";
|
|
1
|
+
import { CLAUDE_CODE_AGENT_CAPABILITIES, CODEX_AGENT_CAPABILITIES, HERMES_AGENT_CAPABILITIES, OPENCLAW_AGENT_CAPABILITIES, PI_AGENT_CAPABILITIES, } from "./agent.js";
|
|
2
2
|
export const BUILTIN_AGENT_ADAPTERS = [
|
|
3
3
|
{
|
|
4
4
|
id: "codex",
|
|
@@ -15,23 +15,28 @@ export const BUILTIN_AGENT_ADAPTERS = [
|
|
|
15
15
|
envFlag: "NORDRELAY_PI_ENABLED",
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
id: "
|
|
19
|
-
label: "
|
|
20
|
-
status: "
|
|
21
|
-
capabilities:
|
|
22
|
-
|
|
18
|
+
id: "hermes",
|
|
19
|
+
label: "Hermes",
|
|
20
|
+
status: "available",
|
|
21
|
+
capabilities: HERMES_AGENT_CAPABILITIES,
|
|
22
|
+
envFlag: "NORDRELAY_HERMES_ENABLED",
|
|
23
|
+
notes: "Uses the Hermes API Server for streaming runs, stop, session continuity, and tool lifecycle events.",
|
|
23
24
|
},
|
|
24
25
|
{
|
|
25
26
|
id: "openclaw",
|
|
26
27
|
label: "OpenClaw",
|
|
27
|
-
status: "
|
|
28
|
-
capabilities:
|
|
28
|
+
status: "available",
|
|
29
|
+
capabilities: OPENCLAW_AGENT_CAPABILITIES,
|
|
30
|
+
envFlag: "NORDRELAY_OPENCLAW_ENABLED",
|
|
31
|
+
notes: "Uses the OpenClaw Gateway WebSocket RPC surface for streamed agent runs, session continuity, and tool lifecycle events.",
|
|
29
32
|
},
|
|
30
33
|
{
|
|
31
|
-
id: "
|
|
32
|
-
label: "
|
|
33
|
-
status: "
|
|
34
|
-
capabilities:
|
|
34
|
+
id: "claude-code",
|
|
35
|
+
label: "Claude Code",
|
|
36
|
+
status: "available",
|
|
37
|
+
capabilities: CLAUDE_CODE_AGENT_CAPABILITIES,
|
|
38
|
+
envFlag: "NORDRELAY_CLAUDE_CODE_ENABLED",
|
|
39
|
+
notes: "Uses the Claude Agent SDK with host Claude Code sessions, streaming, tool lifecycle events, session continuity, and handback.",
|
|
35
40
|
},
|
|
36
41
|
];
|
|
37
42
|
export function listAgentAdapterDescriptors() {
|
|
@@ -40,21 +45,3 @@ export function listAgentAdapterDescriptors() {
|
|
|
40
45
|
capabilities: { ...descriptor.capabilities },
|
|
41
46
|
}));
|
|
42
47
|
}
|
|
43
|
-
function plannedCapabilities() {
|
|
44
|
-
return {
|
|
45
|
-
launchProfiles: false,
|
|
46
|
-
fastMode: false,
|
|
47
|
-
externalActivity: false,
|
|
48
|
-
cliMirror: false,
|
|
49
|
-
activityLog: false,
|
|
50
|
-
auth: false,
|
|
51
|
-
login: false,
|
|
52
|
-
logout: false,
|
|
53
|
-
usageLimits: false,
|
|
54
|
-
workspaces: true,
|
|
55
|
-
attachments: true,
|
|
56
|
-
modelSelection: true,
|
|
57
|
-
reasoningSelection: true,
|
|
58
|
-
handback: true,
|
|
59
|
-
};
|
|
60
|
-
}
|
package/dist/agent-factory.js
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { CodexSessionService } from "./codex-session.js";
|
|
2
|
+
import { ClaudeCodeSessionService } from "./claude-code-session.js";
|
|
3
|
+
import { HermesSessionService } from "./hermes-session.js";
|
|
4
|
+
import { OpenClawSessionService } from "./openclaw-session.js";
|
|
2
5
|
import { PiSessionService } from "./pi-session.js";
|
|
3
6
|
export async function createAgentSessionService(config, agentId, options) {
|
|
4
7
|
if (agentId === "pi") {
|
|
@@ -7,6 +10,24 @@ export async function createAgentSessionService(config, agentId, options) {
|
|
|
7
10
|
}
|
|
8
11
|
return PiSessionService.create(config, options);
|
|
9
12
|
}
|
|
13
|
+
if (agentId === "hermes") {
|
|
14
|
+
if (config.hermesEnabled !== true) {
|
|
15
|
+
throw new Error("Hermes support is disabled. Set NORDRELAY_HERMES_ENABLED=true.");
|
|
16
|
+
}
|
|
17
|
+
return HermesSessionService.create(config, options);
|
|
18
|
+
}
|
|
19
|
+
if (agentId === "openclaw") {
|
|
20
|
+
if (config.openClawEnabled !== true) {
|
|
21
|
+
throw new Error("OpenClaw support is disabled. Set NORDRELAY_OPENCLAW_ENABLED=true.");
|
|
22
|
+
}
|
|
23
|
+
return OpenClawSessionService.create(config, options);
|
|
24
|
+
}
|
|
25
|
+
if (agentId === "claude-code") {
|
|
26
|
+
if (config.claudeCodeEnabled !== true) {
|
|
27
|
+
throw new Error("Claude Code support is disabled. Set NORDRELAY_CLAUDE_CODE_ENABLED=true.");
|
|
28
|
+
}
|
|
29
|
+
return ClaudeCodeSessionService.create(config, options);
|
|
30
|
+
}
|
|
10
31
|
if (config.codexEnabled === false) {
|
|
11
32
|
throw new Error("Codex support is disabled. Set NORDRELAY_CODEX_ENABLED=true.");
|
|
12
33
|
}
|
|
@@ -18,5 +39,11 @@ export function enabledAgents(config) {
|
|
|
18
39
|
agents.push("codex");
|
|
19
40
|
if (config.piEnabled)
|
|
20
41
|
agents.push("pi");
|
|
42
|
+
if (config.hermesEnabled)
|
|
43
|
+
agents.push("hermes");
|
|
44
|
+
if (config.openClawEnabled)
|
|
45
|
+
agents.push("openclaw");
|
|
46
|
+
if (config.claudeCodeEnabled)
|
|
47
|
+
agents.push("claude-code");
|
|
21
48
|
return agents;
|
|
22
49
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { escapeHTML } from "./format.js";
|
|
2
|
+
export const AGENT_FEATURES = [
|
|
3
|
+
{ key: "modelSelection", label: "Model", description: "Pick the model used for new turns or sessions." },
|
|
4
|
+
{ key: "reasoningSelection", label: "Reasoning", description: "Pick thinking/reasoning effort where the agent exposes it." },
|
|
5
|
+
{ key: "launchProfiles", label: "Launch profiles", description: "Switch sandbox/approval launch behavior for new sessions." },
|
|
6
|
+
{ key: "fastMode", label: "Fast mode", description: "Toggle the agent-specific low-latency mode." },
|
|
7
|
+
{ key: "workspaces", label: "Workspaces", description: "List and switch allowed workspaces." },
|
|
8
|
+
{ key: "attachments", label: "Files/images", description: "Send files, photos, staged attachments, and voice transcripts." },
|
|
9
|
+
{ key: "externalActivity", label: "External busy", description: "Detect active CLI turns started outside NordRelay." },
|
|
10
|
+
{ key: "cliMirror", label: "CLI mirror", description: "Mirror CLI-started turns back to Telegram/WebUI." },
|
|
11
|
+
{ key: "activityLog", label: "Activity", description: "Read activity timelines for sessions and turns." },
|
|
12
|
+
{ key: "usageStats", label: "Usage stats", description: "Show token/context usage reported by the agent." },
|
|
13
|
+
{ key: "subscriptionLimits", label: "Limits", description: "Show subscription/quota limits when the agent exposes them." },
|
|
14
|
+
{ key: "auth", label: "Auth status", description: "Check whether the agent is authenticated." },
|
|
15
|
+
{ key: "login", label: "Login", description: "Start an agent login flow from NordRelay." },
|
|
16
|
+
{ key: "logout", label: "Logout", description: "Sign out of the agent from NordRelay." },
|
|
17
|
+
{ key: "handback", label: "Handback", description: "Return a remote session to the native CLI." },
|
|
18
|
+
];
|
|
19
|
+
export function agentFeatureStates(capabilities) {
|
|
20
|
+
return AGENT_FEATURES.map((feature) => ({
|
|
21
|
+
...feature,
|
|
22
|
+
supported: Boolean(capabilities[feature.key]),
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
export function formatAgentFeatureSummaryPlain(capabilities) {
|
|
26
|
+
const states = agentFeatureStates(capabilities);
|
|
27
|
+
const supported = states.filter((feature) => feature.supported).map((feature) => feature.label);
|
|
28
|
+
const unsupported = states.filter((feature) => !feature.supported).map((feature) => feature.label);
|
|
29
|
+
return [
|
|
30
|
+
`Supported: ${supported.join(", ") || "-"}`,
|
|
31
|
+
`Not supported: ${unsupported.join(", ") || "-"}`,
|
|
32
|
+
];
|
|
33
|
+
}
|
|
34
|
+
export function formatAgentFeatureSummaryHTML(capabilities) {
|
|
35
|
+
const states = agentFeatureStates(capabilities);
|
|
36
|
+
const supported = states.filter((feature) => feature.supported).map((feature) => feature.label);
|
|
37
|
+
const unsupported = states.filter((feature) => !feature.supported).map((feature) => feature.label);
|
|
38
|
+
return [
|
|
39
|
+
`<b>Supported:</b> ${escapeHTML(supported.join(", ") || "-")}`,
|
|
40
|
+
`<b>Not supported:</b> ${escapeHTML(unsupported.join(", ") || "-")}`,
|
|
41
|
+
];
|
|
42
|
+
}
|