@parall/parall 1.32.1 → 1.34.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/gateway.d.ts +9 -0
- package/dist/gateway.d.ts.map +1 -1
- package/dist/gateway.js +35 -2
- package/dist/index.bundle.mjs +206 -26
- package/package.json +3 -3
- package/src/gateway.ts +39 -2
package/dist/gateway.d.ts
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
import type { PluginRuntime } from 'openclaw/plugin-sdk';
|
|
1
2
|
import type { ChannelPlugin } from 'openclaw/plugin-sdk/core';
|
|
2
3
|
/** Extract ChannelGatewayAdapter from ChannelPlugin (removed from public SDK exports in 2026.3.24). */
|
|
3
4
|
type ChannelGatewayAdapter<T = unknown> = NonNullable<ChannelPlugin<T>['gateway']>;
|
|
5
|
+
import { type DispatchAdapter } from '@parall/agent-core';
|
|
4
6
|
import type { ResolvedParallAccount } from './types.js';
|
|
7
|
+
export declare function createOpenClawDispatchAdapter(opts: {
|
|
8
|
+
core: PluginRuntime;
|
|
9
|
+
cfg: Record<string, unknown>;
|
|
10
|
+
accountId: string;
|
|
11
|
+
sessionsDir: string;
|
|
12
|
+
workspaceDir: string;
|
|
13
|
+
}): DispatchAdapter;
|
|
5
14
|
export declare const parallGateway: ChannelGatewayAdapter<ResolvedParallAccount>;
|
|
6
15
|
export {};
|
|
7
16
|
//# sourceMappingURL=gateway.d.ts.map
|
package/dist/gateway.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gateway.d.ts","sourceRoot":"","sources":["../src/gateway.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAE9D,uGAAuG;AACvG,KAAK,qBAAqB,CAAC,CAAC,GAAG,OAAO,IAAI,WAAW,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AACnF,OAAO,EAOL,KAAK,eAAe,EAGrB,MAAM,oBAAoB,CAAC;AAqB5B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAiKxD,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,aAAa,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB,GAAG,eAAe,CA0KlB;AAED,eAAO,MAAM,aAAa,EAAE,qBAAqB,CAAC,qBAAqB,CAmJtE,CAAC"}
|
package/dist/gateway.js
CHANGED
|
@@ -145,8 +145,41 @@ async function waitForOpenClawSessionId(sessionsDir, sessionKey, timeoutMs = 10_
|
|
|
145
145
|
}
|
|
146
146
|
return null;
|
|
147
147
|
}
|
|
148
|
-
function createOpenClawDispatchAdapter(opts) {
|
|
148
|
+
export function createOpenClawDispatchAdapter(opts) {
|
|
149
149
|
const activeStreams = new Map();
|
|
150
|
+
let configFallbackWarned = false;
|
|
151
|
+
/**
|
|
152
|
+
* Resolve the config for one dispatch. OpenClaw hot-reloads
|
|
153
|
+
* `agents.defaults.model` / `models.providers` WITHOUT restarting channel
|
|
154
|
+
* plugins, so the `ctx.cfg` snapshot captured at startAccount goes stale the
|
|
155
|
+
* moment the operator switches the agent's model — every run would keep the
|
|
156
|
+
* old model until the whole gateway restarts. `core.config.current()` is the
|
|
157
|
+
* host's live (hot-reload-refreshed) config; fall back to the startup
|
|
158
|
+
* snapshot on hosts that predate the API. The fallback warns once per
|
|
159
|
+
* degradation streak (latch resets on success) — silently dispatching with
|
|
160
|
+
* the stale snapshot would recreate the invisible model-switch mismatch this
|
|
161
|
+
* function exists to fix.
|
|
162
|
+
*/
|
|
163
|
+
function resolveDispatchConfig(log) {
|
|
164
|
+
try {
|
|
165
|
+
const current = opts.core.config?.current?.();
|
|
166
|
+
if (current && typeof current === 'object') {
|
|
167
|
+
configFallbackWarned = false;
|
|
168
|
+
return current;
|
|
169
|
+
}
|
|
170
|
+
if (!configFallbackWarned) {
|
|
171
|
+
configFallbackWarned = true;
|
|
172
|
+
log?.warn?.(`parall[${opts.accountId}]: config.current() unavailable on this host — dispatching with the startup config snapshot; model switches need a gateway restart until then`);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
if (!configFallbackWarned) {
|
|
177
|
+
configFallbackWarned = true;
|
|
178
|
+
log?.warn?.(`parall[${opts.accountId}]: config.current() failed (${String(err)}) — dispatching with the startup config snapshot; model switches need a gateway restart until then`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return opts.cfg;
|
|
182
|
+
}
|
|
150
183
|
return {
|
|
151
184
|
abortDispatch(sessionKey) {
|
|
152
185
|
activeStreams.get(sessionKey)?.fail(new Error('dispatch deadline exceeded'));
|
|
@@ -172,7 +205,7 @@ function createOpenClawDispatchAdapter(opts) {
|
|
|
172
205
|
let turnGroupKey = '';
|
|
173
206
|
const run = opts.core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
174
207
|
ctx: buildInboundCtx(opts.core, opts.accountId, event, sessionKey, promptBody, earlierEvents),
|
|
175
|
-
cfg:
|
|
208
|
+
cfg: resolveDispatchConfig(context.log),
|
|
176
209
|
dispatcherOptions: {
|
|
177
210
|
deliver: async (payload) => {
|
|
178
211
|
const replyText = payload.text?.trim();
|
package/dist/index.bundle.mjs
CHANGED
|
@@ -27092,6 +27092,7 @@ var ENDPOINTS = {
|
|
|
27092
27092
|
MACHINE_AGENT_DAEMON_CONFIG: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/daemon-config`,
|
|
27093
27093
|
MACHINE_AGENT_WORKSPACE_SETUP: (orgId, machineId, agentId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/agents/${agentId}/workspace/setup`,
|
|
27094
27094
|
MACHINE_LLM_SOURCE: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/llm-source`,
|
|
27095
|
+
MACHINE_PROVIDER_ENABLED: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/provider-enabled`,
|
|
27095
27096
|
MACHINE_RUNTIME_AUTH: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/runtime-auth`,
|
|
27096
27097
|
MACHINE_KEYS: (orgId, machineId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys`,
|
|
27097
27098
|
MACHINE_KEY: (orgId, machineId, keyId) => `${API_BASE}/orgs/${orgId}/machines/${machineId}/keys/${keyId}`,
|
|
@@ -27105,8 +27106,9 @@ var ENDPOINTS = {
|
|
|
27105
27106
|
MACHINES_ME: `${API_BASE}/machines/me`,
|
|
27106
27107
|
MACHINES_ME_AGENTS: `${API_BASE}/machines/me/agents`,
|
|
27107
27108
|
MACHINES_ME_HEALTH: `${API_BASE}/machines/me/health`,
|
|
27108
|
-
|
|
27109
|
-
|
|
27109
|
+
MACHINES_ME_CLIPS: `${API_BASE}/machines/me/clips`,
|
|
27110
|
+
MACHINES_ME_BROWSER_PROFILES: `${API_BASE}/machines/me/browser-profiles`,
|
|
27111
|
+
MACHINES_ME_BROWSER_PROFILE_STATUS: (profileId) => `${API_BASE}/machines/me/browser-profiles/${profileId}/status`,
|
|
27110
27112
|
MACHINES_ME_AGENT_LAUNCH_CREDENTIAL: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/launch-credential`,
|
|
27111
27113
|
MACHINES_ME_AGENT_WORKSPACE_STATE: (agentId) => `${API_BASE}/machines/me/agents/${agentId}/workspace-state`,
|
|
27112
27114
|
MACHINES_ME_WS_TICKET: `${API_BASE}/machines/me/ws/ticket`,
|
|
@@ -27205,6 +27207,7 @@ var ENDPOINTS = {
|
|
|
27205
27207
|
DISPATCH_RECEIVED: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/received`,
|
|
27206
27208
|
DISPATCH_ACK: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/ack`,
|
|
27207
27209
|
DISPATCH_ACK_BY_ID: (orgId, id) => `${API_BASE}/orgs/${orgId}/dispatch/${id}/ack`,
|
|
27210
|
+
DISPATCH_EXPIRE: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/expire`,
|
|
27208
27211
|
DISPATCH_BY_MESSAGES: (orgId) => `${API_BASE}/orgs/${orgId}/dispatch/by-messages`,
|
|
27209
27212
|
// Unread
|
|
27210
27213
|
UNREAD: `${API_BASE}/me/unread`,
|
|
@@ -27223,6 +27226,8 @@ var ENDPOINTS = {
|
|
|
27223
27226
|
PUSH_VAPID_KEY: `${API_BASE}/push/vapid-key`,
|
|
27224
27227
|
// Notification preferences
|
|
27225
27228
|
NOTIFICATION_PREFERENCES: `${API_BASE}/notification-preferences`,
|
|
27229
|
+
// Unified search (messages + tasks + wiki, org-scoped)
|
|
27230
|
+
SEARCH: (orgId) => `${API_BASE}/orgs/${orgId}/search`,
|
|
27226
27231
|
// Feature flags (org-scoped, server-evaluated)
|
|
27227
27232
|
FEATURE_FLAGS: (orgId) => `${API_BASE}/orgs/${orgId}/feature-flags`,
|
|
27228
27233
|
// Billing & Credits (org-scoped)
|
|
@@ -27243,6 +27248,13 @@ var ENDPOINTS = {
|
|
|
27243
27248
|
AGENT_CLIP: (orgId, agentId, clipId) => `${CLIP_BASE}/orgs/${orgId}/agents/${agentId}/clips/${clipId}`,
|
|
27244
27249
|
CLIP_INVOKE: (orgId) => `${CLIP_BASE}/orgs/${orgId}/invoke`,
|
|
27245
27250
|
CLIP_ONLINE: (orgId) => `${CLIP_BASE}/orgs/${orgId}/online`,
|
|
27251
|
+
BROWSER_PROFILES: (orgId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles`,
|
|
27252
|
+
BROWSER_PROFILE: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}`,
|
|
27253
|
+
BROWSER_PROFILE_OPEN: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/open`,
|
|
27254
|
+
BROWSER_PROFILE_STOP: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/stop`,
|
|
27255
|
+
BROWSER_PROFILE_RESET: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/reset`,
|
|
27256
|
+
BROWSER_PROFILE_CONSENTS: (orgId, profileId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/consents`,
|
|
27257
|
+
BROWSER_PROFILE_CONSENT: (orgId, profileId, clipId) => `${CLIP_BASE}/orgs/${orgId}/browser-profiles/${profileId}/consents/${clipId}`,
|
|
27246
27258
|
// Clip registry (global, served by clip-service → Pinix Hub proxy)
|
|
27247
27259
|
CLIP_REGISTRY: () => `${CLIP_BASE}/registry/clips`
|
|
27248
27260
|
};
|
|
@@ -27317,9 +27329,10 @@ var WS_EVENTS = {
|
|
|
27317
27329
|
MACHINE_FILESYSTEM_BROWSE: "machine.filesystem.browse",
|
|
27318
27330
|
MACHINE_UPDATE: "machine.update",
|
|
27319
27331
|
MACHINE_CONFIG_UPDATED: "machine.config.updated",
|
|
27320
|
-
|
|
27332
|
+
MACHINE_CLIP_SYNC: "machine.clip.sync",
|
|
27333
|
+
MACHINE_BROWSER_PROFILE_LIFECYCLE: "machine.browser_profile.lifecycle",
|
|
27321
27334
|
AGENT_NEW_SESSION: "agent.new_session",
|
|
27322
|
-
|
|
27335
|
+
CLIP_CREATED: "clip.created",
|
|
27323
27336
|
CLIP_REMOVED: "clip.removed",
|
|
27324
27337
|
CLIP_UPDATED: "clip.updated"
|
|
27325
27338
|
};
|
|
@@ -27348,8 +27361,13 @@ var ParallClient = class _ParallClient {
|
|
|
27348
27361
|
/** Proactive refresh when token expires within this window (seconds). */
|
|
27349
27362
|
static REFRESH_THRESHOLD_S = 5 * 60;
|
|
27350
27363
|
static normalizeFetchError(err) {
|
|
27351
|
-
if (typeof DOMException !== "undefined" && err instanceof DOMException
|
|
27352
|
-
|
|
27364
|
+
if (typeof DOMException !== "undefined" && err instanceof DOMException) {
|
|
27365
|
+
if (err.name === "TimeoutError") {
|
|
27366
|
+
return new ApiError(0, "Request timed out", "REQUEST_TIMEOUT");
|
|
27367
|
+
}
|
|
27368
|
+
if (err.name === "AbortError") {
|
|
27369
|
+
return new ApiError(0, "Request aborted", "REQUEST_ABORTED");
|
|
27370
|
+
}
|
|
27353
27371
|
}
|
|
27354
27372
|
const apiError = new ApiError(0, "Network request failed", "NETWORK_ERROR");
|
|
27355
27373
|
if (err instanceof Error && err.message && err.message !== "Failed to fetch") {
|
|
@@ -27456,13 +27474,15 @@ var ParallClient = class _ParallClient {
|
|
|
27456
27474
|
url += `?${qs}`;
|
|
27457
27475
|
}
|
|
27458
27476
|
const headers = this.buildHeaders();
|
|
27477
|
+
const timeoutSignal = AbortSignal.timeout(opts?.timeoutMs ?? 15e3);
|
|
27478
|
+
const signal = opts?.signal ? AbortSignal.any([opts.signal, timeoutSignal]) : timeoutSignal;
|
|
27459
27479
|
let res;
|
|
27460
27480
|
try {
|
|
27461
27481
|
res = await fetch(url, {
|
|
27462
27482
|
method,
|
|
27463
27483
|
headers,
|
|
27464
27484
|
body: body ? JSON.stringify(body) : void 0,
|
|
27465
|
-
signal
|
|
27485
|
+
signal
|
|
27466
27486
|
});
|
|
27467
27487
|
} catch (err) {
|
|
27468
27488
|
throw _ParallClient.normalizeFetchError(err);
|
|
@@ -27772,8 +27792,8 @@ var ParallClient = class _ParallClient {
|
|
|
27772
27792
|
const res = await this.request("GET", ENDPOINTS.CHAT_MEMBERS(orgId, chatId));
|
|
27773
27793
|
return res.data;
|
|
27774
27794
|
}
|
|
27775
|
-
async addChatMember(orgId, chatId, userId
|
|
27776
|
-
return this.request("POST", ENDPOINTS.CHAT_MEMBERS(orgId, chatId), { user_id: userId
|
|
27795
|
+
async addChatMember(orgId, chatId, userId) {
|
|
27796
|
+
return this.request("POST", ENDPOINTS.CHAT_MEMBERS(orgId, chatId), { user_id: userId });
|
|
27777
27797
|
}
|
|
27778
27798
|
async removeChatMember(orgId, chatId, userId) {
|
|
27779
27799
|
return this.request("DELETE", ENDPOINTS.CHAT_MEMBER(orgId, chatId, userId));
|
|
@@ -28032,6 +28052,16 @@ var ParallClient = class _ParallClient {
|
|
|
28032
28052
|
llm_source: llmSource
|
|
28033
28053
|
});
|
|
28034
28054
|
}
|
|
28055
|
+
/**
|
|
28056
|
+
* Toggle whether the machine contributes its local clips as a hub provider
|
|
28057
|
+
* — org-admin-gated (RequireOrgAdmin), like all machine management. See
|
|
28058
|
+
* docs/engineering-design/clip-provider-sharing-design.md.
|
|
28059
|
+
*/
|
|
28060
|
+
async patchMachineProviderEnabled(orgId, machineId, providerEnabled) {
|
|
28061
|
+
return this.request("PATCH", ENDPOINTS.MACHINE_PROVIDER_ENABLED(orgId, machineId), {
|
|
28062
|
+
provider_enabled: providerEnabled
|
|
28063
|
+
});
|
|
28064
|
+
}
|
|
28035
28065
|
/** Get machine-level runtime auth state. */
|
|
28036
28066
|
async getMachineRuntimeAuth(orgId, machineId) {
|
|
28037
28067
|
return this.request("GET", ENDPOINTS.MACHINE_RUNTIME_AUTH(orgId, machineId));
|
|
@@ -28065,25 +28095,39 @@ var ParallClient = class _ParallClient {
|
|
|
28065
28095
|
const res = await this.request("GET", ENDPOINTS.MACHINES_ME_AGENTS);
|
|
28066
28096
|
return res.data;
|
|
28067
28097
|
}
|
|
28068
|
-
/** `GET /machines/me/
|
|
28069
|
-
|
|
28070
|
-
|
|
28071
|
-
const res = await this.request("GET", ENDPOINTS.MACHINES_ME_CLIP_INSTALLS);
|
|
28098
|
+
/** `GET /machines/me/clips` — executable Clip definitions assigned to this machine. */
|
|
28099
|
+
async listMachineClips() {
|
|
28100
|
+
const res = await this.request("GET", ENDPOINTS.MACHINES_ME_CLIPS);
|
|
28072
28101
|
return res.data;
|
|
28073
28102
|
}
|
|
28074
|
-
/** `
|
|
28075
|
-
async
|
|
28076
|
-
|
|
28103
|
+
/** `GET /machines/me/browser-profiles` — browser profiles hosted by this machine. */
|
|
28104
|
+
async listMachineBrowserProfiles() {
|
|
28105
|
+
const res = await this.request("GET", ENDPOINTS.MACHINES_ME_BROWSER_PROFILES);
|
|
28106
|
+
return res.data;
|
|
28107
|
+
}
|
|
28108
|
+
/** `POST /machines/me/browser-profiles/{profileId}/status` — report runtime status. */
|
|
28109
|
+
async reportBrowserProfileStatus(profileId, status, errorMsg) {
|
|
28110
|
+
await this.request("POST", ENDPOINTS.MACHINES_ME_BROWSER_PROFILE_STATUS(profileId), {
|
|
28111
|
+
status,
|
|
28112
|
+
...errorMsg ? { error_msg: errorMsg } : {}
|
|
28113
|
+
});
|
|
28077
28114
|
}
|
|
28078
28115
|
/**
|
|
28079
|
-
* `POST /machines/me/health` — bump the Machine's `updated_at` to now
|
|
28080
|
-
*
|
|
28081
|
-
*
|
|
28082
|
-
*
|
|
28116
|
+
* `POST /machines/me/health` — bump the Machine's `updated_at` to now and
|
|
28117
|
+
* report daemon state. The daemon should call this on a fixed cadence (e.g.
|
|
28118
|
+
* every 30s) so an external observer can detect a wedged supervisor. Both
|
|
28119
|
+
* fields are optional and only persisted when changed:
|
|
28120
|
+
* - `daemonVersion` — the running bundle/launcher version.
|
|
28121
|
+
* - `selfUpdateCapable` — whether the daemon can act on a machine.update
|
|
28122
|
+
* signal (true under a service manager, false for bare `npx` foreground).
|
|
28083
28123
|
*/
|
|
28084
|
-
async postMachineHeartbeat(
|
|
28085
|
-
const body =
|
|
28086
|
-
|
|
28124
|
+
async postMachineHeartbeat(opts) {
|
|
28125
|
+
const body = {};
|
|
28126
|
+
if (opts?.daemonVersion)
|
|
28127
|
+
body.daemon_version = opts.daemonVersion;
|
|
28128
|
+
if (opts?.selfUpdateCapable !== void 0)
|
|
28129
|
+
body.self_update_capable = opts.selfUpdateCapable;
|
|
28130
|
+
return this.request("POST", ENDPOINTS.MACHINES_ME_HEALTH, Object.keys(body).length > 0 ? body : void 0);
|
|
28087
28131
|
}
|
|
28088
28132
|
async reportAgentWorkspaceState(agentId, state) {
|
|
28089
28133
|
const res = await this.request("PUT", ENDPOINTS.MACHINES_ME_AGENT_WORKSPACE_STATE(agentId), state);
|
|
@@ -28185,6 +28229,10 @@ var ParallClient = class _ParallClient {
|
|
|
28185
28229
|
async ackDispatchByID(orgId, id) {
|
|
28186
28230
|
return this.request("POST", ENDPOINTS.DISPATCH_ACK_BY_ID(orgId, id));
|
|
28187
28231
|
}
|
|
28232
|
+
async expireDispatch(orgId, maxAgeHours) {
|
|
28233
|
+
const params = maxAgeHours !== void 0 ? { max_age_hours: String(maxAgeHours) } : void 0;
|
|
28234
|
+
return this.request("POST", ENDPOINTS.DISPATCH_EXPIRE(orgId), void 0, params);
|
|
28235
|
+
}
|
|
28188
28236
|
async getDispatchByMessages(orgId, chatId, messageIds) {
|
|
28189
28237
|
const params = { chat_id: chatId, message_ids: messageIds.join(",") };
|
|
28190
28238
|
return this.request("GET", ENDPOINTS.DISPATCH_BY_MESSAGES(orgId), void 0, params);
|
|
@@ -28382,6 +28430,9 @@ var ParallClient = class _ParallClient {
|
|
|
28382
28430
|
async getWikiNodeSections(orgId, wikiId, params) {
|
|
28383
28431
|
return this.request("GET", ENDPOINTS.WIKI_NODE_SECTIONS(orgId, wikiId), void 0, params);
|
|
28384
28432
|
}
|
|
28433
|
+
async search(orgId, params, opts) {
|
|
28434
|
+
return this.request("GET", ENDPOINTS.SEARCH(orgId), void 0, params, false, opts);
|
|
28435
|
+
}
|
|
28385
28436
|
async searchWiki(orgId, wikiId, params) {
|
|
28386
28437
|
return this.request("GET", ENDPOINTS.WIKI_SEARCH(orgId, wikiId), void 0, params);
|
|
28387
28438
|
}
|
|
@@ -28665,6 +28716,41 @@ var ParallClient = class _ParallClient {
|
|
|
28665
28716
|
const resp = await this.request("GET", ENDPOINTS.CLIP_ONLINE(orgId));
|
|
28666
28717
|
return resp.data;
|
|
28667
28718
|
}
|
|
28719
|
+
async listBrowserProfiles(orgId) {
|
|
28720
|
+
const resp = await this.request("GET", ENDPOINTS.BROWSER_PROFILES(orgId));
|
|
28721
|
+
return resp.data;
|
|
28722
|
+
}
|
|
28723
|
+
async createBrowserProfile(orgId, req) {
|
|
28724
|
+
return this.request("POST", ENDPOINTS.BROWSER_PROFILES(orgId), req);
|
|
28725
|
+
}
|
|
28726
|
+
async getBrowserProfile(orgId, profileId) {
|
|
28727
|
+
return this.request("GET", ENDPOINTS.BROWSER_PROFILE(orgId, profileId));
|
|
28728
|
+
}
|
|
28729
|
+
async updateBrowserProfile(orgId, profileId, req) {
|
|
28730
|
+
return this.request("PATCH", ENDPOINTS.BROWSER_PROFILE(orgId, profileId), req);
|
|
28731
|
+
}
|
|
28732
|
+
async deleteBrowserProfile(orgId, profileId) {
|
|
28733
|
+
await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE(orgId, profileId));
|
|
28734
|
+
}
|
|
28735
|
+
async openBrowserProfile(orgId, profileId, req = {}) {
|
|
28736
|
+
return this.request("POST", ENDPOINTS.BROWSER_PROFILE_OPEN(orgId, profileId), req);
|
|
28737
|
+
}
|
|
28738
|
+
async stopBrowserProfile(orgId, profileId) {
|
|
28739
|
+
return this.request("POST", ENDPOINTS.BROWSER_PROFILE_STOP(orgId, profileId), {});
|
|
28740
|
+
}
|
|
28741
|
+
async resetBrowserProfile(orgId, profileId) {
|
|
28742
|
+
return this.request("POST", ENDPOINTS.BROWSER_PROFILE_RESET(orgId, profileId));
|
|
28743
|
+
}
|
|
28744
|
+
async listBrowserProfileConsents(orgId, profileId) {
|
|
28745
|
+
const resp = await this.request("GET", ENDPOINTS.BROWSER_PROFILE_CONSENTS(orgId, profileId));
|
|
28746
|
+
return resp.data;
|
|
28747
|
+
}
|
|
28748
|
+
async grantBrowserProfileConsent(orgId, profileId, req) {
|
|
28749
|
+
return this.request("POST", ENDPOINTS.BROWSER_PROFILE_CONSENTS(orgId, profileId), req);
|
|
28750
|
+
}
|
|
28751
|
+
async revokeBrowserProfileConsent(orgId, profileId, clipId) {
|
|
28752
|
+
await this.request("DELETE", ENDPOINTS.BROWSER_PROFILE_CONSENT(orgId, profileId, clipId));
|
|
28753
|
+
}
|
|
28668
28754
|
async listRegistryClips(q) {
|
|
28669
28755
|
const url = ENDPOINTS.CLIP_REGISTRY() + (q ? `?q=${encodeURIComponent(q)}` : "");
|
|
28670
28756
|
const resp = await this.request("GET", url);
|
|
@@ -30648,8 +30734,28 @@ var ParallAgentGateway = class {
|
|
|
30648
30734
|
return dispatched;
|
|
30649
30735
|
}
|
|
30650
30736
|
async catchUpFromDispatch() {
|
|
30737
|
+
const OVERFLOW_THRESHOLD = 500;
|
|
30738
|
+
const EXPIRE_AGE_HOURS = 24;
|
|
30739
|
+
const CATCHUP_MAX = 10;
|
|
30740
|
+
let expireSummary = null;
|
|
30741
|
+
let overflowMode = false;
|
|
30742
|
+
try {
|
|
30743
|
+
const { count } = await this.opts.client.getDispatchPendingCount(this.opts.config.org_id);
|
|
30744
|
+
if (count > OVERFLOW_THRESHOLD) {
|
|
30745
|
+
overflowMode = true;
|
|
30746
|
+
const result = await this.opts.client.expireDispatch(this.opts.config.org_id, EXPIRE_AGE_HOURS);
|
|
30747
|
+
if (result.total > 0) {
|
|
30748
|
+
this.opts.log?.warn(`dispatch catch-up overflow: ${count} pending, expired ${result.total} events older than ${EXPIRE_AGE_HOURS}h`);
|
|
30749
|
+
expireSummary = this.buildOfflineSummary(result.groups);
|
|
30750
|
+
}
|
|
30751
|
+
}
|
|
30752
|
+
} catch (err) {
|
|
30753
|
+
this.opts.log?.warn(`dispatch catch-up overflow check failed: ${String(err)}`);
|
|
30754
|
+
}
|
|
30651
30755
|
let cursor;
|
|
30652
30756
|
let processed = 0;
|
|
30757
|
+
let skipped = 0;
|
|
30758
|
+
const skippedByType = /* @__PURE__ */ new Map();
|
|
30653
30759
|
do {
|
|
30654
30760
|
const page = await this.opts.client.getDispatch(this.opts.config.org_id, {
|
|
30655
30761
|
limit: 50,
|
|
@@ -30658,6 +30764,17 @@ var ParallAgentGateway = class {
|
|
|
30658
30764
|
for (const item of page.data ?? []) {
|
|
30659
30765
|
if (this.shuttingDown)
|
|
30660
30766
|
break;
|
|
30767
|
+
if (overflowMode && processed >= CATCHUP_MAX) {
|
|
30768
|
+
try {
|
|
30769
|
+
await this.opts.client.ackDispatchByID(this.opts.config.org_id, item.id);
|
|
30770
|
+
skipped++;
|
|
30771
|
+
const key = item.event_type;
|
|
30772
|
+
skippedByType.set(key, (skippedByType.get(key) ?? 0) + 1);
|
|
30773
|
+
} catch {
|
|
30774
|
+
this.opts.log?.warn(`catch-up skip ack failed for ${item.id}, leaving pending`);
|
|
30775
|
+
}
|
|
30776
|
+
continue;
|
|
30777
|
+
}
|
|
30661
30778
|
processed++;
|
|
30662
30779
|
try {
|
|
30663
30780
|
let dispatched = false;
|
|
@@ -30732,9 +30849,52 @@ var ParallAgentGateway = class {
|
|
|
30732
30849
|
}
|
|
30733
30850
|
cursor = !this.shuttingDown && page.has_more ? page.next_cursor : void 0;
|
|
30734
30851
|
} while (cursor);
|
|
30735
|
-
if (
|
|
30736
|
-
|
|
30852
|
+
if (expireSummary || skipped > 0) {
|
|
30853
|
+
const parts = [];
|
|
30854
|
+
if (expireSummary)
|
|
30855
|
+
parts.push(expireSummary);
|
|
30856
|
+
if (skipped > 0) {
|
|
30857
|
+
const recentLines = [...skippedByType.entries()].map(([type, count]) => `- ${count} recent ${type.replace(".", " ").replace("_", " ")} events`).join("\n");
|
|
30858
|
+
parts.push(expireSummary ? `Additionally, ${skipped} recent events exceeded the catch-up limit and were skipped:
|
|
30859
|
+
${recentLines}` : `[Offline Summary] You were offline. ${skipped} pending events exceeded the catch-up limit and were skipped:
|
|
30860
|
+
${recentLines}
|
|
30861
|
+
|
|
30862
|
+
Use your tools (read messages, check tasks) to review anything still relevant.`);
|
|
30863
|
+
}
|
|
30864
|
+
const fullSummary = parts.join("\n\n");
|
|
30865
|
+
this.pendingRestartNotification = this.pendingRestartNotification ? `${this.pendingRestartNotification}
|
|
30866
|
+
|
|
30867
|
+
${fullSummary}` : fullSummary;
|
|
30868
|
+
}
|
|
30869
|
+
if (processed > 0 || skipped > 0) {
|
|
30870
|
+
this.opts.log?.info(`dispatch catch-up: processed ${processed}, skipped ${skipped}`);
|
|
30871
|
+
}
|
|
30872
|
+
}
|
|
30873
|
+
buildOfflineSummary(groups) {
|
|
30874
|
+
const lines = [
|
|
30875
|
+
"[Offline Summary] You were offline and had a large backlog of pending events. The following old events were skipped:"
|
|
30876
|
+
];
|
|
30877
|
+
for (const g of groups) {
|
|
30878
|
+
const age = this.formatAge(g.oldest);
|
|
30879
|
+
if (g.chat_id && g.event_type === "message") {
|
|
30880
|
+
const name = g.chat_name ?? g.chat_id;
|
|
30881
|
+
lines.push(`- ${g.count} messages in "${name}" (oldest: ${age})`);
|
|
30882
|
+
} else {
|
|
30883
|
+
const label = g.event_type.replace(".", " ").replace("_", " ");
|
|
30884
|
+
lines.push(`- ${g.count} ${label} events (oldest: ${age})`);
|
|
30885
|
+
}
|
|
30737
30886
|
}
|
|
30887
|
+
lines.push("");
|
|
30888
|
+
lines.push("These events were too old to process individually. Use your tools (read messages, check tasks) to review anything still relevant.");
|
|
30889
|
+
return lines.join("\n");
|
|
30890
|
+
}
|
|
30891
|
+
formatAge(iso) {
|
|
30892
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
30893
|
+
const hours = Math.floor(ms / 36e5);
|
|
30894
|
+
if (hours < 24)
|
|
30895
|
+
return `${hours}h ago`;
|
|
30896
|
+
const days = Math.floor(hours / 24);
|
|
30897
|
+
return `${days}d ago`;
|
|
30738
30898
|
}
|
|
30739
30899
|
async handleHello(data) {
|
|
30740
30900
|
const { client, config, log } = this.opts;
|
|
@@ -32259,6 +32419,26 @@ async function waitForOpenClawSessionId(sessionsDir, sessionKey, timeoutMs = 1e4
|
|
|
32259
32419
|
}
|
|
32260
32420
|
function createOpenClawDispatchAdapter(opts) {
|
|
32261
32421
|
const activeStreams = /* @__PURE__ */ new Map();
|
|
32422
|
+
let configFallbackWarned = false;
|
|
32423
|
+
function resolveDispatchConfig(log) {
|
|
32424
|
+
try {
|
|
32425
|
+
const current = opts.core.config?.current?.();
|
|
32426
|
+
if (current && typeof current === "object") {
|
|
32427
|
+
configFallbackWarned = false;
|
|
32428
|
+
return current;
|
|
32429
|
+
}
|
|
32430
|
+
if (!configFallbackWarned) {
|
|
32431
|
+
configFallbackWarned = true;
|
|
32432
|
+
log?.warn?.(`parall[${opts.accountId}]: config.current() unavailable on this host \u2014 dispatching with the startup config snapshot; model switches need a gateway restart until then`);
|
|
32433
|
+
}
|
|
32434
|
+
} catch (err) {
|
|
32435
|
+
if (!configFallbackWarned) {
|
|
32436
|
+
configFallbackWarned = true;
|
|
32437
|
+
log?.warn?.(`parall[${opts.accountId}]: config.current() failed (${String(err)}) \u2014 dispatching with the startup config snapshot; model switches need a gateway restart until then`);
|
|
32438
|
+
}
|
|
32439
|
+
}
|
|
32440
|
+
return opts.cfg;
|
|
32441
|
+
}
|
|
32262
32442
|
return {
|
|
32263
32443
|
abortDispatch(sessionKey) {
|
|
32264
32444
|
activeStreams.get(sessionKey)?.fail(new Error("dispatch deadline exceeded"));
|
|
@@ -32284,7 +32464,7 @@ function createOpenClawDispatchAdapter(opts) {
|
|
|
32284
32464
|
let turnGroupKey = "";
|
|
32285
32465
|
const run = opts.core.channel.reply.dispatchReplyWithBufferedBlockDispatcher({
|
|
32286
32466
|
ctx: buildInboundCtx(opts.core, opts.accountId, event, sessionKey, promptBody, earlierEvents),
|
|
32287
|
-
cfg:
|
|
32467
|
+
cfg: resolveDispatchConfig(context2.log),
|
|
32288
32468
|
dispatcherOptions: {
|
|
32289
32469
|
deliver: async (payload) => {
|
|
32290
32470
|
const replyText = payload.text?.trim();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parall/parall",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.34.0",
|
|
4
4
|
"description": "OpenClaw channel plugin for Parall IM",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
"openclaw.plugin.json"
|
|
17
17
|
],
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@parall/agent-core": "1.
|
|
20
|
-
"@parall/sdk": "1.
|
|
19
|
+
"@parall/agent-core": "1.34.0",
|
|
20
|
+
"@parall/sdk": "1.34.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
23
|
"@types/node": "^22.0.0",
|
package/src/gateway.ts
CHANGED
|
@@ -195,7 +195,7 @@ async function waitForOpenClawSessionId(
|
|
|
195
195
|
return null;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
function createOpenClawDispatchAdapter(opts: {
|
|
198
|
+
export function createOpenClawDispatchAdapter(opts: {
|
|
199
199
|
core: PluginRuntime;
|
|
200
200
|
cfg: Record<string, unknown>;
|
|
201
201
|
accountId: string;
|
|
@@ -203,6 +203,43 @@ function createOpenClawDispatchAdapter(opts: {
|
|
|
203
203
|
workspaceDir: string;
|
|
204
204
|
}): DispatchAdapter {
|
|
205
205
|
const activeStreams = new Map<string, ReturnType<typeof createRuntimeEventStream>>();
|
|
206
|
+
let configFallbackWarned = false;
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* Resolve the config for one dispatch. OpenClaw hot-reloads
|
|
210
|
+
* `agents.defaults.model` / `models.providers` WITHOUT restarting channel
|
|
211
|
+
* plugins, so the `ctx.cfg` snapshot captured at startAccount goes stale the
|
|
212
|
+
* moment the operator switches the agent's model — every run would keep the
|
|
213
|
+
* old model until the whole gateway restarts. `core.config.current()` is the
|
|
214
|
+
* host's live (hot-reload-refreshed) config; fall back to the startup
|
|
215
|
+
* snapshot on hosts that predate the API. The fallback warns once per
|
|
216
|
+
* degradation streak (latch resets on success) — silently dispatching with
|
|
217
|
+
* the stale snapshot would recreate the invisible model-switch mismatch this
|
|
218
|
+
* function exists to fix.
|
|
219
|
+
*/
|
|
220
|
+
function resolveDispatchConfig(log?: { warn?: (msg: string) => void }): Record<string, unknown> {
|
|
221
|
+
try {
|
|
222
|
+
const current = opts.core.config?.current?.();
|
|
223
|
+
if (current && typeof current === 'object') {
|
|
224
|
+
configFallbackWarned = false;
|
|
225
|
+
return current as unknown as Record<string, unknown>;
|
|
226
|
+
}
|
|
227
|
+
if (!configFallbackWarned) {
|
|
228
|
+
configFallbackWarned = true;
|
|
229
|
+
log?.warn?.(
|
|
230
|
+
`parall[${opts.accountId}]: config.current() unavailable on this host — dispatching with the startup config snapshot; model switches need a gateway restart until then`,
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
} catch (err) {
|
|
234
|
+
if (!configFallbackWarned) {
|
|
235
|
+
configFallbackWarned = true;
|
|
236
|
+
log?.warn?.(
|
|
237
|
+
`parall[${opts.accountId}]: config.current() failed (${String(err)}) — dispatching with the startup config snapshot; model switches need a gateway restart until then`,
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return opts.cfg;
|
|
242
|
+
}
|
|
206
243
|
|
|
207
244
|
return {
|
|
208
245
|
abortDispatch(sessionKey: string): void {
|
|
@@ -238,7 +275,7 @@ function createOpenClawDispatchAdapter(opts: {
|
|
|
238
275
|
promptBody,
|
|
239
276
|
earlierEvents,
|
|
240
277
|
),
|
|
241
|
-
cfg:
|
|
278
|
+
cfg: resolveDispatchConfig(context.log),
|
|
242
279
|
dispatcherOptions: {
|
|
243
280
|
deliver: async (payload: { text?: string }) => {
|
|
244
281
|
const replyText = payload.text?.trim();
|