@xcanwin/manyoyo 5.9.2 → 5.9.3
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/lib/web/frontend/app.html +4 -3
- package/lib/web/frontend/app.js +107 -13
- package/lib/web/server.js +51 -5
- package/package.json +1 -1
|
@@ -58,9 +58,10 @@
|
|
|
58
58
|
>更多</button>
|
|
59
59
|
<div class="header-actions" id="headerActions">
|
|
60
60
|
<button type="button" id="refreshBtn" class="secondary">刷新</button>
|
|
61
|
-
<button type="button" id="
|
|
62
|
-
<button type="button" id="removeBtn" class="danger
|
|
63
|
-
<button type="button" id="
|
|
61
|
+
<button type="button" id="openCreateMenuBtn" class="secondary">新建容器</button>
|
|
62
|
+
<button type="button" id="removeBtn" class="danger">删除容器</button>
|
|
63
|
+
<button type="button" id="addAgentBtn" class="secondary">新建 AGENT</button>
|
|
64
|
+
<button type="button" id="removeAllBtn" class="danger">删除 AGENT</button>
|
|
64
65
|
</div>
|
|
65
66
|
</div>
|
|
66
67
|
</div>
|
package/lib/web/frontend/app.js
CHANGED
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
configSaveMessage: '',
|
|
58
58
|
createLoading: false,
|
|
59
59
|
createSubmitting: false,
|
|
60
|
+
creatingAgent: false,
|
|
60
61
|
agentTemplateSaving: false,
|
|
61
62
|
configSnapshot: null,
|
|
62
63
|
sessionDetail: null,
|
|
@@ -131,6 +132,7 @@
|
|
|
131
132
|
const sidebarBackdrop = document.getElementById('sidebarBackdrop');
|
|
132
133
|
const openConfigBtn = document.getElementById('openConfigBtn');
|
|
133
134
|
const openCreateBtn = document.getElementById('openCreateBtn');
|
|
135
|
+
const openCreateMenuBtn = document.getElementById('openCreateMenuBtn');
|
|
134
136
|
const configModal = document.getElementById('configModal');
|
|
135
137
|
const configModalTitle = document.getElementById('configModalTitle');
|
|
136
138
|
const configPath = document.getElementById('configPath');
|
|
@@ -2193,10 +2195,11 @@
|
|
|
2193
2195
|
}
|
|
2194
2196
|
|
|
2195
2197
|
const activeAgentRunning = isAgentRunActiveForSession(state.active) || hasPendingAgentMessagesForSession(state.active);
|
|
2196
|
-
const busy = state.loadingSessions || state.loadingMessages || state.sending;
|
|
2198
|
+
const busy = state.loadingSessions || state.loadingMessages || state.sending || state.creatingAgent;
|
|
2197
2199
|
refreshBtn.disabled = busy;
|
|
2198
2200
|
if (addAgentBtn) {
|
|
2199
2201
|
addAgentBtn.disabled = !state.active || busy;
|
|
2202
|
+
addAgentBtn.textContent = state.creatingAgent ? '新建中...' : '新建 AGENT';
|
|
2200
2203
|
}
|
|
2201
2204
|
removeBtn.disabled = !state.active || busy;
|
|
2202
2205
|
removeAllBtn.disabled = !state.active || busy;
|
|
@@ -2221,6 +2224,9 @@
|
|
|
2221
2224
|
if (openCreateBtn) {
|
|
2222
2225
|
openCreateBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2223
2226
|
}
|
|
2227
|
+
if (openCreateMenuBtn) {
|
|
2228
|
+
openCreateMenuBtn.disabled = state.createLoading || state.createSubmitting;
|
|
2229
|
+
}
|
|
2224
2230
|
if (openConfigBtn) {
|
|
2225
2231
|
openConfigBtn.disabled = state.configLoading || state.configSaving;
|
|
2226
2232
|
}
|
|
@@ -2251,6 +2257,9 @@
|
|
|
2251
2257
|
if (!state.active) {
|
|
2252
2258
|
sendState.textContent = '未选择会话';
|
|
2253
2259
|
sendState.classList.remove('is-active');
|
|
2260
|
+
} else if (state.creatingAgent) {
|
|
2261
|
+
sendState.textContent = '正在新建 AGENT…';
|
|
2262
|
+
sendState.classList.add('is-active');
|
|
2254
2263
|
} else if (activeAgentRunning && agentMode) {
|
|
2255
2264
|
sendState.textContent = state.agentRun.stopping ? '正在停止 Agent…' : 'Agent 执行中';
|
|
2256
2265
|
sendState.classList.add('is-active');
|
|
@@ -2304,6 +2313,8 @@
|
|
|
2304
2313
|
);
|
|
2305
2314
|
if (!state.active) {
|
|
2306
2315
|
sendState.textContent = '未选择会话';
|
|
2316
|
+
} else if (state.creatingAgent) {
|
|
2317
|
+
sendState.textContent = '正在新建 AGENT…';
|
|
2307
2318
|
} else if (agentMode && !agentEnabled) {
|
|
2308
2319
|
sendState.textContent = '当前会话未配置 AGENT 模板';
|
|
2309
2320
|
} else if (state.sending) {
|
|
@@ -2313,7 +2324,7 @@
|
|
|
2313
2324
|
} else {
|
|
2314
2325
|
sendState.textContent = '就绪';
|
|
2315
2326
|
}
|
|
2316
|
-
sendState.classList.toggle('is-active', state.sending);
|
|
2327
|
+
sendState.classList.toggle('is-active', state.sending || state.creatingAgent);
|
|
2317
2328
|
if (composer) {
|
|
2318
2329
|
composer.hidden = !activityTab;
|
|
2319
2330
|
}
|
|
@@ -2699,6 +2710,11 @@
|
|
|
2699
2710
|
if (!targetContainer) {
|
|
2700
2711
|
return;
|
|
2701
2712
|
}
|
|
2713
|
+
if (state.creatingAgent) {
|
|
2714
|
+
return;
|
|
2715
|
+
}
|
|
2716
|
+
state.creatingAgent = true;
|
|
2717
|
+
syncUi();
|
|
2702
2718
|
try {
|
|
2703
2719
|
const data = await api('/api/sessions/' + encodeURIComponent(targetContainer) + '/agents', {
|
|
2704
2720
|
method: 'POST',
|
|
@@ -2712,6 +2728,9 @@
|
|
|
2712
2728
|
}
|
|
2713
2729
|
} catch (e) {
|
|
2714
2730
|
alert(e.message);
|
|
2731
|
+
} finally {
|
|
2732
|
+
state.creatingAgent = false;
|
|
2733
|
+
syncUi();
|
|
2715
2734
|
}
|
|
2716
2735
|
}
|
|
2717
2736
|
|
|
@@ -2755,9 +2774,7 @@
|
|
|
2755
2774
|
});
|
|
2756
2775
|
group.containers.forEach(function (containerGroup) {
|
|
2757
2776
|
containerGroup.sessions.sort(function (a, b) {
|
|
2758
|
-
|
|
2759
|
-
const timeB = b && b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
2760
|
-
return timeB - timeA;
|
|
2777
|
+
return compareSessionByCreatedDesc(a, b);
|
|
2761
2778
|
});
|
|
2762
2779
|
});
|
|
2763
2780
|
return group;
|
|
@@ -2772,6 +2789,72 @@
|
|
|
2772
2789
|
return (parts || []).filter(Boolean).join(' · ');
|
|
2773
2790
|
}
|
|
2774
2791
|
|
|
2792
|
+
function getSessionCreatedTime(session) {
|
|
2793
|
+
if (session && session.createdAt) {
|
|
2794
|
+
const time = new Date(session.createdAt).getTime();
|
|
2795
|
+
if (Number.isFinite(time)) {
|
|
2796
|
+
return time;
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
return 0;
|
|
2800
|
+
}
|
|
2801
|
+
|
|
2802
|
+
function getSessionUpdatedTime(session) {
|
|
2803
|
+
if (session && session.updatedAt) {
|
|
2804
|
+
const time = new Date(session.updatedAt).getTime();
|
|
2805
|
+
if (Number.isFinite(time)) {
|
|
2806
|
+
return time;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
return 0;
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
function getSessionAgentCreationRank(session) {
|
|
2813
|
+
const agentId = session && session.agentId ? String(session.agentId) : '';
|
|
2814
|
+
if (!agentId || agentId === 'default') {
|
|
2815
|
+
return 1;
|
|
2816
|
+
}
|
|
2817
|
+
const matched = agentId.match(/^agent-(\d+)$/);
|
|
2818
|
+
return matched ? (Number(matched[1]) || 0) : 0;
|
|
2819
|
+
}
|
|
2820
|
+
|
|
2821
|
+
function compareSessionByCreatedDesc(a, b) {
|
|
2822
|
+
const createdA = getSessionCreatedTime(a);
|
|
2823
|
+
const createdB = getSessionCreatedTime(b);
|
|
2824
|
+
if (createdA !== createdB) {
|
|
2825
|
+
return createdB - createdA;
|
|
2826
|
+
}
|
|
2827
|
+
if (a && b && a.containerName && a.containerName === b.containerName) {
|
|
2828
|
+
const rankA = getSessionAgentCreationRank(a);
|
|
2829
|
+
const rankB = getSessionAgentCreationRank(b);
|
|
2830
|
+
if (rankA !== rankB) {
|
|
2831
|
+
return rankB - rankA;
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
const updatedA = getSessionUpdatedTime(a);
|
|
2835
|
+
const updatedB = getSessionUpdatedTime(b);
|
|
2836
|
+
if (updatedA !== updatedB) {
|
|
2837
|
+
return updatedB - updatedA;
|
|
2838
|
+
}
|
|
2839
|
+
return String((a && a.name) || '').localeCompare(String((b && b.name) || ''), 'zh-CN');
|
|
2840
|
+
}
|
|
2841
|
+
|
|
2842
|
+
function findLatestCreatedSessionName(sessions, preferredContainerName) {
|
|
2843
|
+
const list = Array.isArray(sessions) ? sessions.filter(Boolean) : [];
|
|
2844
|
+
if (!list.length) {
|
|
2845
|
+
return '';
|
|
2846
|
+
}
|
|
2847
|
+
const targetContainer = String(preferredContainerName || '').trim();
|
|
2848
|
+
const scoped = targetContainer
|
|
2849
|
+
? list.filter(function (session) {
|
|
2850
|
+
return session && session.containerName === targetContainer;
|
|
2851
|
+
})
|
|
2852
|
+
: list;
|
|
2853
|
+
const candidates = scoped.length ? scoped : list;
|
|
2854
|
+
const sorted = candidates.slice().sort(compareSessionByCreatedDesc);
|
|
2855
|
+
return sorted.length && sorted[0] && sorted[0].name ? sorted[0].name : '';
|
|
2856
|
+
}
|
|
2857
|
+
|
|
2775
2858
|
function createDisclosureButton(expanded, label) {
|
|
2776
2859
|
const button = document.createElement('button');
|
|
2777
2860
|
button.type = 'button';
|
|
@@ -2916,7 +2999,7 @@
|
|
|
2916
2999
|
const addAgentBtn = document.createElement('button');
|
|
2917
3000
|
addAgentBtn.type = 'button';
|
|
2918
3001
|
addAgentBtn.className = 'secondary tree-node-menu-item';
|
|
2919
|
-
addAgentBtn.textContent = '新建AGENT';
|
|
3002
|
+
addAgentBtn.textContent = '新建 AGENT';
|
|
2920
3003
|
addAgentBtn.addEventListener('click', function (event) {
|
|
2921
3004
|
event.stopPropagation();
|
|
2922
3005
|
createAgentSession(containerName);
|
|
@@ -3302,7 +3385,7 @@
|
|
|
3302
3385
|
}
|
|
3303
3386
|
}
|
|
3304
3387
|
|
|
3305
|
-
function applySessionsSnapshot(rawSessions, preferredName) {
|
|
3388
|
+
function applySessionsSnapshot(rawSessions, preferredName, preferredContainerName) {
|
|
3306
3389
|
const previousActive = state.active;
|
|
3307
3390
|
state.sessions = Array.isArray(rawSessions) ? rawSessions : [];
|
|
3308
3391
|
pruneSidebarTreeState();
|
|
@@ -3317,7 +3400,7 @@
|
|
|
3317
3400
|
state.sessionDetailError = '';
|
|
3318
3401
|
}
|
|
3319
3402
|
if (!state.active && state.sessions.length) {
|
|
3320
|
-
state.active = state.sessions[0].name;
|
|
3403
|
+
state.active = findLatestCreatedSessionName(state.sessions, preferredContainerName) || state.sessions[0].name;
|
|
3321
3404
|
}
|
|
3322
3405
|
if (state.active && state.active !== previousActive) {
|
|
3323
3406
|
ensureSessionPathExpanded(state.active);
|
|
@@ -3341,7 +3424,7 @@
|
|
|
3341
3424
|
let requestError = null;
|
|
3342
3425
|
try {
|
|
3343
3426
|
const data = await api('/api/sessions');
|
|
3344
|
-
applySessionsSnapshot(data.sessions, opts.preferredName);
|
|
3427
|
+
applySessionsSnapshot(data.sessions, opts.preferredName, opts.preferredContainerName);
|
|
3345
3428
|
} catch (e) {
|
|
3346
3429
|
requestError = e;
|
|
3347
3430
|
} finally {
|
|
@@ -3767,6 +3850,13 @@
|
|
|
3767
3850
|
});
|
|
3768
3851
|
}
|
|
3769
3852
|
|
|
3853
|
+
if (openCreateMenuBtn) {
|
|
3854
|
+
openCreateMenuBtn.addEventListener('click', function () {
|
|
3855
|
+
closeMobileActionsMenu();
|
|
3856
|
+
openCreateModal();
|
|
3857
|
+
});
|
|
3858
|
+
}
|
|
3859
|
+
|
|
3770
3860
|
if (agentTemplateBtn) {
|
|
3771
3861
|
agentTemplateBtn.addEventListener('click', function () {
|
|
3772
3862
|
openAgentTemplateModal().catch(function (e) {
|
|
@@ -4347,14 +4437,18 @@
|
|
|
4347
4437
|
closeMobileActionsMenu();
|
|
4348
4438
|
const activeSession = getActiveSession();
|
|
4349
4439
|
const targetAgent = activeSession && activeSession.agentName ? activeSession.agentName : state.active;
|
|
4350
|
-
const yes = confirm('
|
|
4440
|
+
const yes = confirm('确认删除 AGENT ' + targetAgent + ' ?');
|
|
4351
4441
|
if (!yes) return;
|
|
4352
4442
|
try {
|
|
4353
|
-
const
|
|
4354
|
-
await api('/api/sessions/' + encodeURIComponent(
|
|
4443
|
+
const targetContainerName = activeSession && activeSession.containerName ? activeSession.containerName : '';
|
|
4444
|
+
await api('/api/sessions/' + encodeURIComponent(state.active) + '/remove-with-history', {
|
|
4355
4445
|
method: 'POST'
|
|
4356
4446
|
});
|
|
4357
|
-
await
|
|
4447
|
+
await refreshSessions({
|
|
4448
|
+
preferredContainerName: targetContainerName,
|
|
4449
|
+
withLoading: true,
|
|
4450
|
+
reloadMessages: true
|
|
4451
|
+
});
|
|
4358
4452
|
} catch (e) {
|
|
4359
4453
|
alert(e.message);
|
|
4360
4454
|
}
|
package/lib/web/server.js
CHANGED
|
@@ -165,6 +165,7 @@ function createEmptyWebAgentSession(agentId, agentName) {
|
|
|
165
165
|
agentId,
|
|
166
166
|
agentName: normalizeWebAgentName(agentId, agentName),
|
|
167
167
|
agentPromptCommand: '',
|
|
168
|
+
createdAt: null,
|
|
168
169
|
updatedAt: null,
|
|
169
170
|
messages: [],
|
|
170
171
|
lastResumeAt: null,
|
|
@@ -181,6 +182,7 @@ function normalizeWebAgentSessionRecord(agentId, rawAgent) {
|
|
|
181
182
|
agentPromptCommand: typeof source.agentPromptCommand === 'string'
|
|
182
183
|
? normalizeAgentPromptCommandTemplate(source.agentPromptCommand, `agents.${agentId}.agentPromptCommand`)
|
|
183
184
|
: '',
|
|
185
|
+
createdAt: typeof source.createdAt === 'string' ? source.createdAt : null,
|
|
184
186
|
updatedAt: typeof source.updatedAt === 'string' ? source.updatedAt : null,
|
|
185
187
|
messages: Array.isArray(source.messages) ? source.messages : [],
|
|
186
188
|
lastResumeAt: typeof source.lastResumeAt === 'string' ? source.lastResumeAt : null,
|
|
@@ -384,6 +386,45 @@ function listWebAgentSessions(history, options = {}) {
|
|
|
384
386
|
});
|
|
385
387
|
}
|
|
386
388
|
|
|
389
|
+
function getWebAgentCreationRank(agentId) {
|
|
390
|
+
if (agentId === WEB_DEFAULT_AGENT_ID) {
|
|
391
|
+
return 1;
|
|
392
|
+
}
|
|
393
|
+
const matched = String(agentId || '').match(/^agent-(\d+)$/);
|
|
394
|
+
return matched ? (Number(matched[1]) || 0) : 0;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
function getWebSessionCreatedTime(sessionSummary) {
|
|
398
|
+
if (sessionSummary && sessionSummary.createdAt) {
|
|
399
|
+
const time = new Date(sessionSummary.createdAt).getTime();
|
|
400
|
+
if (Number.isFinite(time)) {
|
|
401
|
+
return time;
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return 0;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function compareWebSessionCreatedDesc(a, b) {
|
|
408
|
+
const timeA = getWebSessionCreatedTime(a);
|
|
409
|
+
const timeB = getWebSessionCreatedTime(b);
|
|
410
|
+
if (timeA !== timeB) {
|
|
411
|
+
return timeB - timeA;
|
|
412
|
+
}
|
|
413
|
+
if (a && b && a.containerName === b.containerName) {
|
|
414
|
+
const rankA = getWebAgentCreationRank(a.agentId);
|
|
415
|
+
const rankB = getWebAgentCreationRank(b.agentId);
|
|
416
|
+
if (rankA !== rankB) {
|
|
417
|
+
return rankB - rankA;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
const updatedA = a && a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
|
|
421
|
+
const updatedB = b && b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
422
|
+
if (updatedA !== updatedB) {
|
|
423
|
+
return updatedB - updatedA;
|
|
424
|
+
}
|
|
425
|
+
return String((a && a.name) || '').localeCompare(String((b && b.name) || ''), 'zh-CN');
|
|
426
|
+
}
|
|
427
|
+
|
|
387
428
|
function createWebSessionMessageId() {
|
|
388
429
|
return `${Date.now()}-${Math.random().toString(16).slice(2, 8)}`;
|
|
389
430
|
}
|
|
@@ -402,6 +443,9 @@ function appendWebSessionMessage(webHistoryDir, sessionRefOrContainerName, role,
|
|
|
402
443
|
timestamp,
|
|
403
444
|
...extra
|
|
404
445
|
};
|
|
446
|
+
if (!agentSession.createdAt) {
|
|
447
|
+
agentSession.createdAt = timestamp;
|
|
448
|
+
}
|
|
405
449
|
agentSession.messages.push(message);
|
|
406
450
|
|
|
407
451
|
if (agentSession.messages.length > WEB_HISTORY_MAX_MESSAGES) {
|
|
@@ -584,7 +628,11 @@ function createWebAgentSession(history) {
|
|
|
584
628
|
}
|
|
585
629
|
const agentId = `agent-${agentIndex}`;
|
|
586
630
|
const agentSession = createEmptyWebAgentSession(agentId, `AGENT ${agentIndex}`);
|
|
631
|
+
const timestamp = new Date().toISOString();
|
|
632
|
+
agentSession.createdAt = timestamp;
|
|
633
|
+
agentSession.updatedAt = timestamp;
|
|
587
634
|
sessionHistory.agents[agentId] = agentSession;
|
|
635
|
+
sessionHistory.updatedAt = timestamp;
|
|
588
636
|
return agentSession;
|
|
589
637
|
}
|
|
590
638
|
|
|
@@ -3041,6 +3089,7 @@ function buildSessionSummary(ctx, state, containerMap, sessionRef) {
|
|
|
3041
3089
|
status: containerInfo.status || 'history',
|
|
3042
3090
|
defaultCommand: containerInfo.defaultCommand || ''
|
|
3043
3091
|
});
|
|
3092
|
+
const createdAt = agentSession.createdAt || containerInfo.createdAt || null;
|
|
3044
3093
|
const updatedAt = agentSession.updatedAt || history.updatedAt || (latestMessage && latestMessage.timestamp) || containerInfo.createdAt || null;
|
|
3045
3094
|
return {
|
|
3046
3095
|
name: buildWebSessionKey(containerName, agentId),
|
|
@@ -3049,6 +3098,7 @@ function buildSessionSummary(ctx, state, containerMap, sessionRef) {
|
|
|
3049
3098
|
agentName: agentSession.agentName,
|
|
3050
3099
|
status: containerInfo.status || 'history',
|
|
3051
3100
|
image: containerInfo.image || '',
|
|
3101
|
+
createdAt,
|
|
3052
3102
|
updatedAt,
|
|
3053
3103
|
messageCount: agentSession.messages.length,
|
|
3054
3104
|
agentEnabled: isAgentPromptCommandEnabled(effectiveAgentPromptCommand),
|
|
@@ -3594,11 +3644,7 @@ async function handleWebApi(req, res, pathname, ctx, state) {
|
|
|
3594
3644
|
}))
|
|
3595
3645
|
.filter(Boolean);
|
|
3596
3646
|
})
|
|
3597
|
-
.sort(
|
|
3598
|
-
const timeA = a.updatedAt ? new Date(a.updatedAt).getTime() : 0;
|
|
3599
|
-
const timeB = b.updatedAt ? new Date(b.updatedAt).getTime() : 0;
|
|
3600
|
-
return timeB - timeA;
|
|
3601
|
-
});
|
|
3647
|
+
.sort(compareWebSessionCreatedDesc);
|
|
3602
3648
|
|
|
3603
3649
|
sendJson(res, 200, { sessions });
|
|
3604
3650
|
}
|