@alfe.ai/openclaw-chat 0.4.0 → 0.5.0
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/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +4 -0
- package/dist/plugin.d.cts +30 -1
- package/dist/plugin.d.ts +30 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin2.cjs +202 -25
- package/dist/plugin2.d.cts +2 -2
- package/dist/plugin2.d.ts +2 -2
- package/dist/plugin2.js +179 -26
- package/package.json +2 -2
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as AlfeResolvedAccount, g as AlfePluginConfig, h as AlfeChannelConfig, m as createAlfeChannelPlugin, u as plugin } from "./plugin.cjs";
|
|
2
2
|
|
|
3
3
|
//#region src/session-store.d.ts
|
|
4
4
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as AlfeResolvedAccount, g as AlfePluginConfig, h as AlfeChannelConfig, m as createAlfeChannelPlugin, u as plugin } from "./plugin.js";
|
|
2
2
|
|
|
3
3
|
//#region src/session-store.d.ts
|
|
4
4
|
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { c as plugin, f as createAlfeChannelPlugin } from "./plugin2.js";
|
|
2
2
|
export { createAlfeChannelPlugin, plugin as default };
|
package/dist/plugin.cjs
CHANGED
|
@@ -3,10 +3,14 @@ Object.defineProperties(exports, {
|
|
|
3
3
|
[Symbol.toStringTag]: { value: "Module" }
|
|
4
4
|
});
|
|
5
5
|
const require_plugin = require("./plugin2.cjs");
|
|
6
|
+
exports.__agentTurnQueueForTest = require_plugin.__agentTurnQueueForTest;
|
|
7
|
+
exports.__resetAgentTurnQueueForTest = require_plugin.__resetAgentTurnQueueForTest;
|
|
8
|
+
exports.__setActiveRunForTest = require_plugin.__setActiveRunForTest;
|
|
6
9
|
exports.admitAgentEvent = require_plugin.admitAgentEvent;
|
|
7
10
|
exports.buildA2ACompletePayload = require_plugin.buildA2ACompletePayload;
|
|
8
11
|
exports.buildToolActivity = require_plugin.buildToolActivity;
|
|
9
12
|
exports.default = require_plugin.plugin;
|
|
10
13
|
exports.joinAssistantText = require_plugin.joinAssistantText;
|
|
14
|
+
exports.resolveAbortTargetKeys = require_plugin.resolveAbortTargetKeys;
|
|
11
15
|
exports.rewriteAssistantText = require_plugin.rewriteAssistantText;
|
|
12
16
|
exports.stripLeakedToolSummary = require_plugin.stripLeakedToolSummary;
|
package/dist/plugin.d.cts
CHANGED
|
@@ -402,6 +402,35 @@ interface PluginApi {
|
|
|
402
402
|
priority?: number;
|
|
403
403
|
}): void;
|
|
404
404
|
}
|
|
405
|
+
declare function enqueueAgentTurn(task: () => Promise<void>, opts?: {
|
|
406
|
+
coalesceKey?: string;
|
|
407
|
+
onSuperseded?: () => void;
|
|
408
|
+
}): Promise<void>;
|
|
409
|
+
/**
|
|
410
|
+
* Test-only: reset the agent-turn backlog between unit tests. Not used at
|
|
411
|
+
* runtime (the backlog lives for the process lifetime of one daemon).
|
|
412
|
+
*/
|
|
413
|
+
declare function __resetAgentTurnQueueForTest(): void;
|
|
414
|
+
/** Test-only accessor for the coalescing queue (see __tests__/queue.test.ts). */
|
|
415
|
+
declare const __agentTurnQueueForTest: {
|
|
416
|
+
enqueue: typeof enqueueAgentTurn;
|
|
417
|
+
backlogLength: () => number;
|
|
418
|
+
};
|
|
419
|
+
interface ActiveRunRef {
|
|
420
|
+
requestSessionKey: string;
|
|
421
|
+
routeSessionKey: string | null;
|
|
422
|
+
}
|
|
423
|
+
/** Test-only: set/clear the active-run ref for handleChatAbort unit tests. */
|
|
424
|
+
declare function __setActiveRunForTest(ref: ActiveRunRef | null): void;
|
|
425
|
+
/**
|
|
426
|
+
* Ordered session keys to try when aborting for `abortSessionKey`. Pure, so it
|
|
427
|
+
* unit-tests without the OpenClaw SDK. The resolved route key (what the run
|
|
428
|
+
* registered under) is preferred; the raw request key is a best-effort
|
|
429
|
+
* fallback. An abort with NO sessionKey targets the single active run. A
|
|
430
|
+
* sessionKey that does NOT match the running turn yields no candidates — we
|
|
431
|
+
* never abort another session's run on a shared daemon.
|
|
432
|
+
*/
|
|
433
|
+
declare function resolveAbortTargetKeys(active: ActiveRunRef | null, abortSessionKey: string | undefined): string[];
|
|
405
434
|
declare const plugin: {
|
|
406
435
|
id: string;
|
|
407
436
|
name: string;
|
|
@@ -411,4 +440,4 @@ declare const plugin: {
|
|
|
411
440
|
deactivate(api: PluginApi): Promise<void>;
|
|
412
441
|
};
|
|
413
442
|
//#endregion
|
|
414
|
-
export {
|
|
443
|
+
export { AlfeResolvedAccount as _, __setActiveRunForTest as a, buildToolActivity as c, resolveAbortTargetKeys as d, rewriteAssistantText as f, AlfePluginConfig as g, AlfeChannelConfig as h, __resetAgentTurnQueueForTest as i, joinAssistantText as l, createAlfeChannelPlugin as m, RunEventGate as n, admitAgentEvent as o, stripLeakedToolSummary as p, __agentTurnQueueForTest as r, buildA2ACompletePayload as s, ActiveRunRef as t, plugin as u };
|
package/dist/plugin.d.ts
CHANGED
|
@@ -402,6 +402,35 @@ interface PluginApi {
|
|
|
402
402
|
priority?: number;
|
|
403
403
|
}): void;
|
|
404
404
|
}
|
|
405
|
+
declare function enqueueAgentTurn(task: () => Promise<void>, opts?: {
|
|
406
|
+
coalesceKey?: string;
|
|
407
|
+
onSuperseded?: () => void;
|
|
408
|
+
}): Promise<void>;
|
|
409
|
+
/**
|
|
410
|
+
* Test-only: reset the agent-turn backlog between unit tests. Not used at
|
|
411
|
+
* runtime (the backlog lives for the process lifetime of one daemon).
|
|
412
|
+
*/
|
|
413
|
+
declare function __resetAgentTurnQueueForTest(): void;
|
|
414
|
+
/** Test-only accessor for the coalescing queue (see __tests__/queue.test.ts). */
|
|
415
|
+
declare const __agentTurnQueueForTest: {
|
|
416
|
+
enqueue: typeof enqueueAgentTurn;
|
|
417
|
+
backlogLength: () => number;
|
|
418
|
+
};
|
|
419
|
+
interface ActiveRunRef {
|
|
420
|
+
requestSessionKey: string;
|
|
421
|
+
routeSessionKey: string | null;
|
|
422
|
+
}
|
|
423
|
+
/** Test-only: set/clear the active-run ref for handleChatAbort unit tests. */
|
|
424
|
+
declare function __setActiveRunForTest(ref: ActiveRunRef | null): void;
|
|
425
|
+
/**
|
|
426
|
+
* Ordered session keys to try when aborting for `abortSessionKey`. Pure, so it
|
|
427
|
+
* unit-tests without the OpenClaw SDK. The resolved route key (what the run
|
|
428
|
+
* registered under) is preferred; the raw request key is a best-effort
|
|
429
|
+
* fallback. An abort with NO sessionKey targets the single active run. A
|
|
430
|
+
* sessionKey that does NOT match the running turn yields no candidates — we
|
|
431
|
+
* never abort another session's run on a shared daemon.
|
|
432
|
+
*/
|
|
433
|
+
declare function resolveAbortTargetKeys(active: ActiveRunRef | null, abortSessionKey: string | undefined): string[];
|
|
405
434
|
declare const plugin: {
|
|
406
435
|
id: string;
|
|
407
436
|
name: string;
|
|
@@ -411,4 +440,4 @@ declare const plugin: {
|
|
|
411
440
|
deactivate(api: PluginApi): Promise<void>;
|
|
412
441
|
};
|
|
413
442
|
//#endregion
|
|
414
|
-
export {
|
|
443
|
+
export { AlfeResolvedAccount as _, __setActiveRunForTest as a, buildToolActivity as c, resolveAbortTargetKeys as d, rewriteAssistantText as f, AlfePluginConfig as g, AlfeChannelConfig as h, __resetAgentTurnQueueForTest as i, joinAssistantText as l, createAlfeChannelPlugin as m, RunEventGate as n, admitAgentEvent as o, stripLeakedToolSummary as p, __agentTurnQueueForTest as r, buildA2ACompletePayload as s, ActiveRunRef as t, plugin as u };
|
package/dist/plugin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as plugin, i as
|
|
2
|
-
export { admitAgentEvent, buildA2ACompletePayload, buildToolActivity, plugin as default, joinAssistantText, rewriteAssistantText, stripLeakedToolSummary };
|
|
1
|
+
import { a as buildA2ACompletePayload, c as plugin, d as stripLeakedToolSummary, i as admitAgentEvent, l as resolveAbortTargetKeys, n as __resetAgentTurnQueueForTest, o as buildToolActivity, r as __setActiveRunForTest, s as joinAssistantText, t as __agentTurnQueueForTest, u as rewriteAssistantText } from "./plugin2.js";
|
|
2
|
+
export { __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildToolActivity, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
package/dist/plugin2.cjs
CHANGED
|
@@ -1186,6 +1186,37 @@ function buildA2ACompletePayload(params) {
|
|
|
1186
1186
|
};
|
|
1187
1187
|
}
|
|
1188
1188
|
let dispatchInbound = null;
|
|
1189
|
+
let abortEmbeddedAgentRun = null;
|
|
1190
|
+
let resolveActiveRunSessionId = null;
|
|
1191
|
+
let resolveRouteEnvelope = null;
|
|
1192
|
+
/**
|
|
1193
|
+
* Load the OpenClaw SDK surfaces from a single resolver anchor. Returns true
|
|
1194
|
+
* once the critical `dispatchInboundDirectDmWithRuntime` is resolved. The abort
|
|
1195
|
+
* primitives + route resolver are best-effort — an older openclaw without them
|
|
1196
|
+
* degrades `chat.abort` to a logged no-op (Stop still seals the UI) rather than
|
|
1197
|
+
* a hard failure.
|
|
1198
|
+
*/
|
|
1199
|
+
function loadOpenClawSdk(req, log, anchor) {
|
|
1200
|
+
let resolvedDispatch = false;
|
|
1201
|
+
try {
|
|
1202
|
+
const channelInbound = req("openclaw/plugin-sdk/channel-inbound");
|
|
1203
|
+
if (channelInbound.dispatchInboundDirectDmWithRuntime) {
|
|
1204
|
+
dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
|
|
1205
|
+
resolvedDispatch = true;
|
|
1206
|
+
}
|
|
1207
|
+
} catch {}
|
|
1208
|
+
try {
|
|
1209
|
+
const harness = req("openclaw/plugin-sdk/agent-harness");
|
|
1210
|
+
if (harness.abortEmbeddedAgentRun) abortEmbeddedAgentRun = harness.abortEmbeddedAgentRun;
|
|
1211
|
+
if (harness.resolveActiveEmbeddedRunSessionId) resolveActiveRunSessionId = harness.resolveActiveEmbeddedRunSessionId;
|
|
1212
|
+
} catch {}
|
|
1213
|
+
try {
|
|
1214
|
+
const envelope = req("openclaw/plugin-sdk/inbound-envelope");
|
|
1215
|
+
if (envelope.resolveInboundRouteEnvelopeBuilderWithRuntime) resolveRouteEnvelope = envelope.resolveInboundRouteEnvelopeBuilderWithRuntime;
|
|
1216
|
+
} catch {}
|
|
1217
|
+
if (resolvedDispatch) log.info(`Resolved OpenClaw SDK from ${anchor} (hard-abort=${abortEmbeddedAgentRun && resolveActiveRunSessionId ? "available" : "unavailable"})`);
|
|
1218
|
+
return resolvedDispatch;
|
|
1219
|
+
}
|
|
1189
1220
|
/**
|
|
1190
1221
|
* Resolve OpenClaw SDK functions from the running process.
|
|
1191
1222
|
*
|
|
@@ -1197,21 +1228,11 @@ let dispatchInbound = null;
|
|
|
1197
1228
|
function resolveOpenClawSdk(log) {
|
|
1198
1229
|
const anchors = [require$1.main?.filename, process.argv[1]].filter(Boolean);
|
|
1199
1230
|
for (const anchor of anchors) try {
|
|
1200
|
-
|
|
1201
|
-
if (channelInbound.dispatchInboundDirectDmWithRuntime) {
|
|
1202
|
-
dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
|
|
1203
|
-
log.info(`Resolved OpenClaw SDK from ${anchor}`);
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1231
|
+
if (loadOpenClawSdk((0, node_module.createRequire)(anchor), log, anchor)) return;
|
|
1206
1232
|
} catch {}
|
|
1207
1233
|
try {
|
|
1208
1234
|
const derivedPath = (0, node_path.join)((0, node_path.resolve)((0, node_path.dirname)(process.execPath), ".."), "lib", "node_modules", "openclaw", "package.json");
|
|
1209
|
-
|
|
1210
|
-
if (channelInbound.dispatchInboundDirectDmWithRuntime) {
|
|
1211
|
-
dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
|
|
1212
|
-
log.info(`Resolved OpenClaw SDK from ${derivedPath}`);
|
|
1213
|
-
return;
|
|
1214
|
-
}
|
|
1235
|
+
if (loadOpenClawSdk((0, node_module.createRequire)(derivedPath), log, derivedPath)) return;
|
|
1215
1236
|
} catch {}
|
|
1216
1237
|
log.warn("OpenClaw SDK not resolvable — chat dispatch will not work");
|
|
1217
1238
|
}
|
|
@@ -1288,11 +1309,111 @@ async function downloadAttachments(attachments, log) {
|
|
|
1288
1309
|
}
|
|
1289
1310
|
return results;
|
|
1290
1311
|
}
|
|
1291
|
-
let
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1312
|
+
let agentTurnBacklog = [];
|
|
1313
|
+
let agentTurnDraining = false;
|
|
1314
|
+
function enqueueAgentTurn(task, opts) {
|
|
1315
|
+
return new Promise((resolve, reject) => {
|
|
1316
|
+
const entry = {
|
|
1317
|
+
run: task,
|
|
1318
|
+
coalesceKey: opts?.coalesceKey,
|
|
1319
|
+
onSuperseded: opts?.onSuperseded ?? (() => void 0),
|
|
1320
|
+
resolve,
|
|
1321
|
+
reject
|
|
1322
|
+
};
|
|
1323
|
+
if (entry.coalesceKey) {
|
|
1324
|
+
const survivors = [];
|
|
1325
|
+
for (const queued of agentTurnBacklog) if (queued.coalesceKey === entry.coalesceKey) {
|
|
1326
|
+
try {
|
|
1327
|
+
queued.onSuperseded();
|
|
1328
|
+
} catch {}
|
|
1329
|
+
queued.resolve();
|
|
1330
|
+
} else survivors.push(queued);
|
|
1331
|
+
agentTurnBacklog = survivors;
|
|
1332
|
+
}
|
|
1333
|
+
agentTurnBacklog.push(entry);
|
|
1334
|
+
drainAgentTurns();
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
async function drainAgentTurns() {
|
|
1338
|
+
if (agentTurnDraining) return;
|
|
1339
|
+
agentTurnDraining = true;
|
|
1340
|
+
try {
|
|
1341
|
+
while (agentTurnBacklog.length > 0) {
|
|
1342
|
+
const entry = agentTurnBacklog.shift();
|
|
1343
|
+
if (!entry) break;
|
|
1344
|
+
try {
|
|
1345
|
+
await entry.run();
|
|
1346
|
+
entry.resolve();
|
|
1347
|
+
} catch (err) {
|
|
1348
|
+
entry.reject(err);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
} finally {
|
|
1352
|
+
agentTurnDraining = false;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Test-only: reset the agent-turn backlog between unit tests. Not used at
|
|
1357
|
+
* runtime (the backlog lives for the process lifetime of one daemon).
|
|
1358
|
+
*/
|
|
1359
|
+
function __resetAgentTurnQueueForTest() {
|
|
1360
|
+
agentTurnBacklog = [];
|
|
1361
|
+
agentTurnDraining = false;
|
|
1362
|
+
}
|
|
1363
|
+
/** Test-only accessor for the coalescing queue (see __tests__/queue.test.ts). */
|
|
1364
|
+
const __agentTurnQueueForTest = {
|
|
1365
|
+
enqueue: enqueueAgentTurn,
|
|
1366
|
+
backlogLength: () => agentTurnBacklog.length
|
|
1367
|
+
};
|
|
1368
|
+
let activeRun = null;
|
|
1369
|
+
/** Test-only: set/clear the active-run ref for handleChatAbort unit tests. */
|
|
1370
|
+
function __setActiveRunForTest(ref) {
|
|
1371
|
+
activeRun = ref;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Ordered session keys to try when aborting for `abortSessionKey`. Pure, so it
|
|
1375
|
+
* unit-tests without the OpenClaw SDK. The resolved route key (what the run
|
|
1376
|
+
* registered under) is preferred; the raw request key is a best-effort
|
|
1377
|
+
* fallback. An abort with NO sessionKey targets the single active run. A
|
|
1378
|
+
* sessionKey that does NOT match the running turn yields no candidates — we
|
|
1379
|
+
* never abort another session's run on a shared daemon.
|
|
1380
|
+
*/
|
|
1381
|
+
function resolveAbortTargetKeys(active, abortSessionKey) {
|
|
1382
|
+
const keys = [];
|
|
1383
|
+
if (active && (!abortSessionKey || active.requestSessionKey === abortSessionKey)) {
|
|
1384
|
+
if (active.routeSessionKey) keys.push(active.routeSessionKey);
|
|
1385
|
+
if (!keys.includes(active.requestSessionKey)) keys.push(active.requestSessionKey);
|
|
1386
|
+
} else if (abortSessionKey) keys.push(abortSessionKey);
|
|
1387
|
+
return keys;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* `chat.abort` handler — genuinely cancels the RUNNING turn on the daemon.
|
|
1391
|
+
*
|
|
1392
|
+
* Invoked OUT-OF-BAND (never through the serialised agent-turn queue) so it
|
|
1393
|
+
* executes immediately while a turn is mid-flight. Resolves the live run's
|
|
1394
|
+
* sessionId from the target session key and fires the run handle's
|
|
1395
|
+
* AbortController via `abortEmbeddedAgentRun`. The in-flight dispatch then
|
|
1396
|
+
* settles (AbortError), so `handleAgentRequest` sends its RPC response and the
|
|
1397
|
+
* chat service seals the UI. When the abort primitives are unavailable (older
|
|
1398
|
+
* openclaw), this degrades to a logged no-op: the UI is still sealed by the
|
|
1399
|
+
* chat service's optimistic idle broadcast, but the turn completes server-side.
|
|
1400
|
+
*/
|
|
1401
|
+
function handleChatAbort(request, log) {
|
|
1402
|
+
const { sessionKey } = request.params;
|
|
1403
|
+
const targetKeys = resolveAbortTargetKeys(activeRun, sessionKey);
|
|
1404
|
+
let aborted = false;
|
|
1405
|
+
if (abortEmbeddedAgentRun && resolveActiveRunSessionId) {
|
|
1406
|
+
for (const key of targetKeys) {
|
|
1407
|
+
const sessionId = resolveActiveRunSessionId(key);
|
|
1408
|
+
if (sessionId && abortEmbeddedAgentRun(sessionId)) {
|
|
1409
|
+
aborted = true;
|
|
1410
|
+
log.info(`chat.abort: hard-aborted running turn (sessionId=${sessionId}, key=${key})`);
|
|
1411
|
+
break;
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (!aborted) log.info(`chat.abort: no active run to abort (candidates=${String(targetKeys.length)})`);
|
|
1415
|
+
} else log.warn("chat.abort: OpenClaw abort primitives unavailable — cannot hard-abort the running turn");
|
|
1416
|
+
chatClient?.sendResponse(request.id, true, { aborted });
|
|
1296
1417
|
}
|
|
1297
1418
|
async function handleAgentRequest(request, log) {
|
|
1298
1419
|
const runtime = pluginRuntime;
|
|
@@ -1473,19 +1594,37 @@ async function handleAgentRequest(request, log) {
|
|
|
1473
1594
|
const conversationLabel = conversationType === "group" ? shortConvId ? `[${channelLabel}] Group (${shortConvId})` : `[${channelLabel}] Group` : shortConvId ? `[${channelLabel}] ${userLabel} (${shortConvId})` : `[${channelLabel}] ${userLabel}`;
|
|
1474
1595
|
let a2aResponseBuffer = "";
|
|
1475
1596
|
if (isA2A) resetA2AEndSignal();
|
|
1597
|
+
const peer = conversationType === "group" ? {
|
|
1598
|
+
kind: "group",
|
|
1599
|
+
id: conversationId ?? senderId
|
|
1600
|
+
} : {
|
|
1601
|
+
kind: "direct",
|
|
1602
|
+
id: conversationId ? `${senderId}:conv:${conversationId}` : senderId
|
|
1603
|
+
};
|
|
1604
|
+
let routeSessionKey = null;
|
|
1605
|
+
if (resolveRouteEnvelope) try {
|
|
1606
|
+
routeSessionKey = resolveRouteEnvelope({
|
|
1607
|
+
cfg,
|
|
1608
|
+
channel: "alfe",
|
|
1609
|
+
accountId: "default",
|
|
1610
|
+
peer,
|
|
1611
|
+
runtime: runtime.channel,
|
|
1612
|
+
sessionStore: cfg.session?.store
|
|
1613
|
+
}).route.sessionKey;
|
|
1614
|
+
} catch (err) {
|
|
1615
|
+
log.debug(`Route precompute failed (abort will use raw key): ${err instanceof Error ? err.message : String(err)}`);
|
|
1616
|
+
}
|
|
1617
|
+
activeRun = {
|
|
1618
|
+
requestSessionKey: legacySessionKey,
|
|
1619
|
+
routeSessionKey
|
|
1620
|
+
};
|
|
1476
1621
|
runGate.sessionKey = (await dispatchInbound({
|
|
1477
1622
|
cfg,
|
|
1478
1623
|
runtime: { channel: runtime.channel },
|
|
1479
1624
|
channel: "alfe",
|
|
1480
1625
|
channelLabel,
|
|
1481
1626
|
accountId: "default",
|
|
1482
|
-
peer
|
|
1483
|
-
kind: "group",
|
|
1484
|
-
id: conversationId ?? senderId
|
|
1485
|
-
} : {
|
|
1486
|
-
kind: "direct",
|
|
1487
|
-
id: conversationId ? `${senderId}:conv:${conversationId}` : senderId
|
|
1488
|
-
},
|
|
1627
|
+
peer,
|
|
1489
1628
|
senderId,
|
|
1490
1629
|
senderAddress: senderId,
|
|
1491
1630
|
recipientAddress: "agent",
|
|
@@ -1554,6 +1693,7 @@ async function handleAgentRequest(request, log) {
|
|
|
1554
1693
|
log.error(`Agent dispatch failed: ${errMsg}`);
|
|
1555
1694
|
chatClient?.sendResponse(request.id, false, { message: errMsg });
|
|
1556
1695
|
} finally {
|
|
1696
|
+
activeRun = null;
|
|
1557
1697
|
unsubscribe();
|
|
1558
1698
|
clearAllToolUpdates();
|
|
1559
1699
|
try {
|
|
@@ -1662,7 +1802,20 @@ const plugin = {
|
|
|
1662
1802
|
apiKey,
|
|
1663
1803
|
onRequest: (request) => {
|
|
1664
1804
|
const handle = async () => {
|
|
1665
|
-
if (request.method === "agent")
|
|
1805
|
+
if (request.method === "agent") {
|
|
1806
|
+
const params = request.params;
|
|
1807
|
+
const coalesceKey = params.coalesce === "replace" && typeof params.sessionKey === "string" ? params.sessionKey : void 0;
|
|
1808
|
+
await enqueueAgentTurn(() => handleAgentRequest(request, log), coalesceKey ? {
|
|
1809
|
+
coalesceKey,
|
|
1810
|
+
onSuperseded: () => {
|
|
1811
|
+
log.info(`Agent turn superseded before start (coalesce=replace): ${coalesceKey}`);
|
|
1812
|
+
chatClient?.sendResponse(request.id, true, {
|
|
1813
|
+
superseded: true,
|
|
1814
|
+
sessionKey: coalesceKey
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
} : void 0);
|
|
1818
|
+
} else if (request.method === "chat.abort") handleChatAbort(request, log);
|
|
1666
1819
|
else if (request.method === "sessions.list") await handleSessionsList(request, log);
|
|
1667
1820
|
else if (request.method === "sessions.get") await handleSessionsGet(request, log);
|
|
1668
1821
|
else chatClient?.sendResponse(request.id, false, { message: `Unknown method: ${request.method}` });
|
|
@@ -1795,6 +1948,24 @@ const plugin = {
|
|
|
1795
1948
|
}
|
|
1796
1949
|
};
|
|
1797
1950
|
//#endregion
|
|
1951
|
+
Object.defineProperty(exports, "__agentTurnQueueForTest", {
|
|
1952
|
+
enumerable: true,
|
|
1953
|
+
get: function() {
|
|
1954
|
+
return __agentTurnQueueForTest;
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
Object.defineProperty(exports, "__resetAgentTurnQueueForTest", {
|
|
1958
|
+
enumerable: true,
|
|
1959
|
+
get: function() {
|
|
1960
|
+
return __resetAgentTurnQueueForTest;
|
|
1961
|
+
}
|
|
1962
|
+
});
|
|
1963
|
+
Object.defineProperty(exports, "__setActiveRunForTest", {
|
|
1964
|
+
enumerable: true,
|
|
1965
|
+
get: function() {
|
|
1966
|
+
return __setActiveRunForTest;
|
|
1967
|
+
}
|
|
1968
|
+
});
|
|
1798
1969
|
Object.defineProperty(exports, "admitAgentEvent", {
|
|
1799
1970
|
enumerable: true,
|
|
1800
1971
|
get: function() {
|
|
@@ -1831,6 +2002,12 @@ Object.defineProperty(exports, "plugin", {
|
|
|
1831
2002
|
return plugin;
|
|
1832
2003
|
}
|
|
1833
2004
|
});
|
|
2005
|
+
Object.defineProperty(exports, "resolveAbortTargetKeys", {
|
|
2006
|
+
enumerable: true,
|
|
2007
|
+
get: function() {
|
|
2008
|
+
return resolveAbortTargetKeys;
|
|
2009
|
+
}
|
|
2010
|
+
});
|
|
1834
2011
|
Object.defineProperty(exports, "rewriteAssistantText", {
|
|
1835
2012
|
enumerable: true,
|
|
1836
2013
|
get: function() {
|
package/dist/plugin2.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { RunEventGate, admitAgentEvent, buildA2ACompletePayload, buildToolActivity, plugin as default, joinAssistantText, rewriteAssistantText, stripLeakedToolSummary };
|
|
1
|
+
import { a as __setActiveRunForTest, c as buildToolActivity, d as resolveAbortTargetKeys, f as rewriteAssistantText, i as __resetAgentTurnQueueForTest, l as joinAssistantText, n as RunEventGate, o as admitAgentEvent, p as stripLeakedToolSummary, r as __agentTurnQueueForTest, s as buildA2ACompletePayload, t as ActiveRunRef, u as plugin } from "./plugin.cjs";
|
|
2
|
+
export { ActiveRunRef, RunEventGate, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildToolActivity, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
package/dist/plugin2.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { RunEventGate, admitAgentEvent, buildA2ACompletePayload, buildToolActivity, plugin as default, joinAssistantText, rewriteAssistantText, stripLeakedToolSummary };
|
|
1
|
+
import { a as __setActiveRunForTest, c as buildToolActivity, d as resolveAbortTargetKeys, f as rewriteAssistantText, i as __resetAgentTurnQueueForTest, l as joinAssistantText, n as RunEventGate, o as admitAgentEvent, p as stripLeakedToolSummary, r as __agentTurnQueueForTest, s as buildA2ACompletePayload, t as ActiveRunRef, u as plugin } from "./plugin.js";
|
|
2
|
+
export { ActiveRunRef, RunEventGate, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildToolActivity, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
package/dist/plugin2.js
CHANGED
|
@@ -1186,6 +1186,37 @@ function buildA2ACompletePayload(params) {
|
|
|
1186
1186
|
};
|
|
1187
1187
|
}
|
|
1188
1188
|
let dispatchInbound = null;
|
|
1189
|
+
let abortEmbeddedAgentRun = null;
|
|
1190
|
+
let resolveActiveRunSessionId = null;
|
|
1191
|
+
let resolveRouteEnvelope = null;
|
|
1192
|
+
/**
|
|
1193
|
+
* Load the OpenClaw SDK surfaces from a single resolver anchor. Returns true
|
|
1194
|
+
* once the critical `dispatchInboundDirectDmWithRuntime` is resolved. The abort
|
|
1195
|
+
* primitives + route resolver are best-effort — an older openclaw without them
|
|
1196
|
+
* degrades `chat.abort` to a logged no-op (Stop still seals the UI) rather than
|
|
1197
|
+
* a hard failure.
|
|
1198
|
+
*/
|
|
1199
|
+
function loadOpenClawSdk(req, log, anchor) {
|
|
1200
|
+
let resolvedDispatch = false;
|
|
1201
|
+
try {
|
|
1202
|
+
const channelInbound = req("openclaw/plugin-sdk/channel-inbound");
|
|
1203
|
+
if (channelInbound.dispatchInboundDirectDmWithRuntime) {
|
|
1204
|
+
dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
|
|
1205
|
+
resolvedDispatch = true;
|
|
1206
|
+
}
|
|
1207
|
+
} catch {}
|
|
1208
|
+
try {
|
|
1209
|
+
const harness = req("openclaw/plugin-sdk/agent-harness");
|
|
1210
|
+
if (harness.abortEmbeddedAgentRun) abortEmbeddedAgentRun = harness.abortEmbeddedAgentRun;
|
|
1211
|
+
if (harness.resolveActiveEmbeddedRunSessionId) resolveActiveRunSessionId = harness.resolveActiveEmbeddedRunSessionId;
|
|
1212
|
+
} catch {}
|
|
1213
|
+
try {
|
|
1214
|
+
const envelope = req("openclaw/plugin-sdk/inbound-envelope");
|
|
1215
|
+
if (envelope.resolveInboundRouteEnvelopeBuilderWithRuntime) resolveRouteEnvelope = envelope.resolveInboundRouteEnvelopeBuilderWithRuntime;
|
|
1216
|
+
} catch {}
|
|
1217
|
+
if (resolvedDispatch) log.info(`Resolved OpenClaw SDK from ${anchor} (hard-abort=${abortEmbeddedAgentRun && resolveActiveRunSessionId ? "available" : "unavailable"})`);
|
|
1218
|
+
return resolvedDispatch;
|
|
1219
|
+
}
|
|
1189
1220
|
/**
|
|
1190
1221
|
* Resolve OpenClaw SDK functions from the running process.
|
|
1191
1222
|
*
|
|
@@ -1197,21 +1228,11 @@ let dispatchInbound = null;
|
|
|
1197
1228
|
function resolveOpenClawSdk(log) {
|
|
1198
1229
|
const anchors = [require.main?.filename, process.argv[1]].filter(Boolean);
|
|
1199
1230
|
for (const anchor of anchors) try {
|
|
1200
|
-
|
|
1201
|
-
if (channelInbound.dispatchInboundDirectDmWithRuntime) {
|
|
1202
|
-
dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
|
|
1203
|
-
log.info(`Resolved OpenClaw SDK from ${anchor}`);
|
|
1204
|
-
return;
|
|
1205
|
-
}
|
|
1231
|
+
if (loadOpenClawSdk(createRequire(anchor), log, anchor)) return;
|
|
1206
1232
|
} catch {}
|
|
1207
1233
|
try {
|
|
1208
1234
|
const derivedPath = join(resolve(dirname(process.execPath), ".."), "lib", "node_modules", "openclaw", "package.json");
|
|
1209
|
-
|
|
1210
|
-
if (channelInbound.dispatchInboundDirectDmWithRuntime) {
|
|
1211
|
-
dispatchInbound = channelInbound.dispatchInboundDirectDmWithRuntime;
|
|
1212
|
-
log.info(`Resolved OpenClaw SDK from ${derivedPath}`);
|
|
1213
|
-
return;
|
|
1214
|
-
}
|
|
1235
|
+
if (loadOpenClawSdk(createRequire(derivedPath), log, derivedPath)) return;
|
|
1215
1236
|
} catch {}
|
|
1216
1237
|
log.warn("OpenClaw SDK not resolvable — chat dispatch will not work");
|
|
1217
1238
|
}
|
|
@@ -1288,11 +1309,111 @@ async function downloadAttachments(attachments, log) {
|
|
|
1288
1309
|
}
|
|
1289
1310
|
return results;
|
|
1290
1311
|
}
|
|
1291
|
-
let
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1312
|
+
let agentTurnBacklog = [];
|
|
1313
|
+
let agentTurnDraining = false;
|
|
1314
|
+
function enqueueAgentTurn(task, opts) {
|
|
1315
|
+
return new Promise((resolve, reject) => {
|
|
1316
|
+
const entry = {
|
|
1317
|
+
run: task,
|
|
1318
|
+
coalesceKey: opts?.coalesceKey,
|
|
1319
|
+
onSuperseded: opts?.onSuperseded ?? (() => void 0),
|
|
1320
|
+
resolve,
|
|
1321
|
+
reject
|
|
1322
|
+
};
|
|
1323
|
+
if (entry.coalesceKey) {
|
|
1324
|
+
const survivors = [];
|
|
1325
|
+
for (const queued of agentTurnBacklog) if (queued.coalesceKey === entry.coalesceKey) {
|
|
1326
|
+
try {
|
|
1327
|
+
queued.onSuperseded();
|
|
1328
|
+
} catch {}
|
|
1329
|
+
queued.resolve();
|
|
1330
|
+
} else survivors.push(queued);
|
|
1331
|
+
agentTurnBacklog = survivors;
|
|
1332
|
+
}
|
|
1333
|
+
agentTurnBacklog.push(entry);
|
|
1334
|
+
drainAgentTurns();
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
async function drainAgentTurns() {
|
|
1338
|
+
if (agentTurnDraining) return;
|
|
1339
|
+
agentTurnDraining = true;
|
|
1340
|
+
try {
|
|
1341
|
+
while (agentTurnBacklog.length > 0) {
|
|
1342
|
+
const entry = agentTurnBacklog.shift();
|
|
1343
|
+
if (!entry) break;
|
|
1344
|
+
try {
|
|
1345
|
+
await entry.run();
|
|
1346
|
+
entry.resolve();
|
|
1347
|
+
} catch (err) {
|
|
1348
|
+
entry.reject(err);
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
} finally {
|
|
1352
|
+
agentTurnDraining = false;
|
|
1353
|
+
}
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Test-only: reset the agent-turn backlog between unit tests. Not used at
|
|
1357
|
+
* runtime (the backlog lives for the process lifetime of one daemon).
|
|
1358
|
+
*/
|
|
1359
|
+
function __resetAgentTurnQueueForTest() {
|
|
1360
|
+
agentTurnBacklog = [];
|
|
1361
|
+
agentTurnDraining = false;
|
|
1362
|
+
}
|
|
1363
|
+
/** Test-only accessor for the coalescing queue (see __tests__/queue.test.ts). */
|
|
1364
|
+
const __agentTurnQueueForTest = {
|
|
1365
|
+
enqueue: enqueueAgentTurn,
|
|
1366
|
+
backlogLength: () => agentTurnBacklog.length
|
|
1367
|
+
};
|
|
1368
|
+
let activeRun = null;
|
|
1369
|
+
/** Test-only: set/clear the active-run ref for handleChatAbort unit tests. */
|
|
1370
|
+
function __setActiveRunForTest(ref) {
|
|
1371
|
+
activeRun = ref;
|
|
1372
|
+
}
|
|
1373
|
+
/**
|
|
1374
|
+
* Ordered session keys to try when aborting for `abortSessionKey`. Pure, so it
|
|
1375
|
+
* unit-tests without the OpenClaw SDK. The resolved route key (what the run
|
|
1376
|
+
* registered under) is preferred; the raw request key is a best-effort
|
|
1377
|
+
* fallback. An abort with NO sessionKey targets the single active run. A
|
|
1378
|
+
* sessionKey that does NOT match the running turn yields no candidates — we
|
|
1379
|
+
* never abort another session's run on a shared daemon.
|
|
1380
|
+
*/
|
|
1381
|
+
function resolveAbortTargetKeys(active, abortSessionKey) {
|
|
1382
|
+
const keys = [];
|
|
1383
|
+
if (active && (!abortSessionKey || active.requestSessionKey === abortSessionKey)) {
|
|
1384
|
+
if (active.routeSessionKey) keys.push(active.routeSessionKey);
|
|
1385
|
+
if (!keys.includes(active.requestSessionKey)) keys.push(active.requestSessionKey);
|
|
1386
|
+
} else if (abortSessionKey) keys.push(abortSessionKey);
|
|
1387
|
+
return keys;
|
|
1388
|
+
}
|
|
1389
|
+
/**
|
|
1390
|
+
* `chat.abort` handler — genuinely cancels the RUNNING turn on the daemon.
|
|
1391
|
+
*
|
|
1392
|
+
* Invoked OUT-OF-BAND (never through the serialised agent-turn queue) so it
|
|
1393
|
+
* executes immediately while a turn is mid-flight. Resolves the live run's
|
|
1394
|
+
* sessionId from the target session key and fires the run handle's
|
|
1395
|
+
* AbortController via `abortEmbeddedAgentRun`. The in-flight dispatch then
|
|
1396
|
+
* settles (AbortError), so `handleAgentRequest` sends its RPC response and the
|
|
1397
|
+
* chat service seals the UI. When the abort primitives are unavailable (older
|
|
1398
|
+
* openclaw), this degrades to a logged no-op: the UI is still sealed by the
|
|
1399
|
+
* chat service's optimistic idle broadcast, but the turn completes server-side.
|
|
1400
|
+
*/
|
|
1401
|
+
function handleChatAbort(request, log) {
|
|
1402
|
+
const { sessionKey } = request.params;
|
|
1403
|
+
const targetKeys = resolveAbortTargetKeys(activeRun, sessionKey);
|
|
1404
|
+
let aborted = false;
|
|
1405
|
+
if (abortEmbeddedAgentRun && resolveActiveRunSessionId) {
|
|
1406
|
+
for (const key of targetKeys) {
|
|
1407
|
+
const sessionId = resolveActiveRunSessionId(key);
|
|
1408
|
+
if (sessionId && abortEmbeddedAgentRun(sessionId)) {
|
|
1409
|
+
aborted = true;
|
|
1410
|
+
log.info(`chat.abort: hard-aborted running turn (sessionId=${sessionId}, key=${key})`);
|
|
1411
|
+
break;
|
|
1412
|
+
}
|
|
1413
|
+
}
|
|
1414
|
+
if (!aborted) log.info(`chat.abort: no active run to abort (candidates=${String(targetKeys.length)})`);
|
|
1415
|
+
} else log.warn("chat.abort: OpenClaw abort primitives unavailable — cannot hard-abort the running turn");
|
|
1416
|
+
chatClient?.sendResponse(request.id, true, { aborted });
|
|
1296
1417
|
}
|
|
1297
1418
|
async function handleAgentRequest(request, log) {
|
|
1298
1419
|
const runtime = pluginRuntime;
|
|
@@ -1473,19 +1594,37 @@ async function handleAgentRequest(request, log) {
|
|
|
1473
1594
|
const conversationLabel = conversationType === "group" ? shortConvId ? `[${channelLabel}] Group (${shortConvId})` : `[${channelLabel}] Group` : shortConvId ? `[${channelLabel}] ${userLabel} (${shortConvId})` : `[${channelLabel}] ${userLabel}`;
|
|
1474
1595
|
let a2aResponseBuffer = "";
|
|
1475
1596
|
if (isA2A) resetA2AEndSignal();
|
|
1597
|
+
const peer = conversationType === "group" ? {
|
|
1598
|
+
kind: "group",
|
|
1599
|
+
id: conversationId ?? senderId
|
|
1600
|
+
} : {
|
|
1601
|
+
kind: "direct",
|
|
1602
|
+
id: conversationId ? `${senderId}:conv:${conversationId}` : senderId
|
|
1603
|
+
};
|
|
1604
|
+
let routeSessionKey = null;
|
|
1605
|
+
if (resolveRouteEnvelope) try {
|
|
1606
|
+
routeSessionKey = resolveRouteEnvelope({
|
|
1607
|
+
cfg,
|
|
1608
|
+
channel: "alfe",
|
|
1609
|
+
accountId: "default",
|
|
1610
|
+
peer,
|
|
1611
|
+
runtime: runtime.channel,
|
|
1612
|
+
sessionStore: cfg.session?.store
|
|
1613
|
+
}).route.sessionKey;
|
|
1614
|
+
} catch (err) {
|
|
1615
|
+
log.debug(`Route precompute failed (abort will use raw key): ${err instanceof Error ? err.message : String(err)}`);
|
|
1616
|
+
}
|
|
1617
|
+
activeRun = {
|
|
1618
|
+
requestSessionKey: legacySessionKey,
|
|
1619
|
+
routeSessionKey
|
|
1620
|
+
};
|
|
1476
1621
|
runGate.sessionKey = (await dispatchInbound({
|
|
1477
1622
|
cfg,
|
|
1478
1623
|
runtime: { channel: runtime.channel },
|
|
1479
1624
|
channel: "alfe",
|
|
1480
1625
|
channelLabel,
|
|
1481
1626
|
accountId: "default",
|
|
1482
|
-
peer
|
|
1483
|
-
kind: "group",
|
|
1484
|
-
id: conversationId ?? senderId
|
|
1485
|
-
} : {
|
|
1486
|
-
kind: "direct",
|
|
1487
|
-
id: conversationId ? `${senderId}:conv:${conversationId}` : senderId
|
|
1488
|
-
},
|
|
1627
|
+
peer,
|
|
1489
1628
|
senderId,
|
|
1490
1629
|
senderAddress: senderId,
|
|
1491
1630
|
recipientAddress: "agent",
|
|
@@ -1554,6 +1693,7 @@ async function handleAgentRequest(request, log) {
|
|
|
1554
1693
|
log.error(`Agent dispatch failed: ${errMsg}`);
|
|
1555
1694
|
chatClient?.sendResponse(request.id, false, { message: errMsg });
|
|
1556
1695
|
} finally {
|
|
1696
|
+
activeRun = null;
|
|
1557
1697
|
unsubscribe();
|
|
1558
1698
|
clearAllToolUpdates();
|
|
1559
1699
|
try {
|
|
@@ -1662,7 +1802,20 @@ const plugin = {
|
|
|
1662
1802
|
apiKey,
|
|
1663
1803
|
onRequest: (request) => {
|
|
1664
1804
|
const handle = async () => {
|
|
1665
|
-
if (request.method === "agent")
|
|
1805
|
+
if (request.method === "agent") {
|
|
1806
|
+
const params = request.params;
|
|
1807
|
+
const coalesceKey = params.coalesce === "replace" && typeof params.sessionKey === "string" ? params.sessionKey : void 0;
|
|
1808
|
+
await enqueueAgentTurn(() => handleAgentRequest(request, log), coalesceKey ? {
|
|
1809
|
+
coalesceKey,
|
|
1810
|
+
onSuperseded: () => {
|
|
1811
|
+
log.info(`Agent turn superseded before start (coalesce=replace): ${coalesceKey}`);
|
|
1812
|
+
chatClient?.sendResponse(request.id, true, {
|
|
1813
|
+
superseded: true,
|
|
1814
|
+
sessionKey: coalesceKey
|
|
1815
|
+
});
|
|
1816
|
+
}
|
|
1817
|
+
} : void 0);
|
|
1818
|
+
} else if (request.method === "chat.abort") handleChatAbort(request, log);
|
|
1666
1819
|
else if (request.method === "sessions.list") await handleSessionsList(request, log);
|
|
1667
1820
|
else if (request.method === "sessions.get") await handleSessionsGet(request, log);
|
|
1668
1821
|
else chatClient?.sendResponse(request.id, false, { message: `Unknown method: ${request.method}` });
|
|
@@ -1795,4 +1948,4 @@ const plugin = {
|
|
|
1795
1948
|
}
|
|
1796
1949
|
};
|
|
1797
1950
|
//#endregion
|
|
1798
|
-
export {
|
|
1951
|
+
export { buildA2ACompletePayload as a, plugin as c, stripLeakedToolSummary as d, createAlfeChannelPlugin as f, admitAgentEvent as i, resolveAbortTargetKeys as l, __resetAgentTurnQueueForTest as n, buildToolActivity as o, __setActiveRunForTest as r, joinAssistantText as s, __agentTurnQueueForTest as t, rewriteAssistantText as u };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/openclaw-chat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "OpenClaw chat plugin for Alfe — web widget and mobile app channels",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/plugin.js",
|
|
@@ -27,8 +27,8 @@
|
|
|
27
27
|
"openclaw.plugin.json"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@alfe.ai/chat": "^0.0.14",
|
|
31
30
|
"@alfe.ai/agent-api-client": "^0.5.0",
|
|
31
|
+
"@alfe.ai/chat": "^0.0.14",
|
|
32
32
|
"@alfe.ai/config": "^0.3.0"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|