@coclaw/openclaw-coclaw 0.1.2 → 0.1.4
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/package.json +1 -1
- package/src/realtime-bridge.js +15 -16
- package/src/session-manager/manager.js +21 -1
package/package.json
CHANGED
package/src/realtime-bridge.js
CHANGED
|
@@ -152,7 +152,6 @@ async function gatewayRpc(method, params = {}, options = {}) {
|
|
|
152
152
|
});
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
// eslint-disable-next-line no-unused-vars -- 功能暂时禁用,保留函数体供后续修复参考
|
|
156
155
|
async function ensureMainSessionKey() {
|
|
157
156
|
if (mainSessionEnsured) {
|
|
158
157
|
return { ok: true, state: 'ready' };
|
|
@@ -162,25 +161,25 @@ async function ensureMainSessionKey() {
|
|
|
162
161
|
}
|
|
163
162
|
mainSessionEnsurePromise = (async () => {
|
|
164
163
|
const key = 'agent:main:main';
|
|
164
|
+
// sessions.resolve 仅返回 { ok, key },不含 entry
|
|
165
165
|
const resolved = await gatewayRpc('sessions.resolve', { key }, { timeoutMs: 2000 });
|
|
166
|
-
|
|
167
|
-
if (resolved?.ok === true && typeof resolvedSessionId === 'string' && resolvedSessionId.trim()) {
|
|
166
|
+
if (resolved?.ok === true) {
|
|
168
167
|
mainSessionEnsured = true;
|
|
169
|
-
logBridgeDebug(`main session key ensure: ready key=${key}
|
|
170
|
-
return { ok: true, state: 'ready'
|
|
168
|
+
logBridgeDebug(`main session key ensure: ready key=${key}`);
|
|
169
|
+
return { ok: true, state: 'ready' };
|
|
171
170
|
}
|
|
171
|
+
// 仅当网关真实响应 "不存在" 时才创建;超时/网关未就绪等瞬态错误不触发 reset
|
|
172
|
+
if (!resolved?.response) {
|
|
173
|
+
return { ok: false, error: resolved?.error ?? 'resolve_transient_failure' };
|
|
174
|
+
}
|
|
175
|
+
// session key 不存在,通过 sessions.reset 创建
|
|
172
176
|
const reset = await gatewayRpc('sessions.reset', { key, reason: 'new' }, { timeoutMs: 2500 });
|
|
173
177
|
if (reset?.ok !== true) {
|
|
174
178
|
return { ok: false, error: reset?.error ?? 'sessions_reset_failed' };
|
|
175
179
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
mainSessionEnsured = true;
|
|
180
|
-
logBridgeDebug(`main session key ensure: created key=${key} sessionId=${verifySessionId}`);
|
|
181
|
-
return { ok: true, state: 'created', sessionId: verifySessionId };
|
|
182
|
-
}
|
|
183
|
-
return { ok: false, error: verify?.error ?? 'sessions_resolve_after_reset_failed' };
|
|
180
|
+
mainSessionEnsured = true;
|
|
181
|
+
logBridgeDebug(`main session key ensure: created key=${key}`);
|
|
182
|
+
return { ok: true, state: 'created' };
|
|
184
183
|
})();
|
|
185
184
|
try {
|
|
186
185
|
const result = await mainSessionEnsurePromise;
|
|
@@ -259,9 +258,7 @@ function ensureGatewayConnection() {
|
|
|
259
258
|
gatewayReady = true;
|
|
260
259
|
logBridgeDebug(`gateway connect ok <- id=${payload.id}`);
|
|
261
260
|
gatewayConnectReqId = null;
|
|
262
|
-
|
|
263
|
-
// 导致对话被频繁重置。详见 docs/ensure-main-session-bug-analysis.md
|
|
264
|
-
// void ensureMainSessionKey();
|
|
261
|
+
void ensureMainSessionKey();
|
|
265
262
|
}
|
|
266
263
|
else {
|
|
267
264
|
gatewayReady = false;
|
|
@@ -528,6 +525,8 @@ export async function refreshRealtimeBridge() {
|
|
|
528
525
|
|
|
529
526
|
export async function stopRealtimeBridge() {
|
|
530
527
|
started = false;
|
|
528
|
+
mainSessionEnsured = false;
|
|
529
|
+
mainSessionEnsurePromise = null;
|
|
531
530
|
clearConnectTimer();
|
|
532
531
|
if (reconnectTimer) {
|
|
533
532
|
clearTimeout(reconnectTimer);
|
|
@@ -184,10 +184,28 @@ export function createSessionManager(options = {}) {
|
|
|
184
184
|
}
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// 补充 sessions.json 中有索引但无 transcript 文件的 session(如 reset 后未对话、新建 session)
|
|
188
|
+
for (const [sessionKey, entry] of Object.entries(index)) {
|
|
189
|
+
const sid = entry?.sessionId;
|
|
190
|
+
if (!sid || grouped.has(sid)) continue;
|
|
191
|
+
grouped.set(sid, {
|
|
192
|
+
sessionId: sid,
|
|
193
|
+
sessionKey,
|
|
194
|
+
indexed: true,
|
|
195
|
+
archiveType: 'live',
|
|
196
|
+
fileName: null,
|
|
197
|
+
updatedAt: entry.updatedAt ?? 0,
|
|
198
|
+
size: 0,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
187
202
|
const rows = Array.from(grouped.values());
|
|
188
203
|
rows.sort((a, b) => b.updatedAt - a.updatedAt);
|
|
189
204
|
|
|
190
205
|
const items = rows.slice(cursor, cursor + limit).map((row) => {
|
|
206
|
+
if (!row.fileName) {
|
|
207
|
+
return { ...row };
|
|
208
|
+
}
|
|
191
209
|
const transcriptPath = nodePath.join(dir, row.fileName);
|
|
192
210
|
const derivedTitle = deriveTitle(transcriptPath, logger);
|
|
193
211
|
if (!derivedTitle) {
|
|
@@ -246,7 +264,9 @@ export function createSessionManager(options = {}) {
|
|
|
246
264
|
const limit = clamp(params.limit, 1, 500, 100);
|
|
247
265
|
const cursor = clamp(params.cursor, 0, Number.MAX_SAFE_INTEGER, 0);
|
|
248
266
|
const file = resolveTranscriptFile(agentId, sessionId);
|
|
249
|
-
if (!file)
|
|
267
|
+
if (!file) {
|
|
268
|
+
return { agentId, sessionId, total: 0, cursor: String(cursor), nextCursor: null, messages: [] };
|
|
269
|
+
}
|
|
250
270
|
|
|
251
271
|
const all = [];
|
|
252
272
|
for (const line of fs.readFileSync(file, 'utf8').split(/\r?\n/).filter(Boolean)) {
|