aamp-openclaw-plugin 0.1.30 → 0.1.32
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.js +172 -14
- package/dist/index.js.map +2 -2
- package/package.json +48 -12
package/dist/index.js
CHANGED
|
@@ -1833,6 +1833,7 @@ var AampClient = class _AampClient extends TinyEmitter {
|
|
|
1833
1833
|
jmapClient;
|
|
1834
1834
|
smtpSender;
|
|
1835
1835
|
config;
|
|
1836
|
+
streamAppendQueues = /* @__PURE__ */ new Map();
|
|
1836
1837
|
constructor(config) {
|
|
1837
1838
|
super();
|
|
1838
1839
|
this.config = config;
|
|
@@ -2162,7 +2163,15 @@ var AampClient = class _AampClient extends TinyEmitter {
|
|
|
2162
2163
|
}
|
|
2163
2164
|
return res.json();
|
|
2164
2165
|
}
|
|
2165
|
-
|
|
2166
|
+
getStreamAppendQueue(streamId) {
|
|
2167
|
+
let queue = this.streamAppendQueues.get(streamId);
|
|
2168
|
+
if (!queue) {
|
|
2169
|
+
queue = { running: false, operations: [] };
|
|
2170
|
+
this.streamAppendQueues.set(streamId, queue);
|
|
2171
|
+
}
|
|
2172
|
+
return queue;
|
|
2173
|
+
}
|
|
2174
|
+
async dispatchStreamAppend(opts) {
|
|
2166
2175
|
const stream = await this.resolveStreamCapability();
|
|
2167
2176
|
const res = await _AampClient.callDiscoveredApi(this.config.baseUrl, {
|
|
2168
2177
|
action: stream.appendAction ?? "aamp.stream.append",
|
|
@@ -2176,7 +2185,98 @@ var AampClient = class _AampClient extends TinyEmitter {
|
|
|
2176
2185
|
}
|
|
2177
2186
|
return res.json();
|
|
2178
2187
|
}
|
|
2188
|
+
enqueueStreamAppend(streamId, operation) {
|
|
2189
|
+
const queue = this.getStreamAppendQueue(streamId);
|
|
2190
|
+
queue.operations.push(operation);
|
|
2191
|
+
void this.drainStreamAppendQueue(streamId);
|
|
2192
|
+
}
|
|
2193
|
+
async drainStreamAppendQueue(streamId) {
|
|
2194
|
+
const queue = this.streamAppendQueues.get(streamId);
|
|
2195
|
+
if (!queue || queue.running)
|
|
2196
|
+
return;
|
|
2197
|
+
queue.running = true;
|
|
2198
|
+
try {
|
|
2199
|
+
while (queue.operations.length) {
|
|
2200
|
+
const operation = queue.operations.shift();
|
|
2201
|
+
if (!operation)
|
|
2202
|
+
continue;
|
|
2203
|
+
if (operation.kind === "text-delta-batch") {
|
|
2204
|
+
try {
|
|
2205
|
+
const event = await this.dispatchStreamAppend({
|
|
2206
|
+
streamId,
|
|
2207
|
+
type: "text.delta",
|
|
2208
|
+
payload: {
|
|
2209
|
+
...operation.payload,
|
|
2210
|
+
text: operation.text
|
|
2211
|
+
}
|
|
2212
|
+
});
|
|
2213
|
+
for (const resolve of operation.resolvers)
|
|
2214
|
+
resolve(event);
|
|
2215
|
+
} catch (error) {
|
|
2216
|
+
for (const reject of operation.rejecters)
|
|
2217
|
+
reject(error);
|
|
2218
|
+
}
|
|
2219
|
+
continue;
|
|
2220
|
+
}
|
|
2221
|
+
try {
|
|
2222
|
+
const event = await this.dispatchStreamAppend(operation.opts);
|
|
2223
|
+
operation.resolve(event);
|
|
2224
|
+
} catch (error) {
|
|
2225
|
+
operation.reject(error);
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
} finally {
|
|
2229
|
+
queue.running = false;
|
|
2230
|
+
if (queue.operations.length === 0) {
|
|
2231
|
+
this.streamAppendQueues.delete(streamId);
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
}
|
|
2235
|
+
async flushStreamAppendQueue(streamId) {
|
|
2236
|
+
while (true) {
|
|
2237
|
+
const queue = this.streamAppendQueues.get(streamId);
|
|
2238
|
+
if (!queue)
|
|
2239
|
+
return;
|
|
2240
|
+
if (!queue.running && queue.operations.length === 0) {
|
|
2241
|
+
this.streamAppendQueues.delete(streamId);
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
async appendStreamEvent(opts) {
|
|
2248
|
+
if (opts.type === "text.delta" && typeof opts.payload.text === "string") {
|
|
2249
|
+
return await new Promise((resolve, reject) => {
|
|
2250
|
+
const queue = this.getStreamAppendQueue(opts.streamId);
|
|
2251
|
+
const lastOperation = queue.operations.at(-1);
|
|
2252
|
+
if (lastOperation?.kind === "text-delta-batch") {
|
|
2253
|
+
lastOperation.text += String(opts.payload.text ?? "");
|
|
2254
|
+
lastOperation.resolvers.push(resolve);
|
|
2255
|
+
lastOperation.rejecters.push(reject);
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
this.enqueueStreamAppend(opts.streamId, {
|
|
2259
|
+
kind: "text-delta-batch",
|
|
2260
|
+
text: String(opts.payload.text ?? ""),
|
|
2261
|
+
payload: {
|
|
2262
|
+
...opts.payload
|
|
2263
|
+
},
|
|
2264
|
+
resolvers: [resolve],
|
|
2265
|
+
rejecters: [reject]
|
|
2266
|
+
});
|
|
2267
|
+
});
|
|
2268
|
+
}
|
|
2269
|
+
return await new Promise((resolve, reject) => {
|
|
2270
|
+
this.enqueueStreamAppend(opts.streamId, {
|
|
2271
|
+
kind: "single-event",
|
|
2272
|
+
opts,
|
|
2273
|
+
resolve,
|
|
2274
|
+
reject
|
|
2275
|
+
});
|
|
2276
|
+
});
|
|
2277
|
+
}
|
|
2179
2278
|
async closeStream(opts) {
|
|
2279
|
+
await this.flushStreamAppendQueue(opts.streamId);
|
|
2180
2280
|
const stream = await this.resolveStreamCapability();
|
|
2181
2281
|
const res = await _AampClient.callDiscoveredApi(this.config.baseUrl, {
|
|
2182
2282
|
action: stream.closeAction ?? "aamp.stream.close",
|
|
@@ -2436,6 +2536,13 @@ function baseUrl(aampHost) {
|
|
|
2436
2536
|
var pendingTasks = /* @__PURE__ */ new Map();
|
|
2437
2537
|
var activeTaskStreams = /* @__PURE__ */ new Map();
|
|
2438
2538
|
var terminalTaskIds = new Set(loadTaskState(defaultTaskStatePath()).terminalTaskIds ?? []);
|
|
2539
|
+
var AAMP_SESSION_PREFIX = "aamp:";
|
|
2540
|
+
var DEFAULT_OPENCLAW_AGENT_ID = "main";
|
|
2541
|
+
var OPENCLAW_AGENT_SESSION_PREFIX = "agent:";
|
|
2542
|
+
var VALID_OPENCLAW_AGENT_ID_RE = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
|
|
2543
|
+
var INVALID_OPENCLAW_AGENT_ID_RE = /[^a-z0-9_-]+/g;
|
|
2544
|
+
var LEADING_DASH_RE = /^-+/;
|
|
2545
|
+
var TRAILING_DASH_RE = /-+$/;
|
|
2439
2546
|
var dispatchedSubtasks = /* @__PURE__ */ new Map();
|
|
2440
2547
|
var waitingDispatches = /* @__PURE__ */ new Map();
|
|
2441
2548
|
var aampClient = null;
|
|
@@ -2447,7 +2554,6 @@ var lastLoggedTransportMode = "disconnected";
|
|
|
2447
2554
|
var reconcileTimer = null;
|
|
2448
2555
|
var transportMonitorTimer = null;
|
|
2449
2556
|
var historicalReconcileCompleted = false;
|
|
2450
|
-
var currentSessionKey = "agent:main:main";
|
|
2451
2557
|
var channelRuntime = null;
|
|
2452
2558
|
var channelCfg = null;
|
|
2453
2559
|
async function ensureTaskStream(task) {
|
|
@@ -2514,6 +2620,50 @@ function logTransportState(api, mode, email, previousMode) {
|
|
|
2514
2620
|
function isSyntheticPendingKey(taskKey) {
|
|
2515
2621
|
return taskKey.startsWith("result:") || taskKey.startsWith("help:");
|
|
2516
2622
|
}
|
|
2623
|
+
function normalizeOpenClawAgentId(value) {
|
|
2624
|
+
const trimmed = typeof value === "string" ? value.trim() : "";
|
|
2625
|
+
if (!trimmed)
|
|
2626
|
+
return DEFAULT_OPENCLAW_AGENT_ID;
|
|
2627
|
+
if (VALID_OPENCLAW_AGENT_ID_RE.test(trimmed))
|
|
2628
|
+
return trimmed.toLowerCase();
|
|
2629
|
+
return trimmed.toLowerCase().replace(INVALID_OPENCLAW_AGENT_ID_RE, "-").replace(LEADING_DASH_RE, "").replace(TRAILING_DASH_RE, "").slice(0, 64) || DEFAULT_OPENCLAW_AGENT_ID;
|
|
2630
|
+
}
|
|
2631
|
+
function resolveDefaultOpenClawAgentId(config) {
|
|
2632
|
+
const agents = config?.agents?.list;
|
|
2633
|
+
if (!Array.isArray(agents) || agents.length === 0)
|
|
2634
|
+
return DEFAULT_OPENCLAW_AGENT_ID;
|
|
2635
|
+
const defaults = agents.filter((agent) => agent?.default);
|
|
2636
|
+
return normalizeOpenClawAgentId((defaults[0] ?? agents[0])?.id);
|
|
2637
|
+
}
|
|
2638
|
+
function stripOpenClawAgentScope(sessionKey) {
|
|
2639
|
+
const trimmed = sessionKey.trim();
|
|
2640
|
+
if (!trimmed.toLowerCase().startsWith(OPENCLAW_AGENT_SESSION_PREFIX))
|
|
2641
|
+
return trimmed;
|
|
2642
|
+
const parts = trimmed.split(":");
|
|
2643
|
+
if (parts.length < 3 || parts[0]?.toLowerCase() !== "agent")
|
|
2644
|
+
return trimmed;
|
|
2645
|
+
return parts.slice(2).join(":");
|
|
2646
|
+
}
|
|
2647
|
+
function isAampSessionKey(sessionKey) {
|
|
2648
|
+
return typeof sessionKey === "string" && stripOpenClawAgentScope(sessionKey).toLowerCase().startsWith(AAMP_SESSION_PREFIX);
|
|
2649
|
+
}
|
|
2650
|
+
function buildOpenClawMainSessionKey(mainKey, config) {
|
|
2651
|
+
const trimmed = mainKey.trim();
|
|
2652
|
+
if (!trimmed)
|
|
2653
|
+
return `${OPENCLAW_AGENT_SESSION_PREFIX}${resolveDefaultOpenClawAgentId(config)}:main`;
|
|
2654
|
+
if (trimmed.toLowerCase().startsWith(OPENCLAW_AGENT_SESSION_PREFIX))
|
|
2655
|
+
return trimmed;
|
|
2656
|
+
return `${OPENCLAW_AGENT_SESSION_PREFIX}${resolveDefaultOpenClawAgentId(config)}:${trimmed}`;
|
|
2657
|
+
}
|
|
2658
|
+
function buildAampConversationSessionKey(value, config) {
|
|
2659
|
+
return buildOpenClawMainSessionKey(`${AAMP_SESSION_PREFIX}default:${value}`, config);
|
|
2660
|
+
}
|
|
2661
|
+
function buildAampTaskSessionKey(taskId, config) {
|
|
2662
|
+
return buildAampConversationSessionKey(`task:${taskId}`, config);
|
|
2663
|
+
}
|
|
2664
|
+
function buildAampWakeSessionKey(kind, id) {
|
|
2665
|
+
return `${AAMP_SESSION_PREFIX}wake:${kind}:${id}`;
|
|
2666
|
+
}
|
|
2517
2667
|
function saveTerminalTaskIds() {
|
|
2518
2668
|
saveTaskState({ terminalTaskIds: [...terminalTaskIds] }, defaultTaskStatePath());
|
|
2519
2669
|
}
|
|
@@ -2749,10 +2899,12 @@ var src_default = {
|
|
|
2749
2899
|
api.logger.info(`[AAMP] Directory profile synced${cardText ? " (card text registered)" : ""}`);
|
|
2750
2900
|
}
|
|
2751
2901
|
function wakeAgentForPendingTask(task) {
|
|
2752
|
-
const
|
|
2902
|
+
const fallbackSessionKey = buildAampWakeSessionKey("task", task.taskId);
|
|
2903
|
+
const openClawSessionKey = buildAampTaskSessionKey(task.taskId, api.config);
|
|
2904
|
+
const fallback = () => triggerHeartbeatWake(fallbackSessionKey, `task ${task.taskId}`);
|
|
2753
2905
|
const dispatcher = channelRuntime?.reply?.dispatchReplyWithBufferedBlockDispatcher;
|
|
2754
2906
|
api.logger.info(
|
|
2755
|
-
`[AAMP] Wake requested for task ${task.taskId} \u2014 channelRuntime=${channelRuntime ? "yes" : "no"} channelCfg=${channelCfg ? "yes" : "no"} dispatcher=${typeof dispatcher === "function" ? "yes" : "no"} session=${
|
|
2907
|
+
`[AAMP] Wake requested for task ${task.taskId} \u2014 channelRuntime=${channelRuntime ? "yes" : "no"} channelCfg=${channelCfg ? "yes" : "no"} dispatcher=${typeof dispatcher === "function" ? "yes" : "no"} session=${openClawSessionKey} fallbackSession=${fallbackSessionKey}`
|
|
2756
2908
|
);
|
|
2757
2909
|
if (!channelRuntime || !channelCfg || typeof dispatcher !== "function") {
|
|
2758
2910
|
fallback();
|
|
@@ -2772,7 +2924,7 @@ var src_default = {
|
|
|
2772
2924
|
BodyForAgent: prompt,
|
|
2773
2925
|
From: task.from,
|
|
2774
2926
|
To: agentEmail,
|
|
2775
|
-
SessionKey:
|
|
2927
|
+
SessionKey: openClawSessionKey,
|
|
2776
2928
|
AccountId: "default",
|
|
2777
2929
|
ChatType: "dm",
|
|
2778
2930
|
Provider: "aamp",
|
|
@@ -2879,7 +3031,7 @@ var src_default = {
|
|
|
2879
3031
|
} catch (err) {
|
|
2880
3032
|
api.logger.error(`[AAMP] task.dispatch handler failed for ${task.taskId}: ${err.message}`);
|
|
2881
3033
|
if (pendingTasks.has(task.taskId)) {
|
|
2882
|
-
triggerHeartbeatWake(
|
|
3034
|
+
triggerHeartbeatWake(buildAampWakeSessionKey("task", task.taskId), `task ${task.taskId}`);
|
|
2883
3035
|
}
|
|
2884
3036
|
}
|
|
2885
3037
|
})();
|
|
@@ -2986,7 +3138,7 @@ ${notifyBody?.bodyText ?? "Sub-task completed."}${actionSection}`;
|
|
|
2986
3138
|
BodyForAgent: prompt,
|
|
2987
3139
|
From: result.from,
|
|
2988
3140
|
To: agentEmail,
|
|
2989
|
-
SessionKey:
|
|
3141
|
+
SessionKey: buildAampConversationSessionKey(result.from, api.config),
|
|
2990
3142
|
AccountId: "default",
|
|
2991
3143
|
ChatType: "dm",
|
|
2992
3144
|
Provider: "aamp",
|
|
@@ -3014,7 +3166,7 @@ ${notifyBody?.bodyText ?? "Sub-task completed."}${actionSection}`;
|
|
|
3014
3166
|
api.logger.error(`[AAMP] Channel dispatch failed: ${err.message}`);
|
|
3015
3167
|
});
|
|
3016
3168
|
} else {
|
|
3017
|
-
const notifySessionKey =
|
|
3169
|
+
const notifySessionKey = buildAampWakeSessionKey("result", result.taskId);
|
|
3018
3170
|
try {
|
|
3019
3171
|
api.runtime.system.requestHeartbeatNow({ reason: "wake", sessionKey: notifySessionKey });
|
|
3020
3172
|
api.logger.info(`[AAMP] Heartbeat for sub-task result ${result.taskId}`);
|
|
@@ -3063,7 +3215,7 @@ ${notifyBody?.bodyText ?? help.question}`;
|
|
|
3063
3215
|
BodyForAgent: prompt,
|
|
3064
3216
|
From: help.from,
|
|
3065
3217
|
To: agentEmail,
|
|
3066
|
-
SessionKey:
|
|
3218
|
+
SessionKey: buildAampConversationSessionKey(help.from, api.config),
|
|
3067
3219
|
AccountId: "default",
|
|
3068
3220
|
ChatType: "dm",
|
|
3069
3221
|
Provider: "aamp",
|
|
@@ -3090,7 +3242,7 @@ ${notifyBody?.bodyText ?? help.question}`;
|
|
|
3090
3242
|
api.logger.error(`[AAMP] Channel dispatch failed for help: ${err.message}`);
|
|
3091
3243
|
});
|
|
3092
3244
|
} else {
|
|
3093
|
-
const helpSessionKey =
|
|
3245
|
+
const helpSessionKey = buildAampWakeSessionKey("help", help.taskId);
|
|
3094
3246
|
try {
|
|
3095
3247
|
api.runtime.system.requestHeartbeatNow({ reason: "wake", sessionKey: helpSessionKey });
|
|
3096
3248
|
api.logger.info(`[AAMP] Heartbeat fallback for sub-task help ${help.taskId}`);
|
|
@@ -3230,7 +3382,10 @@ ${notifyBody?.bodyText ?? help.question}`;
|
|
|
3230
3382
|
return;
|
|
3231
3383
|
api.logger.info(`[AAMP] gateway_start: re-triggering heartbeat for ${pendingTasks.size} pending task(s)`);
|
|
3232
3384
|
try {
|
|
3233
|
-
api.runtime.system.requestHeartbeatNow({
|
|
3385
|
+
api.runtime.system.requestHeartbeatNow({
|
|
3386
|
+
reason: "wake",
|
|
3387
|
+
sessionKey: buildAampWakeSessionKey("queue", "gateway-start")
|
|
3388
|
+
});
|
|
3234
3389
|
} catch (err) {
|
|
3235
3390
|
api.logger.warn(`[AAMP] gateway_start heartbeat failed: ${err.message}`);
|
|
3236
3391
|
}
|
|
@@ -3238,8 +3393,8 @@ ${notifyBody?.bodyText ?? help.question}`;
|
|
|
3238
3393
|
api.on(
|
|
3239
3394
|
"before_prompt_build",
|
|
3240
3395
|
(_event, ctx) => {
|
|
3241
|
-
if (
|
|
3242
|
-
|
|
3396
|
+
if (!isAampSessionKey(ctx?.sessionKey)) {
|
|
3397
|
+
return {};
|
|
3243
3398
|
}
|
|
3244
3399
|
for (const [id, t] of pendingTasks) {
|
|
3245
3400
|
if (hasExpired(t)) {
|
|
@@ -3525,7 +3680,10 @@ ${task.contextLinks.map((l) => ` - ${l}`).join("\n")}` : "",
|
|
|
3525
3680
|
api.logger.info(`[AAMP] \u2192 task.result ${task.taskId} ${p.status}`);
|
|
3526
3681
|
if (pendingTasks.size > 0) {
|
|
3527
3682
|
try {
|
|
3528
|
-
api.runtime.system.requestHeartbeatNow({
|
|
3683
|
+
api.runtime.system.requestHeartbeatNow({
|
|
3684
|
+
reason: "wake",
|
|
3685
|
+
sessionKey: buildAampWakeSessionKey("queue", "follow-up")
|
|
3686
|
+
});
|
|
3529
3687
|
} catch {
|
|
3530
3688
|
}
|
|
3531
3689
|
}
|