@alfe.ai/openclaw-chat 0.9.4 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/plugin.cjs +1 -0
- package/dist/plugin.d.cts +47 -1
- package/dist/plugin.d.ts +47 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin2.cjs +137 -10
- package/dist/plugin2.d.cts +2 -2
- package/dist/plugin2.d.ts +2 -2
- package/dist/plugin2.js +132 -11
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as AlfeResolvedAccount, E as SessionSummary, S as AlfePluginConfig, T as SessionData, b as createAlfeChannelPlugin, g as plugin, w as ChatMessage, x as AlfeChannelConfig } from "./plugin.cjs";
|
|
2
2
|
export { type AlfeChannelConfig, type AlfePluginConfig, type AlfeResolvedAccount, type ChatMessage, type SessionData, type SessionSummary, createAlfeChannelPlugin, plugin as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { C as
|
|
1
|
+
import { C as AlfeResolvedAccount, E as SessionSummary, S as AlfePluginConfig, T as SessionData, b as createAlfeChannelPlugin, g as plugin, w as ChatMessage, x as AlfeChannelConfig } from "./plugin.js";
|
|
2
2
|
export { type AlfeChannelConfig, type AlfePluginConfig, type AlfeResolvedAccount, type ChatMessage, type SessionData, type SessionSummary, createAlfeChannelPlugin, plugin as default };
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { _ as createAlfeChannelPlugin, p as plugin } from "./plugin2.js";
|
|
2
2
|
export { createAlfeChannelPlugin, plugin as default };
|
package/dist/plugin.cjs
CHANGED
|
@@ -13,6 +13,7 @@ exports.buildA2ACompletePayload = require_plugin.buildA2ACompletePayload;
|
|
|
13
13
|
exports.buildOriginEnvelopeContext = require_plugin.buildOriginEnvelopeContext;
|
|
14
14
|
exports.buildToolActivity = require_plugin.buildToolActivity;
|
|
15
15
|
exports.computeOpenClawSdkAnchors = require_plugin.computeOpenClawSdkAnchors;
|
|
16
|
+
exports.decideChatServiceStart = require_plugin.decideChatServiceStart;
|
|
16
17
|
exports.default = require_plugin.plugin;
|
|
17
18
|
exports.joinAssistantText = require_plugin.joinAssistantText;
|
|
18
19
|
exports.resolveAbortTargetKeys = require_plugin.resolveAbortTargetKeys;
|
package/dist/plugin.d.cts
CHANGED
|
@@ -64,6 +64,20 @@ type StoredMessageComponent = {
|
|
|
64
64
|
label: string;
|
|
65
65
|
value: string;
|
|
66
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* Persisted reference to a message attachment. Deliberately stores NO URL —
|
|
69
|
+
* the download URL is short-lived and re-signed on demand through the chat
|
|
70
|
+
* service's participant-gated resolve endpoint (keyed by `attachmentId`). Only
|
|
71
|
+
* media bound to the conversation (a real chat-bucket upload) is persisted;
|
|
72
|
+
* remote-passthrough media has no `attachmentId` and is not stored.
|
|
73
|
+
*/
|
|
74
|
+
interface StoredAttachment {
|
|
75
|
+
attachmentId: string;
|
|
76
|
+
type: 'image' | 'video' | 'audio' | 'document' | 'file';
|
|
77
|
+
mimeType: string;
|
|
78
|
+
filename: string;
|
|
79
|
+
size?: number;
|
|
80
|
+
}
|
|
67
81
|
interface ChatMessage {
|
|
68
82
|
role: 'user' | 'assistant';
|
|
69
83
|
content: string;
|
|
@@ -77,6 +91,12 @@ interface ChatMessage {
|
|
|
77
91
|
* content). Persisted so a refresh / reconnect replays the button.
|
|
78
92
|
*/
|
|
79
93
|
components?: StoredMessageComponent[];
|
|
94
|
+
/**
|
|
95
|
+
* Attachment references (images/files). Additive — absent on pre-attachment
|
|
96
|
+
* files. Persisted so history replays them; the client resolves each URL on
|
|
97
|
+
* demand via the participant-gated endpoint. See {@link StoredAttachment}.
|
|
98
|
+
*/
|
|
99
|
+
attachments?: StoredAttachment[];
|
|
80
100
|
}
|
|
81
101
|
/**
|
|
82
102
|
* Persisted form of a turn's agent activity (tool cards + thinking), so a
|
|
@@ -600,6 +620,32 @@ interface AnchorEnv {
|
|
|
600
620
|
* Pure except for the injected `realpath` / `which` seams — unit-tested.
|
|
601
621
|
*/
|
|
602
622
|
declare function computeOpenClawSdkAnchors(deps: AnchorEnv): string[];
|
|
623
|
+
/**
|
|
624
|
+
* Decide what `startChatService()` should do given the current connection
|
|
625
|
+
* state. Pure so the branch logic — the load-bearing fix for the
|
|
626
|
+
* health-monitor no-op restart loop (Badi Junior, 2026-07-09) — is unit
|
|
627
|
+
* testable without standing up a real WebSocket or the OpenClaw SDK.
|
|
628
|
+
*
|
|
629
|
+
* OpenClaw calls the registered service's `start()` in two very different
|
|
630
|
+
* situations that a sticky activation flag could not tell apart:
|
|
631
|
+
* - a redundant duplicate (re-`activate()` per tool-discovery pass / reconnect)
|
|
632
|
+
* → must be a no-op ('skip'), and
|
|
633
|
+
* - a channel health-monitor REVIVE of a channel it decided is "stopped"
|
|
634
|
+
* (`health-monitor: [alfe:default] restarting (reason: stopped)`), sometimes
|
|
635
|
+
* with no preceding `stop()` → must actually reconnect.
|
|
636
|
+
*
|
|
637
|
+
* Keying on the live client fixes it:
|
|
638
|
+
* - a connect in flight, or an already-connected client → 'skip'
|
|
639
|
+
* - a client that exists but is not connected → 'recycle' it then reconnect
|
|
640
|
+
* - no client at all → 'connect'
|
|
641
|
+
*
|
|
642
|
+
* Exported for unit tests.
|
|
643
|
+
*/
|
|
644
|
+
declare function decideChatServiceStart(state: {
|
|
645
|
+
connectInFlight: boolean;
|
|
646
|
+
clientPresent: boolean;
|
|
647
|
+
clientConnected: boolean;
|
|
648
|
+
}): 'skip' | 'recycle' | 'connect';
|
|
603
649
|
declare function enqueueAgentTurn(task: () => Promise<void>, opts?: {
|
|
604
650
|
coalesceKey?: string;
|
|
605
651
|
onSuperseded?: () => void;
|
|
@@ -681,4 +727,4 @@ declare const plugin: {
|
|
|
681
727
|
deactivate(api: PluginApi): Promise<void>;
|
|
682
728
|
};
|
|
683
729
|
//#endregion
|
|
684
|
-
export {
|
|
730
|
+
export { AlfeResolvedAccount as C, SessionSummary as E, AlfePluginConfig as S, SessionData as T, resolveAbortTargetKeys as _, VOICE_REPLY_SYSTEM_PROMPT as a, createAlfeChannelPlugin as b, __setActiveRunForTest as c, buildOriginEnvelopeContext as d, buildToolActivity as f, plugin as g, joinAssistantText as h, RunEventGate as i, admitAgentEvent as l, decideChatServiceStart as m, AnchorEnv as n, __agentTurnQueueForTest as o, computeOpenClawSdkAnchors as p, CROSS_AGENT_TOOLS_SYSTEM_PROMPT as r, __resetAgentTurnQueueForTest as s, ActiveRunRef as t, buildA2ACompletePayload as u, rewriteAssistantText as v, ChatMessage as w, AlfeChannelConfig as x, stripLeakedToolSummary as y };
|
package/dist/plugin.d.ts
CHANGED
|
@@ -64,6 +64,20 @@ type StoredMessageComponent = {
|
|
|
64
64
|
label: string;
|
|
65
65
|
value: string;
|
|
66
66
|
};
|
|
67
|
+
/**
|
|
68
|
+
* Persisted reference to a message attachment. Deliberately stores NO URL —
|
|
69
|
+
* the download URL is short-lived and re-signed on demand through the chat
|
|
70
|
+
* service's participant-gated resolve endpoint (keyed by `attachmentId`). Only
|
|
71
|
+
* media bound to the conversation (a real chat-bucket upload) is persisted;
|
|
72
|
+
* remote-passthrough media has no `attachmentId` and is not stored.
|
|
73
|
+
*/
|
|
74
|
+
interface StoredAttachment {
|
|
75
|
+
attachmentId: string;
|
|
76
|
+
type: 'image' | 'video' | 'audio' | 'document' | 'file';
|
|
77
|
+
mimeType: string;
|
|
78
|
+
filename: string;
|
|
79
|
+
size?: number;
|
|
80
|
+
}
|
|
67
81
|
interface ChatMessage {
|
|
68
82
|
role: 'user' | 'assistant';
|
|
69
83
|
content: string;
|
|
@@ -77,6 +91,12 @@ interface ChatMessage {
|
|
|
77
91
|
* content). Persisted so a refresh / reconnect replays the button.
|
|
78
92
|
*/
|
|
79
93
|
components?: StoredMessageComponent[];
|
|
94
|
+
/**
|
|
95
|
+
* Attachment references (images/files). Additive — absent on pre-attachment
|
|
96
|
+
* files. Persisted so history replays them; the client resolves each URL on
|
|
97
|
+
* demand via the participant-gated endpoint. See {@link StoredAttachment}.
|
|
98
|
+
*/
|
|
99
|
+
attachments?: StoredAttachment[];
|
|
80
100
|
}
|
|
81
101
|
/**
|
|
82
102
|
* Persisted form of a turn's agent activity (tool cards + thinking), so a
|
|
@@ -600,6 +620,32 @@ interface AnchorEnv {
|
|
|
600
620
|
* Pure except for the injected `realpath` / `which` seams — unit-tested.
|
|
601
621
|
*/
|
|
602
622
|
declare function computeOpenClawSdkAnchors(deps: AnchorEnv): string[];
|
|
623
|
+
/**
|
|
624
|
+
* Decide what `startChatService()` should do given the current connection
|
|
625
|
+
* state. Pure so the branch logic — the load-bearing fix for the
|
|
626
|
+
* health-monitor no-op restart loop (Badi Junior, 2026-07-09) — is unit
|
|
627
|
+
* testable without standing up a real WebSocket or the OpenClaw SDK.
|
|
628
|
+
*
|
|
629
|
+
* OpenClaw calls the registered service's `start()` in two very different
|
|
630
|
+
* situations that a sticky activation flag could not tell apart:
|
|
631
|
+
* - a redundant duplicate (re-`activate()` per tool-discovery pass / reconnect)
|
|
632
|
+
* → must be a no-op ('skip'), and
|
|
633
|
+
* - a channel health-monitor REVIVE of a channel it decided is "stopped"
|
|
634
|
+
* (`health-monitor: [alfe:default] restarting (reason: stopped)`), sometimes
|
|
635
|
+
* with no preceding `stop()` → must actually reconnect.
|
|
636
|
+
*
|
|
637
|
+
* Keying on the live client fixes it:
|
|
638
|
+
* - a connect in flight, or an already-connected client → 'skip'
|
|
639
|
+
* - a client that exists but is not connected → 'recycle' it then reconnect
|
|
640
|
+
* - no client at all → 'connect'
|
|
641
|
+
*
|
|
642
|
+
* Exported for unit tests.
|
|
643
|
+
*/
|
|
644
|
+
declare function decideChatServiceStart(state: {
|
|
645
|
+
connectInFlight: boolean;
|
|
646
|
+
clientPresent: boolean;
|
|
647
|
+
clientConnected: boolean;
|
|
648
|
+
}): 'skip' | 'recycle' | 'connect';
|
|
603
649
|
declare function enqueueAgentTurn(task: () => Promise<void>, opts?: {
|
|
604
650
|
coalesceKey?: string;
|
|
605
651
|
onSuperseded?: () => void;
|
|
@@ -681,4 +727,4 @@ declare const plugin: {
|
|
|
681
727
|
deactivate(api: PluginApi): Promise<void>;
|
|
682
728
|
};
|
|
683
729
|
//#endregion
|
|
684
|
-
export {
|
|
730
|
+
export { AlfeResolvedAccount as C, SessionSummary as E, AlfePluginConfig as S, SessionData as T, resolveAbortTargetKeys as _, VOICE_REPLY_SYSTEM_PROMPT as a, createAlfeChannelPlugin as b, __setActiveRunForTest as c, buildOriginEnvelopeContext as d, buildToolActivity as f, plugin as g, joinAssistantText as h, RunEventGate as i, admitAgentEvent as l, decideChatServiceStart as m, AnchorEnv as n, __agentTurnQueueForTest as o, computeOpenClawSdkAnchors as p, CROSS_AGENT_TOOLS_SYSTEM_PROMPT as r, __resetAgentTurnQueueForTest as s, ActiveRunRef as t, buildA2ACompletePayload as u, rewriteAssistantText as v, ChatMessage as w, AlfeChannelConfig as x, stripLeakedToolSummary as y };
|
package/dist/plugin.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as __setActiveRunForTest, c as buildOriginEnvelopeContext, d as
|
|
2
|
-
export { CROSS_AGENT_TOOLS_SYSTEM_PROMPT, VOICE_REPLY_SYSTEM_PROMPT, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildOriginEnvelopeContext, buildToolActivity, computeOpenClawSdkAnchors, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
|
1
|
+
import { a as __setActiveRunForTest, c as buildOriginEnvelopeContext, d as decideChatServiceStart, f as joinAssistantText, g as stripLeakedToolSummary, h as rewriteAssistantText, i as __resetAgentTurnQueueForTest, l as buildToolActivity, m as resolveAbortTargetKeys, n as VOICE_REPLY_SYSTEM_PROMPT, o as admitAgentEvent, p as plugin, r as __agentTurnQueueForTest, s as buildA2ACompletePayload, t as CROSS_AGENT_TOOLS_SYSTEM_PROMPT, u as computeOpenClawSdkAnchors } from "./plugin2.js";
|
|
2
|
+
export { CROSS_AGENT_TOOLS_SYSTEM_PROMPT, VOICE_REPLY_SYSTEM_PROMPT, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildOriginEnvelopeContext, buildToolActivity, computeOpenClawSdkAnchors, decideChatServiceStart, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
package/dist/plugin2.cjs
CHANGED
|
@@ -210,7 +210,8 @@ async function uploadLocalFile(localPath, log, deps) {
|
|
|
210
210
|
url: presigned.downloadUrl,
|
|
211
211
|
filename,
|
|
212
212
|
mimeType,
|
|
213
|
-
size
|
|
213
|
+
size,
|
|
214
|
+
attachmentId: presigned.id
|
|
214
215
|
};
|
|
215
216
|
} catch (err) {
|
|
216
217
|
log.warn(`Outbound media upload failed for ${filename}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -874,7 +875,7 @@ async function createSession(sessionId, agentId, channel, tenantId, userId) {
|
|
|
874
875
|
return session;
|
|
875
876
|
}
|
|
876
877
|
const writeLocks = /* @__PURE__ */ new Map();
|
|
877
|
-
async function addMessage(sessionId, role, content, senderId, senderName, components) {
|
|
878
|
+
async function addMessage(sessionId, role, content, senderId, senderName, components, attachments) {
|
|
878
879
|
const next = (writeLocks.get(sessionId) ?? Promise.resolve()).then(async () => {
|
|
879
880
|
const session = await getSession(sessionId);
|
|
880
881
|
if (!session) return;
|
|
@@ -884,7 +885,8 @@ async function addMessage(sessionId, role, content, senderId, senderName, compon
|
|
|
884
885
|
timestamp: Date.now(),
|
|
885
886
|
...senderId ? { senderId } : {},
|
|
886
887
|
...senderName ? { senderName } : {},
|
|
887
|
-
...components?.length ? { components } : {}
|
|
888
|
+
...components?.length ? { components } : {},
|
|
889
|
+
...attachments?.length ? { attachments } : {}
|
|
888
890
|
});
|
|
889
891
|
await saveSession(session);
|
|
890
892
|
}).finally(() => {
|
|
@@ -2201,6 +2203,105 @@ function resolveOpenClawSdk(log) {
|
|
|
2201
2203
|
let pluginRuntime = null;
|
|
2202
2204
|
let chatClient = null;
|
|
2203
2205
|
let connectingPromise = null;
|
|
2206
|
+
/**
|
|
2207
|
+
* Decide what `startChatService()` should do given the current connection
|
|
2208
|
+
* state. Pure so the branch logic — the load-bearing fix for the
|
|
2209
|
+
* health-monitor no-op restart loop (Badi Junior, 2026-07-09) — is unit
|
|
2210
|
+
* testable without standing up a real WebSocket or the OpenClaw SDK.
|
|
2211
|
+
*
|
|
2212
|
+
* OpenClaw calls the registered service's `start()` in two very different
|
|
2213
|
+
* situations that a sticky activation flag could not tell apart:
|
|
2214
|
+
* - a redundant duplicate (re-`activate()` per tool-discovery pass / reconnect)
|
|
2215
|
+
* → must be a no-op ('skip'), and
|
|
2216
|
+
* - a channel health-monitor REVIVE of a channel it decided is "stopped"
|
|
2217
|
+
* (`health-monitor: [alfe:default] restarting (reason: stopped)`), sometimes
|
|
2218
|
+
* with no preceding `stop()` → must actually reconnect.
|
|
2219
|
+
*
|
|
2220
|
+
* Keying on the live client fixes it:
|
|
2221
|
+
* - a connect in flight, or an already-connected client → 'skip'
|
|
2222
|
+
* - a client that exists but is not connected → 'recycle' it then reconnect
|
|
2223
|
+
* - no client at all → 'connect'
|
|
2224
|
+
*
|
|
2225
|
+
* Exported for unit tests.
|
|
2226
|
+
*/
|
|
2227
|
+
function decideChatServiceStart(state) {
|
|
2228
|
+
if (state.connectInFlight) return "skip";
|
|
2229
|
+
if (state.clientPresent && state.clientConnected) return "skip";
|
|
2230
|
+
if (state.clientPresent) return "recycle";
|
|
2231
|
+
return "connect";
|
|
2232
|
+
}
|
|
2233
|
+
const STORED_ATTACHMENT_TYPES = new Set([
|
|
2234
|
+
"image",
|
|
2235
|
+
"video",
|
|
2236
|
+
"audio",
|
|
2237
|
+
"document",
|
|
2238
|
+
"file"
|
|
2239
|
+
]);
|
|
2240
|
+
/** Narrow a possibly-loose type string, inferring from the mime as a fallback. */
|
|
2241
|
+
function coerceStoredAttachmentType(type, mimeType) {
|
|
2242
|
+
if (type && STORED_ATTACHMENT_TYPES.has(type)) return type;
|
|
2243
|
+
const m = mimeType ?? "";
|
|
2244
|
+
if (m.startsWith("image/")) return "image";
|
|
2245
|
+
if (m.startsWith("video/")) return "video";
|
|
2246
|
+
if (m.startsWith("audio/")) return "audio";
|
|
2247
|
+
if (m === "application/pdf" || m.includes("document") || m.includes("spreadsheet") || m.includes("presentation")) return "document";
|
|
2248
|
+
return "file";
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* Map inbound user attachments to the persisted reference shape (drops the
|
|
2252
|
+
* presigned url — it's re-signed on demand). Every composer upload carries a
|
|
2253
|
+
* chat-bucket `id`, so all are persisted.
|
|
2254
|
+
*/
|
|
2255
|
+
function userAttachmentsToStored(refs) {
|
|
2256
|
+
if (!refs?.length) return void 0;
|
|
2257
|
+
const out = [];
|
|
2258
|
+
for (const r of refs) {
|
|
2259
|
+
if (!r.id) continue;
|
|
2260
|
+
out.push({
|
|
2261
|
+
attachmentId: r.id,
|
|
2262
|
+
type: coerceStoredAttachmentType(r.type, r.mimeType),
|
|
2263
|
+
mimeType: r.mimeType,
|
|
2264
|
+
filename: r.filename ?? "file",
|
|
2265
|
+
...typeof r.size === "number" && r.size > 0 ? { size: r.size } : {}
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
return out.length ? out : void 0;
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Map resolved assistant media to persisted references. Only media uploaded to
|
|
2272
|
+
* our bucket (carrying `attachmentId`) is replayable — remote-passthrough media
|
|
2273
|
+
* has no bindable record and stays live-URL-only.
|
|
2274
|
+
*/
|
|
2275
|
+
function assistantMediaToStored(media) {
|
|
2276
|
+
if (!media?.length) return void 0;
|
|
2277
|
+
const out = [];
|
|
2278
|
+
for (const m of media) {
|
|
2279
|
+
if (!m.attachmentId) continue;
|
|
2280
|
+
out.push({
|
|
2281
|
+
attachmentId: m.attachmentId,
|
|
2282
|
+
type: coerceStoredAttachmentType(void 0, m.mimeType),
|
|
2283
|
+
mimeType: m.mimeType ?? "application/octet-stream",
|
|
2284
|
+
filename: m.filename ?? "file",
|
|
2285
|
+
...typeof m.size === "number" && m.size > 0 ? { size: m.size } : {}
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
return out.length ? out : void 0;
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Project persisted attachment references onto the `sessions.get` wire shape.
|
|
2292
|
+
* `attachmentId` becomes the wire `id`; the URL is intentionally omitted — the
|
|
2293
|
+
* client resolves a short-lived signed URL on demand.
|
|
2294
|
+
*/
|
|
2295
|
+
function replayAttachments(atts) {
|
|
2296
|
+
if (!atts?.length) return void 0;
|
|
2297
|
+
return atts.map((a) => ({
|
|
2298
|
+
id: a.attachmentId,
|
|
2299
|
+
type: a.type,
|
|
2300
|
+
mimeType: a.mimeType,
|
|
2301
|
+
filename: a.filename,
|
|
2302
|
+
...typeof a.size === "number" ? { size: a.size } : {}
|
|
2303
|
+
}));
|
|
2304
|
+
}
|
|
2204
2305
|
const MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
2205
2306
|
const DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
2206
2307
|
const MAX_REDIRECTS = 5;
|
|
@@ -2450,7 +2551,7 @@ async function handleAgentRequest(request, log) {
|
|
|
2450
2551
|
const cfg = runtime.config.loadConfig();
|
|
2451
2552
|
const sessionId = conversationId ?? legacySessionKey;
|
|
2452
2553
|
if (!await getSession(sessionId)) await createSession(sessionId, "", "alfe", tenantId, userId);
|
|
2453
|
-
await addMessage(sessionId, "user", message, userId ?? senderId, displayName ?? senderId);
|
|
2554
|
+
await addMessage(sessionId, "user", message, userId ?? senderId, displayName ?? senderId, void 0, userAttachmentsToStored(rawAttachments));
|
|
2454
2555
|
const runGate = {
|
|
2455
2556
|
runId: null,
|
|
2456
2557
|
sessionKey: null
|
|
@@ -2686,7 +2787,7 @@ async function handleAgentRequest(request, log) {
|
|
|
2686
2787
|
const note = formatMediaFailureNote(media.newFailures);
|
|
2687
2788
|
responseText = responseText ? `${responseText}\n\n${note}` : note;
|
|
2688
2789
|
}
|
|
2689
|
-
await addMessage(sessionId, "assistant", responseText);
|
|
2790
|
+
await addMessage(sessionId, "assistant", responseText, void 0, void 0, void 0, assistantMediaToStored(media.attachments));
|
|
2690
2791
|
if (isA2A) a2aResponseBuffer += (a2aResponseBuffer && responseText ? "\n\n" : "") + responseText;
|
|
2691
2792
|
chatClient?.notify("agent-message", {
|
|
2692
2793
|
conversationId: conversationId ?? legacySessionKey,
|
|
@@ -2799,7 +2900,8 @@ async function handleSessionsGet(request, log) {
|
|
|
2799
2900
|
role: m.role,
|
|
2800
2901
|
content: m.content,
|
|
2801
2902
|
timestamp: m.timestamp,
|
|
2802
|
-
...m.components?.length ? { components: m.components } : {}
|
|
2903
|
+
...m.components?.length ? { components: m.components } : {},
|
|
2904
|
+
...m.attachments?.length ? { attachments: replayAttachments(m.attachments) } : {}
|
|
2803
2905
|
})),
|
|
2804
2906
|
activity: await resolveHistoryActivity(session)
|
|
2805
2907
|
});
|
|
@@ -2844,15 +2946,30 @@ const plugin = {
|
|
|
2844
2946
|
}
|
|
2845
2947
|
const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
|
|
2846
2948
|
const startChatService = () => {
|
|
2847
|
-
|
|
2848
|
-
|
|
2949
|
+
const action = decideChatServiceStart({
|
|
2950
|
+
connectInFlight: connectingPromise !== null,
|
|
2951
|
+
clientPresent: chatClient !== null,
|
|
2952
|
+
clientConnected: chatClient?.isConnected ?? false
|
|
2953
|
+
});
|
|
2954
|
+
if (action === "skip") {
|
|
2955
|
+
log.debug("Chat service already connected or connecting — skipping duplicate start");
|
|
2849
2956
|
return;
|
|
2850
2957
|
}
|
|
2958
|
+
if (action === "recycle") {
|
|
2959
|
+
log.info("Chat service client present but not connected — recycling before reconnect");
|
|
2960
|
+
try {
|
|
2961
|
+
chatClient?.stop();
|
|
2962
|
+
} catch (err) {
|
|
2963
|
+
log.debug(`Recycle of stale chat client failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2964
|
+
}
|
|
2965
|
+
chatClient = null;
|
|
2966
|
+
}
|
|
2851
2967
|
globalThis.__alfeChatPluginActivated = true;
|
|
2852
2968
|
log.info("Chat plugin registering...");
|
|
2853
2969
|
resolveOpenClawSdk(log);
|
|
2854
2970
|
pluginRuntime = api.runtime ?? null;
|
|
2855
|
-
|
|
2971
|
+
let thisConnect = null;
|
|
2972
|
+
thisConnect = Promise.resolve().then(() => {
|
|
2856
2973
|
try {
|
|
2857
2974
|
const { apiKey, chatWsUrl } = (0, _alfe_ai_chat.resolveAlfeChat)({
|
|
2858
2975
|
apiKey: pluginConfig.apiKey,
|
|
@@ -2900,7 +3017,10 @@ const plugin = {
|
|
|
2900
3017
|
} catch (err) {
|
|
2901
3018
|
log.error(`Failed to initialize chat service: ${err instanceof Error ? err.message : String(err)}`);
|
|
2902
3019
|
}
|
|
3020
|
+
}).finally(() => {
|
|
3021
|
+
if (connectingPromise === thisConnect) connectingPromise = null;
|
|
2903
3022
|
});
|
|
3023
|
+
connectingPromise = thisConnect;
|
|
2904
3024
|
};
|
|
2905
3025
|
const stopChatService = async () => {
|
|
2906
3026
|
globalThis.__alfeChatPluginActivated = false;
|
|
@@ -2952,7 +3072,8 @@ const plugin = {
|
|
|
2952
3072
|
role: m.role,
|
|
2953
3073
|
content: m.content,
|
|
2954
3074
|
timestamp: m.timestamp,
|
|
2955
|
-
...m.components?.length ? { components: m.components } : {}
|
|
3075
|
+
...m.components?.length ? { components: m.components } : {},
|
|
3076
|
+
...m.attachments?.length ? { attachments: replayAttachments(m.attachments) } : {}
|
|
2956
3077
|
})),
|
|
2957
3078
|
activity: await resolveHistoryActivity(session)
|
|
2958
3079
|
};
|
|
@@ -3079,6 +3200,12 @@ Object.defineProperty(exports, "createAlfeChannelPlugin", {
|
|
|
3079
3200
|
return createAlfeChannelPlugin;
|
|
3080
3201
|
}
|
|
3081
3202
|
});
|
|
3203
|
+
Object.defineProperty(exports, "decideChatServiceStart", {
|
|
3204
|
+
enumerable: true,
|
|
3205
|
+
get: function() {
|
|
3206
|
+
return decideChatServiceStart;
|
|
3207
|
+
}
|
|
3208
|
+
});
|
|
3082
3209
|
Object.defineProperty(exports, "joinAssistantText", {
|
|
3083
3210
|
enumerable: true,
|
|
3084
3211
|
get: function() {
|
package/dist/plugin2.d.cts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { ActiveRunRef, AnchorEnv, CROSS_AGENT_TOOLS_SYSTEM_PROMPT, RunEventGate, VOICE_REPLY_SYSTEM_PROMPT, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildOriginEnvelopeContext, buildToolActivity, computeOpenClawSdkAnchors, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
|
1
|
+
import { _ as resolveAbortTargetKeys, a as VOICE_REPLY_SYSTEM_PROMPT, c as __setActiveRunForTest, d as buildOriginEnvelopeContext, f as buildToolActivity, g as plugin, h as joinAssistantText, i as RunEventGate, l as admitAgentEvent, m as decideChatServiceStart, n as AnchorEnv, o as __agentTurnQueueForTest, p as computeOpenClawSdkAnchors, r as CROSS_AGENT_TOOLS_SYSTEM_PROMPT, s as __resetAgentTurnQueueForTest, t as ActiveRunRef, u as buildA2ACompletePayload, v as rewriteAssistantText, y as stripLeakedToolSummary } from "./plugin.cjs";
|
|
2
|
+
export { ActiveRunRef, AnchorEnv, CROSS_AGENT_TOOLS_SYSTEM_PROMPT, RunEventGate, VOICE_REPLY_SYSTEM_PROMPT, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildOriginEnvelopeContext, buildToolActivity, computeOpenClawSdkAnchors, decideChatServiceStart, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
package/dist/plugin2.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as
|
|
2
|
-
export { ActiveRunRef, AnchorEnv, CROSS_AGENT_TOOLS_SYSTEM_PROMPT, RunEventGate, VOICE_REPLY_SYSTEM_PROMPT, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildOriginEnvelopeContext, buildToolActivity, computeOpenClawSdkAnchors, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
|
1
|
+
import { _ as resolveAbortTargetKeys, a as VOICE_REPLY_SYSTEM_PROMPT, c as __setActiveRunForTest, d as buildOriginEnvelopeContext, f as buildToolActivity, g as plugin, h as joinAssistantText, i as RunEventGate, l as admitAgentEvent, m as decideChatServiceStart, n as AnchorEnv, o as __agentTurnQueueForTest, p as computeOpenClawSdkAnchors, r as CROSS_AGENT_TOOLS_SYSTEM_PROMPT, s as __resetAgentTurnQueueForTest, t as ActiveRunRef, u as buildA2ACompletePayload, v as rewriteAssistantText, y as stripLeakedToolSummary } from "./plugin.js";
|
|
2
|
+
export { ActiveRunRef, AnchorEnv, CROSS_AGENT_TOOLS_SYSTEM_PROMPT, RunEventGate, VOICE_REPLY_SYSTEM_PROMPT, __agentTurnQueueForTest, __resetAgentTurnQueueForTest, __setActiveRunForTest, admitAgentEvent, buildA2ACompletePayload, buildOriginEnvelopeContext, buildToolActivity, computeOpenClawSdkAnchors, decideChatServiceStart, plugin as default, joinAssistantText, resolveAbortTargetKeys, rewriteAssistantText, stripLeakedToolSummary };
|
package/dist/plugin2.js
CHANGED
|
@@ -210,7 +210,8 @@ async function uploadLocalFile(localPath, log, deps) {
|
|
|
210
210
|
url: presigned.downloadUrl,
|
|
211
211
|
filename,
|
|
212
212
|
mimeType,
|
|
213
|
-
size
|
|
213
|
+
size,
|
|
214
|
+
attachmentId: presigned.id
|
|
214
215
|
};
|
|
215
216
|
} catch (err) {
|
|
216
217
|
log.warn(`Outbound media upload failed for ${filename}: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -874,7 +875,7 @@ async function createSession(sessionId, agentId, channel, tenantId, userId) {
|
|
|
874
875
|
return session;
|
|
875
876
|
}
|
|
876
877
|
const writeLocks = /* @__PURE__ */ new Map();
|
|
877
|
-
async function addMessage(sessionId, role, content, senderId, senderName, components) {
|
|
878
|
+
async function addMessage(sessionId, role, content, senderId, senderName, components, attachments) {
|
|
878
879
|
const next = (writeLocks.get(sessionId) ?? Promise.resolve()).then(async () => {
|
|
879
880
|
const session = await getSession(sessionId);
|
|
880
881
|
if (!session) return;
|
|
@@ -884,7 +885,8 @@ async function addMessage(sessionId, role, content, senderId, senderName, compon
|
|
|
884
885
|
timestamp: Date.now(),
|
|
885
886
|
...senderId ? { senderId } : {},
|
|
886
887
|
...senderName ? { senderName } : {},
|
|
887
|
-
...components?.length ? { components } : {}
|
|
888
|
+
...components?.length ? { components } : {},
|
|
889
|
+
...attachments?.length ? { attachments } : {}
|
|
888
890
|
});
|
|
889
891
|
await saveSession(session);
|
|
890
892
|
}).finally(() => {
|
|
@@ -2201,6 +2203,105 @@ function resolveOpenClawSdk(log) {
|
|
|
2201
2203
|
let pluginRuntime = null;
|
|
2202
2204
|
let chatClient = null;
|
|
2203
2205
|
let connectingPromise = null;
|
|
2206
|
+
/**
|
|
2207
|
+
* Decide what `startChatService()` should do given the current connection
|
|
2208
|
+
* state. Pure so the branch logic — the load-bearing fix for the
|
|
2209
|
+
* health-monitor no-op restart loop (Badi Junior, 2026-07-09) — is unit
|
|
2210
|
+
* testable without standing up a real WebSocket or the OpenClaw SDK.
|
|
2211
|
+
*
|
|
2212
|
+
* OpenClaw calls the registered service's `start()` in two very different
|
|
2213
|
+
* situations that a sticky activation flag could not tell apart:
|
|
2214
|
+
* - a redundant duplicate (re-`activate()` per tool-discovery pass / reconnect)
|
|
2215
|
+
* → must be a no-op ('skip'), and
|
|
2216
|
+
* - a channel health-monitor REVIVE of a channel it decided is "stopped"
|
|
2217
|
+
* (`health-monitor: [alfe:default] restarting (reason: stopped)`), sometimes
|
|
2218
|
+
* with no preceding `stop()` → must actually reconnect.
|
|
2219
|
+
*
|
|
2220
|
+
* Keying on the live client fixes it:
|
|
2221
|
+
* - a connect in flight, or an already-connected client → 'skip'
|
|
2222
|
+
* - a client that exists but is not connected → 'recycle' it then reconnect
|
|
2223
|
+
* - no client at all → 'connect'
|
|
2224
|
+
*
|
|
2225
|
+
* Exported for unit tests.
|
|
2226
|
+
*/
|
|
2227
|
+
function decideChatServiceStart(state) {
|
|
2228
|
+
if (state.connectInFlight) return "skip";
|
|
2229
|
+
if (state.clientPresent && state.clientConnected) return "skip";
|
|
2230
|
+
if (state.clientPresent) return "recycle";
|
|
2231
|
+
return "connect";
|
|
2232
|
+
}
|
|
2233
|
+
const STORED_ATTACHMENT_TYPES = new Set([
|
|
2234
|
+
"image",
|
|
2235
|
+
"video",
|
|
2236
|
+
"audio",
|
|
2237
|
+
"document",
|
|
2238
|
+
"file"
|
|
2239
|
+
]);
|
|
2240
|
+
/** Narrow a possibly-loose type string, inferring from the mime as a fallback. */
|
|
2241
|
+
function coerceStoredAttachmentType(type, mimeType) {
|
|
2242
|
+
if (type && STORED_ATTACHMENT_TYPES.has(type)) return type;
|
|
2243
|
+
const m = mimeType ?? "";
|
|
2244
|
+
if (m.startsWith("image/")) return "image";
|
|
2245
|
+
if (m.startsWith("video/")) return "video";
|
|
2246
|
+
if (m.startsWith("audio/")) return "audio";
|
|
2247
|
+
if (m === "application/pdf" || m.includes("document") || m.includes("spreadsheet") || m.includes("presentation")) return "document";
|
|
2248
|
+
return "file";
|
|
2249
|
+
}
|
|
2250
|
+
/**
|
|
2251
|
+
* Map inbound user attachments to the persisted reference shape (drops the
|
|
2252
|
+
* presigned url — it's re-signed on demand). Every composer upload carries a
|
|
2253
|
+
* chat-bucket `id`, so all are persisted.
|
|
2254
|
+
*/
|
|
2255
|
+
function userAttachmentsToStored(refs) {
|
|
2256
|
+
if (!refs?.length) return void 0;
|
|
2257
|
+
const out = [];
|
|
2258
|
+
for (const r of refs) {
|
|
2259
|
+
if (!r.id) continue;
|
|
2260
|
+
out.push({
|
|
2261
|
+
attachmentId: r.id,
|
|
2262
|
+
type: coerceStoredAttachmentType(r.type, r.mimeType),
|
|
2263
|
+
mimeType: r.mimeType,
|
|
2264
|
+
filename: r.filename ?? "file",
|
|
2265
|
+
...typeof r.size === "number" && r.size > 0 ? { size: r.size } : {}
|
|
2266
|
+
});
|
|
2267
|
+
}
|
|
2268
|
+
return out.length ? out : void 0;
|
|
2269
|
+
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Map resolved assistant media to persisted references. Only media uploaded to
|
|
2272
|
+
* our bucket (carrying `attachmentId`) is replayable — remote-passthrough media
|
|
2273
|
+
* has no bindable record and stays live-URL-only.
|
|
2274
|
+
*/
|
|
2275
|
+
function assistantMediaToStored(media) {
|
|
2276
|
+
if (!media?.length) return void 0;
|
|
2277
|
+
const out = [];
|
|
2278
|
+
for (const m of media) {
|
|
2279
|
+
if (!m.attachmentId) continue;
|
|
2280
|
+
out.push({
|
|
2281
|
+
attachmentId: m.attachmentId,
|
|
2282
|
+
type: coerceStoredAttachmentType(void 0, m.mimeType),
|
|
2283
|
+
mimeType: m.mimeType ?? "application/octet-stream",
|
|
2284
|
+
filename: m.filename ?? "file",
|
|
2285
|
+
...typeof m.size === "number" && m.size > 0 ? { size: m.size } : {}
|
|
2286
|
+
});
|
|
2287
|
+
}
|
|
2288
|
+
return out.length ? out : void 0;
|
|
2289
|
+
}
|
|
2290
|
+
/**
|
|
2291
|
+
* Project persisted attachment references onto the `sessions.get` wire shape.
|
|
2292
|
+
* `attachmentId` becomes the wire `id`; the URL is intentionally omitted — the
|
|
2293
|
+
* client resolves a short-lived signed URL on demand.
|
|
2294
|
+
*/
|
|
2295
|
+
function replayAttachments(atts) {
|
|
2296
|
+
if (!atts?.length) return void 0;
|
|
2297
|
+
return atts.map((a) => ({
|
|
2298
|
+
id: a.attachmentId,
|
|
2299
|
+
type: a.type,
|
|
2300
|
+
mimeType: a.mimeType,
|
|
2301
|
+
filename: a.filename,
|
|
2302
|
+
...typeof a.size === "number" ? { size: a.size } : {}
|
|
2303
|
+
}));
|
|
2304
|
+
}
|
|
2204
2305
|
const MAX_FILE_SIZE = 50 * 1024 * 1024;
|
|
2205
2306
|
const DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
2206
2307
|
const MAX_REDIRECTS = 5;
|
|
@@ -2450,7 +2551,7 @@ async function handleAgentRequest(request, log) {
|
|
|
2450
2551
|
const cfg = runtime.config.loadConfig();
|
|
2451
2552
|
const sessionId = conversationId ?? legacySessionKey;
|
|
2452
2553
|
if (!await getSession(sessionId)) await createSession(sessionId, "", "alfe", tenantId, userId);
|
|
2453
|
-
await addMessage(sessionId, "user", message, userId ?? senderId, displayName ?? senderId);
|
|
2554
|
+
await addMessage(sessionId, "user", message, userId ?? senderId, displayName ?? senderId, void 0, userAttachmentsToStored(rawAttachments));
|
|
2454
2555
|
const runGate = {
|
|
2455
2556
|
runId: null,
|
|
2456
2557
|
sessionKey: null
|
|
@@ -2686,7 +2787,7 @@ async function handleAgentRequest(request, log) {
|
|
|
2686
2787
|
const note = formatMediaFailureNote(media.newFailures);
|
|
2687
2788
|
responseText = responseText ? `${responseText}\n\n${note}` : note;
|
|
2688
2789
|
}
|
|
2689
|
-
await addMessage(sessionId, "assistant", responseText);
|
|
2790
|
+
await addMessage(sessionId, "assistant", responseText, void 0, void 0, void 0, assistantMediaToStored(media.attachments));
|
|
2690
2791
|
if (isA2A) a2aResponseBuffer += (a2aResponseBuffer && responseText ? "\n\n" : "") + responseText;
|
|
2691
2792
|
chatClient?.notify("agent-message", {
|
|
2692
2793
|
conversationId: conversationId ?? legacySessionKey,
|
|
@@ -2799,7 +2900,8 @@ async function handleSessionsGet(request, log) {
|
|
|
2799
2900
|
role: m.role,
|
|
2800
2901
|
content: m.content,
|
|
2801
2902
|
timestamp: m.timestamp,
|
|
2802
|
-
...m.components?.length ? { components: m.components } : {}
|
|
2903
|
+
...m.components?.length ? { components: m.components } : {},
|
|
2904
|
+
...m.attachments?.length ? { attachments: replayAttachments(m.attachments) } : {}
|
|
2803
2905
|
})),
|
|
2804
2906
|
activity: await resolveHistoryActivity(session)
|
|
2805
2907
|
});
|
|
@@ -2844,15 +2946,30 @@ const plugin = {
|
|
|
2844
2946
|
}
|
|
2845
2947
|
const pluginConfig = (((api.config ?? {}).plugins?.entries)?.["@alfe.ai/openclaw-chat"] ?? {}).config ?? {};
|
|
2846
2948
|
const startChatService = () => {
|
|
2847
|
-
|
|
2848
|
-
|
|
2949
|
+
const action = decideChatServiceStart({
|
|
2950
|
+
connectInFlight: connectingPromise !== null,
|
|
2951
|
+
clientPresent: chatClient !== null,
|
|
2952
|
+
clientConnected: chatClient?.isConnected ?? false
|
|
2953
|
+
});
|
|
2954
|
+
if (action === "skip") {
|
|
2955
|
+
log.debug("Chat service already connected or connecting — skipping duplicate start");
|
|
2849
2956
|
return;
|
|
2850
2957
|
}
|
|
2958
|
+
if (action === "recycle") {
|
|
2959
|
+
log.info("Chat service client present but not connected — recycling before reconnect");
|
|
2960
|
+
try {
|
|
2961
|
+
chatClient?.stop();
|
|
2962
|
+
} catch (err) {
|
|
2963
|
+
log.debug(`Recycle of stale chat client failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
2964
|
+
}
|
|
2965
|
+
chatClient = null;
|
|
2966
|
+
}
|
|
2851
2967
|
globalThis.__alfeChatPluginActivated = true;
|
|
2852
2968
|
log.info("Chat plugin registering...");
|
|
2853
2969
|
resolveOpenClawSdk(log);
|
|
2854
2970
|
pluginRuntime = api.runtime ?? null;
|
|
2855
|
-
|
|
2971
|
+
let thisConnect = null;
|
|
2972
|
+
thisConnect = Promise.resolve().then(() => {
|
|
2856
2973
|
try {
|
|
2857
2974
|
const { apiKey, chatWsUrl } = resolveAlfeChat({
|
|
2858
2975
|
apiKey: pluginConfig.apiKey,
|
|
@@ -2900,7 +3017,10 @@ const plugin = {
|
|
|
2900
3017
|
} catch (err) {
|
|
2901
3018
|
log.error(`Failed to initialize chat service: ${err instanceof Error ? err.message : String(err)}`);
|
|
2902
3019
|
}
|
|
3020
|
+
}).finally(() => {
|
|
3021
|
+
if (connectingPromise === thisConnect) connectingPromise = null;
|
|
2903
3022
|
});
|
|
3023
|
+
connectingPromise = thisConnect;
|
|
2904
3024
|
};
|
|
2905
3025
|
const stopChatService = async () => {
|
|
2906
3026
|
globalThis.__alfeChatPluginActivated = false;
|
|
@@ -2952,7 +3072,8 @@ const plugin = {
|
|
|
2952
3072
|
role: m.role,
|
|
2953
3073
|
content: m.content,
|
|
2954
3074
|
timestamp: m.timestamp,
|
|
2955
|
-
...m.components?.length ? { components: m.components } : {}
|
|
3075
|
+
...m.components?.length ? { components: m.components } : {},
|
|
3076
|
+
...m.attachments?.length ? { attachments: replayAttachments(m.attachments) } : {}
|
|
2956
3077
|
})),
|
|
2957
3078
|
activity: await resolveHistoryActivity(session)
|
|
2958
3079
|
};
|
|
@@ -3013,4 +3134,4 @@ const plugin = {
|
|
|
3013
3134
|
}
|
|
3014
3135
|
};
|
|
3015
3136
|
//#endregion
|
|
3016
|
-
export { __setActiveRunForTest as a, buildOriginEnvelopeContext as c,
|
|
3137
|
+
export { createAlfeChannelPlugin as _, __setActiveRunForTest as a, buildOriginEnvelopeContext as c, decideChatServiceStart as d, joinAssistantText as f, stripLeakedToolSummary as g, rewriteAssistantText as h, __resetAgentTurnQueueForTest as i, buildToolActivity as l, resolveAbortTargetKeys as m, VOICE_REPLY_SYSTEM_PROMPT as n, admitAgentEvent as o, plugin as p, __agentTurnQueueForTest as r, buildA2ACompletePayload as s, CROSS_AGENT_TOOLS_SYSTEM_PROMPT as t, computeOpenClawSdkAnchors as u };
|