@coclaw/openclaw-coclaw 0.2.4 → 0.3.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/index.js +6 -2
- package/package.json +1 -1
- package/src/realtime-bridge.js +55 -38
package/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import { registerCoclawCli } from './src/cli-registrar.js';
|
|
|
3
3
|
import { resolveErrorMessage } from './src/common/errors.js';
|
|
4
4
|
import { notBound, bindOk, unbindOk } from './src/common/messages.js';
|
|
5
5
|
import { coclawChannelPlugin } from './src/channel-plugin.js';
|
|
6
|
-
import { refreshRealtimeBridge, startRealtimeBridge, stopRealtimeBridge } from './src/realtime-bridge.js';
|
|
6
|
+
import { ensureAgentSession, refreshRealtimeBridge, startRealtimeBridge, stopRealtimeBridge } from './src/realtime-bridge.js';
|
|
7
7
|
import { setRuntime } from './src/runtime.js';
|
|
8
8
|
import { createSessionManager } from './src/session-manager/manager.js';
|
|
9
9
|
import { AutoUpgradeScheduler } from './src/auto-upgrade/updater.js';
|
|
@@ -88,8 +88,12 @@ const plugin = {
|
|
|
88
88
|
}
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
-
api.registerGatewayMethod('nativeui.sessions.listAll', ({ params, respond }) => {
|
|
91
|
+
api.registerGatewayMethod('nativeui.sessions.listAll', async ({ params, respond }) => {
|
|
92
92
|
try {
|
|
93
|
+
const agentId = params?.agentId?.trim?.() || 'main';
|
|
94
|
+
// best-effort ensure:失败不阻断 listAll
|
|
95
|
+
try { await ensureAgentSession(agentId); }
|
|
96
|
+
catch {}
|
|
93
97
|
respond(true, manager.listAll(params ?? {}));
|
|
94
98
|
}
|
|
95
99
|
catch (err) {
|
package/package.json
CHANGED
package/src/realtime-bridge.js
CHANGED
|
@@ -90,8 +90,6 @@ export class RealtimeBridge {
|
|
|
90
90
|
this.gatewayConnectReqId = null;
|
|
91
91
|
this.gatewayRpcSeq = 0;
|
|
92
92
|
this.gatewayPendingRequests = new Map();
|
|
93
|
-
this.mainSessionEnsurePromise = null;
|
|
94
|
-
this.mainSessionEnsured = false;
|
|
95
93
|
this.logger = console;
|
|
96
94
|
this.pluginConfig = {};
|
|
97
95
|
this.intentionallyClosed = false;
|
|
@@ -248,45 +246,58 @@ export class RealtimeBridge {
|
|
|
248
246
|
});
|
|
249
247
|
}
|
|
250
248
|
|
|
251
|
-
|
|
252
|
-
|
|
249
|
+
/**
|
|
250
|
+
* 确保指定 agent 的主 session 存在(sessions.resolve + 条件 sessions.reset)
|
|
251
|
+
* @param {string} [agentId] - agent ID,默认 'main'
|
|
252
|
+
* @returns {Promise<{ok: boolean, state?: string, error?: string}>}
|
|
253
|
+
*/
|
|
254
|
+
async ensureAgentSession(agentId) {
|
|
255
|
+
const aid = typeof agentId === 'string' && agentId.trim() ? agentId.trim() : 'main';
|
|
256
|
+
const key = `agent:${aid}:main`;
|
|
257
|
+
const resolved = await this.__gatewayRpc('sessions.resolve', { key }, { timeoutMs: 2000 });
|
|
258
|
+
if (resolved?.ok === true) {
|
|
259
|
+
this.__logDebug(`ensure agent session: ready agentId=${aid}`);
|
|
253
260
|
return { ok: true, state: 'ready' };
|
|
254
261
|
}
|
|
255
|
-
|
|
256
|
-
if (
|
|
257
|
-
return
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
262
|
+
// 仅当网关真实响应 "不存在" 时才创建;超时/网关未就绪等瞬态错误不触发 reset
|
|
263
|
+
if (!resolved?.response) {
|
|
264
|
+
return { ok: false, error: resolved?.error ?? 'resolve_transient_failure' };
|
|
265
|
+
}
|
|
266
|
+
// session key 不存在,通过 sessions.reset 创建
|
|
267
|
+
const reset = await this.__gatewayRpc('sessions.reset', { key, reason: 'new' }, { timeoutMs: 2500 });
|
|
268
|
+
if (reset?.ok !== true) {
|
|
269
|
+
return { ok: false, error: reset?.error ?? 'sessions_reset_failed' };
|
|
270
|
+
}
|
|
271
|
+
this.__logDebug(`ensure agent session: created agentId=${aid}`);
|
|
272
|
+
return { ok: true, state: 'created' };
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async __ensureAllAgentSessions() {
|
|
276
|
+
try {
|
|
277
|
+
const listResult = await this.__gatewayRpc('agents.list', {}, { timeoutMs: 3000 });
|
|
278
|
+
let agentIds = ['main'];
|
|
279
|
+
if (listResult?.ok === true && Array.isArray(listResult?.response?.payload?.agents)) {
|
|
280
|
+
const ids = listResult.response.payload.agents
|
|
281
|
+
.map((a) => a?.id)
|
|
282
|
+
.filter((id) => typeof id === 'string' && id.trim());
|
|
283
|
+
if (ids.length > 0) agentIds = ids;
|
|
271
284
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
if (reset?.ok !== true) {
|
|
275
|
-
return { ok: false, error: reset?.error ?? 'sessions_reset_failed' };
|
|
285
|
+
else {
|
|
286
|
+
this.logger.warn?.(`[coclaw] agents.list failed, falling back to main: ${listResult?.error ?? 'unknown'}`);
|
|
276
287
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
this.logger.warn?.(`[coclaw] ensure
|
|
288
|
+
const results = await Promise.allSettled(
|
|
289
|
+
agentIds.map((id) => this.ensureAgentSession(id)),
|
|
290
|
+
);
|
|
291
|
+
for (let i = 0; i < results.length; i++) {
|
|
292
|
+
const r = results[i];
|
|
293
|
+
if (r.status === 'fulfilled' && r.value?.ok) continue;
|
|
294
|
+
const err = r.status === 'fulfilled' ? r.value?.error : String(r.reason);
|
|
295
|
+
this.logger.warn?.(`[coclaw] ensure agent session failed: agentId=${agentIds[i]} error=${err ?? 'unknown'}`);
|
|
285
296
|
}
|
|
286
|
-
return result;
|
|
287
297
|
}
|
|
288
|
-
|
|
289
|
-
|
|
298
|
+
/* c8 ignore next 3 -- 防御性兜底,__gatewayRpc 内部已有完整错误处理 */
|
|
299
|
+
catch (err) {
|
|
300
|
+
this.logger.warn?.(`[coclaw] ensureAllAgentSessions unexpected error: ${String(err?.message ?? err)}`);
|
|
290
301
|
}
|
|
291
302
|
}
|
|
292
303
|
|
|
@@ -395,7 +406,7 @@ export class RealtimeBridge {
|
|
|
395
406
|
this.gatewayReady = true;
|
|
396
407
|
this.__logDebug(`gateway connect ok <- id=${payload.id}`);
|
|
397
408
|
this.gatewayConnectReqId = null;
|
|
398
|
-
void this.
|
|
409
|
+
void this.__ensureAllAgentSessions();
|
|
399
410
|
}
|
|
400
411
|
else {
|
|
401
412
|
this.gatewayReady = false;
|
|
@@ -672,8 +683,6 @@ export class RealtimeBridge {
|
|
|
672
683
|
|
|
673
684
|
async stop() {
|
|
674
685
|
this.started = false;
|
|
675
|
-
this.mainSessionEnsured = false;
|
|
676
|
-
this.mainSessionEnsurePromise = null;
|
|
677
686
|
this.__clearServerHeartbeat();
|
|
678
687
|
this.__clearConnectTimer();
|
|
679
688
|
if (this.reconnectTimer) {
|
|
@@ -724,4 +733,12 @@ export async function stopRealtimeBridge() {
|
|
|
724
733
|
return;
|
|
725
734
|
}
|
|
726
735
|
await singleton.stop();
|
|
736
|
+
singleton = null;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
export async function ensureAgentSession(agentId) {
|
|
740
|
+
if (!singleton) {
|
|
741
|
+
return { ok: false, error: 'bridge_not_started' };
|
|
742
|
+
}
|
|
743
|
+
return singleton.ensureAgentSession(agentId);
|
|
727
744
|
}
|