@xopcai/xopc 0.0.167 → 0.0.169
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/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{activity-store-DjEDu38T.js → activity-store-DumQD8EX.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DQULz7qY.js → agent-avatar-dicebear-CNI1HQdV.js} +1 -1
- package/dist/gateway/static/root/assets/{agents-CnzkBgKC.js → agents-DfpeWAnu.js} +2 -2
- package/dist/gateway/static/root/assets/{api-DwVCuPOb.js → api-D7eNcGmE.js} +1 -1
- package/dist/gateway/static/root/assets/{app-management-settings-panel-DOjWALVF.js → app-management-settings-panel-BPbnbnFn.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C31COUIC.js → appearance-settings-WWFCDver.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-lSC486eu.js → apps-page-B27faKqW.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DQPvLqfx.js → archive-plugin-Cu2dsFtI.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DwT1x1rc.js → attachment-load-C9mycbtr.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-ByYBiiMR.js → automation-suggestion-card-DtHqVViI.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-iZTnc1YZ.js → automations-page-BoH5grBX.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-CRXiHoZS.js → binary-plugins-DqrPRyjm.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CHO6ILiz.js → block-editor-B9dc3pqc.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-C-OOPZcJ.js → browser-settings-page-CK2fnxHY.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflow-inputs-3UaarfXS.js → browser-workflow-inputs-70k5yvTc.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-workflows-page-BFaa-N_D.js → browser-workflows-page-DBNuaWwR.js} +1 -1
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-BayH0Uom.js → capabilities-settings-panel-gg9GXU00.js} +6 -6
- package/dist/gateway/static/root/assets/{capability-presets-api-DdCHSzcA.js → capability-presets-api-CvV4M4Oe.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-A1qGVyll.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-BOkLI89e.js → channel-recipient-api-BnLOBd7v.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-settings-C-Spmwr5.js → channels-settings-H4vCzqiD.js} +1 -1
- package/dist/gateway/static/root/assets/channels-status-swr-DtswVkDX.js +1 -0
- package/dist/gateway/static/root/assets/{chunk-KS7C4IRE-uQ0fehio.js → chunk-KS7C4IRE-BMhrPKJC.js} +2 -2
- package/dist/gateway/static/root/assets/{connector-logo-CbcC0T6i.js → connector-logo-CYQPu4Nn.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-DpDmJ3Nx.js → connectors-page-DphVkloc.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-CR7RGQff.js → desktop-pet-Deb8fsr-.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BudmCcPE.js → desktop-pet-settings-DHTY5Ku1.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-BLG2Oe6z.js → directory-picker-path-field-cGL2aEB6.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-BwBGC0SG.js → dreaming-settings-C2XF2wL4.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-Pr65_hLC.js → extension-debug-page-F8AzDx0d.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-BuJDcoKn.js → extension-page-ZrX_Ge87.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-B3802tn5.js → extension-settings-page-VypAD6ok.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-D-NVkfts.js → gateway-config-api-C-UsxEKi.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-DIdsKVXv.js → gateway-settings-ChG26Coy.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-qnEmj-vL.js → gateway-startup-retry-D73V3EVy.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-51j_DxgV.js → goal-create-dialog-B6aBG2KK.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-detail-page-CeqMr5GF.js → goal-detail-page-B_G9oVL1.js} +3 -3
- package/dist/gateway/static/root/assets/{goals-config-api-BkVBh7ct.js → goals-config-api-fv7JLhjy.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-lf3oM4Xa.js → goals-page-BQmg_7aD.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-settings-Cg7MJLvx.js → goals-settings-DlfyneMz.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BV3kJOcX.js → heartbeat-settings-BPyFbSbh.js} +1 -1
- package/dist/gateway/static/root/assets/image-generation-api-CSKX7PsM.js +1 -0
- package/dist/gateway/static/root/assets/index-DJtuKve9.js +199 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B9K5rTZZ.js → keyboard-shortcuts-settings-BUxrnWH_.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-ehzr9CBG.js → local-app-workbench-page-Dzlj4fH8.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-BBx6mfAD.js → local-apps-page-BsZMeDnS.js} +1 -1
- package/dist/gateway/static/root/assets/{locale-store-tnRLWdx2.js → locale-store-DXq-Y8Bi.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-xuwEkusZ.js → logs-page-Bg1B-cKU.js} +1 -1
- package/dist/gateway/static/root/assets/{markdown-split-DRDddIt8.js → markdown-split-Cmaw70yM.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Dn3hxhOV.js → media-plugins-Blqj_oJD.js} +1 -1
- package/dist/gateway/static/root/assets/{messages-B1EG4gdu.js → messages-Cj_n7gUv.js} +2 -2
- package/dist/gateway/static/root/assets/notes-page-B6Fdlf_s.js +1 -0
- package/dist/gateway/static/root/assets/{notes-workbench-DXGXn5XF.js → notes-workbench-4HYPR6Hb.js} +2 -2
- package/dist/gateway/static/root/assets/{page-tabs-P2BEd1D8.js → page-tabs-D6zFoyJY.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DrkjmW0F.js → preview-open-alternatives-BLoo7Ad8.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CGzMEowb.js → product-open-page-0-tt2dp7.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-IiE2ddWb.js → project-detail-page-CGa68F1d.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-DGOVhaYI.js → projects-page-BXmIeErj.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-l_y_Shgl.js → remote-access-hub-bxrIHaRt.js} +1 -1
- package/dist/gateway/static/root/assets/{save-bar-controls-BkGrufxl.js → save-bar-controls-9ujl7LRy.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-A8tDpL-9.js → schedule-field-e80Mj-0z.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-N6_hDWgx.js → schema-form-DYZQD-PL.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-CAX4ipPv.js → sessions-page-D_7ms_LG.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-VLuu9WHc.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Bb6yYt5f.js → settings-form-section-Clt3p-mk.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-Q_Vh6HEl.js → settings-loading-skeleton-CTuS66nC.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-CjOtQpbR.js → settings-page-CMP_owwc.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-CtESNNdx.js → settings-page-layout-BWUV_wx6.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-CGxHXgJB.js → setup-status-panel-CAClgrxi.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-C65IsFmd.js → share-preview-page-tISZJtRK.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-Ct3fcbHr.js → shares-settings-t-hP0QDv.js} +1 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CYRaxTqs.js +1 -0
- package/dist/gateway/static/root/assets/{skills-page-FeieOEn3.js → skills-page-C6CXLWnN.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-CdUl2I0D.js → system-settings-panel-6u0k0wJi.js} +1 -1
- package/dist/gateway/static/root/assets/{theme-store-H9T49Iar.js → theme-store-DSpAOJ9G.js} +1 -1
- package/dist/gateway/static/root/assets/{time-picker-EkhqT3fS.js → time-picker-BF3f8el1.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-5xRRUE9Y.js → typed-models-lib-CyRCjjGS.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-UACJTyH0.js → use-channel-catalog-B_Igd7ec.js} +1 -1
- package/dist/gateway/static/root/assets/{user-context-page-DHiRvd4i.js → user-context-page-B3zeQLeM.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-Bql0SPCp.js → voice-api-key-field-BanJk_cf.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-page-BcmZux7y.js → work-discovery-page-BCANmOUS.js} +1 -1
- package/dist/gateway/static/root/assets/{work-item-detail-page-D94Q5zVD.js → work-item-detail-page-t5xiIEFv.js} +1 -1
- package/dist/gateway/static/root/assets/{work-page-DdFBMDcB.js → work-page-CEI3zs-y.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-Dow7ZztR.js → workflow-run-setup-panel-DCXTQx7p.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-wOVSoduy.js → workflows-page-B8FRLCHp.js} +3 -3
- package/dist/gateway/static/root/index.html +7 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +12 -5
- package/dist/src/agent/memory/dreaming/config.js +1 -1
- package/dist/src/agent/models/manager.d.ts +5 -0
- package/dist/src/agent/models/manager.js +8 -0
- package/dist/src/agent/prompt/sections/messaging-runtime.js +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +1 -1
- package/dist/src/agent/tools/communication.js +25 -7
- package/dist/src/agent-runtime/index.js +1 -1
- package/dist/src/agent-runtime/runtime-profile.js +1 -1
- package/dist/src/channels/plugin-registry.js +6 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/hono/routes/composer-history.d.ts +3 -0
- package/dist/src/gateway/hono/routes/composer-history.js +28 -0
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/session/client-history.d.ts +2 -0
- package/dist/src/session/client-history.js +2 -0
- package/dist/src/session/patch-metadata.d.ts +2 -0
- package/dist/src/session/patch-metadata.js +2 -0
- package/dist/src/storage/sqlite/composer-input-history-repository.d.ts +12 -0
- package/dist/src/storage/sqlite/composer-input-history-repository.js +42 -0
- package/dist/src/storage/sqlite/index.d.ts +1 -0
- package/dist/src/storage/sqlite/index.js +2 -1
- package/dist/src/storage/sqlite/migrations/059_composer_input_history.sql +8 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +5 -1
- package/dist/src/tui/backends/embedded-backend.js +53 -9
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +3 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +23 -3
- package/dist/src/tui/components/custom-editor.d.ts +1 -0
- package/dist/src/tui/components/custom-editor.js +6 -0
- package/dist/src/tui/tui-backend.d.ts +11 -0
- package/dist/src/tui/tui-empty-session-cleanup.d.ts +11 -0
- package/dist/src/tui/tui-empty-session-cleanup.js +37 -0
- package/dist/src/tui/tui-submit.d.ts +1 -0
- package/dist/src/tui/tui-submit.js +1 -1
- package/dist/src/tui/tui.js +101 -17
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-JlhjAhT7.js +0 -2
- package/dist/gateway/static/root/assets/channels-status-swr-ZrqadU60.js +0 -1
- package/dist/gateway/static/root/assets/index-B24B26og.js +0 -199
- package/dist/gateway/static/root/assets/notes-page-BtKHSb4z.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-eVlH9brU.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-ElA5kabh.js +0 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { openXopcDatabase } from "../../storage/sqlite/connection.js";
|
|
4
|
+
import { appendComposerInputHistory, listComposerInputHistory } from "../../storage/sqlite/composer-input-history-repository.js";
|
|
4
5
|
import { init_agent_session_key, resolveAgentIdFromSessionKey } from "../../routing/agent-session-key.js";
|
|
5
6
|
import { getSessionMetadata } from "../../storage/sqlite/session-repository.js";
|
|
6
7
|
import "../../storage/sqlite/index.js";
|
|
@@ -77,6 +78,12 @@ var EmbeddedBackend = class {
|
|
|
77
78
|
get connectionLabel() {
|
|
78
79
|
return "local embedded";
|
|
79
80
|
}
|
|
81
|
+
async getComposerInputHistory() {
|
|
82
|
+
return listComposerInputHistory();
|
|
83
|
+
}
|
|
84
|
+
async recordComposerInputHistory(text) {
|
|
85
|
+
return appendComposerInputHistory(text).item;
|
|
86
|
+
}
|
|
80
87
|
start() {
|
|
81
88
|
if (this.running) return;
|
|
82
89
|
this.running = true;
|
|
@@ -122,6 +129,7 @@ var EmbeddedBackend = class {
|
|
|
122
129
|
}
|
|
123
130
|
}
|
|
124
131
|
async createAgent(config, sessionIndex) {
|
|
132
|
+
await this.refreshXopcCloudModels();
|
|
125
133
|
const { AgentService } = await import("../../agent/service.js");
|
|
126
134
|
const workspace = this.workspace || getWorkspacePath(config);
|
|
127
135
|
const modelId = getAgentDefaultModelRef(config);
|
|
@@ -143,6 +151,20 @@ var EmbeddedBackend = class {
|
|
|
143
151
|
await agent.start();
|
|
144
152
|
return agent;
|
|
145
153
|
}
|
|
154
|
+
async refreshXopcCloudModels() {
|
|
155
|
+
try {
|
|
156
|
+
const { XopcCloudModelSource } = await import("../../providers/xopc-cloud-model-source.js");
|
|
157
|
+
const result = await new XopcCloudModelSource().refresh();
|
|
158
|
+
if (result.status === "updated") log.info({ modelCount: result.modelCount }, `XOPC Cloud model catalog refreshed: ${result.modelCount} models`);
|
|
159
|
+
} catch (err) {
|
|
160
|
+
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
161
|
+
log.warn({
|
|
162
|
+
err,
|
|
163
|
+
errorMessage,
|
|
164
|
+
phase: "model_catalog_refresh"
|
|
165
|
+
}, `XOPC Cloud model catalog refresh failed: ${errorMessage}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
146
168
|
stop() {
|
|
147
169
|
this.running = false;
|
|
148
170
|
this.chatAbort?.abort();
|
|
@@ -419,9 +441,10 @@ var EmbeddedBackend = class {
|
|
|
419
441
|
}
|
|
420
442
|
}
|
|
421
443
|
async getSessionStats(sessionKey) {
|
|
422
|
-
|
|
444
|
+
const store = this.agent?.sessionStore ?? this.sessionIndex?.getStore();
|
|
445
|
+
if (!store) return computeTuiSessionStats([]);
|
|
423
446
|
try {
|
|
424
|
-
return computeTuiSessionStats(await
|
|
447
|
+
return computeTuiSessionStats(await store.loadTranscriptRows(sessionKey));
|
|
425
448
|
} catch (error) {
|
|
426
449
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
427
450
|
log.warn({
|
|
@@ -485,9 +508,10 @@ var EmbeddedBackend = class {
|
|
|
485
508
|
}
|
|
486
509
|
}
|
|
487
510
|
async deleteSession(sessionKey) {
|
|
488
|
-
|
|
511
|
+
const store = this.agent?.sessionStore ?? this.sessionIndex?.getStore();
|
|
512
|
+
if (!store) return { ok: false };
|
|
489
513
|
try {
|
|
490
|
-
return { ok: await
|
|
514
|
+
return { ok: await store.deleteSession(sessionKey) };
|
|
491
515
|
} catch (error) {
|
|
492
516
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
493
517
|
log.warn({
|
|
@@ -535,6 +559,9 @@ var EmbeddedBackend = class {
|
|
|
535
559
|
contextWindow: model.contextWindow
|
|
536
560
|
}));
|
|
537
561
|
}
|
|
562
|
+
async refreshModels() {
|
|
563
|
+
await this.refreshXopcCloudModels();
|
|
564
|
+
}
|
|
538
565
|
async resetSession(sessionKey) {
|
|
539
566
|
if (!this.agent) return;
|
|
540
567
|
await this.agent.resetSession(sessionKey);
|
|
@@ -542,11 +569,6 @@ var EmbeddedBackend = class {
|
|
|
542
569
|
async patchSession(sessionKey, patch) {
|
|
543
570
|
const agent = await this.ensureAgent();
|
|
544
571
|
const projectId = typeof patch.projectId === "string" ? patch.projectId.trim() : "";
|
|
545
|
-
if (projectId) {
|
|
546
|
-
await this.sessionIndexReady;
|
|
547
|
-
await this.sessionIndex?.getStore().resolveTranscriptPath(sessionKey);
|
|
548
|
-
new ProjectService().attachSession(sessionKey, projectId);
|
|
549
|
-
}
|
|
550
572
|
const result = await agent.sessionConfig.patch(sessionKey, {
|
|
551
573
|
model: typeof patch.model === "string" ? patch.model : void 0,
|
|
552
574
|
thinkingLevel: typeof patch.thinkingLevel === "string" ? patch.thinkingLevel : void 0,
|
|
@@ -555,6 +577,28 @@ var EmbeddedBackend = class {
|
|
|
555
577
|
workingDirectory: typeof patch.workingDirectory === "string" ? patch.workingDirectory : void 0
|
|
556
578
|
});
|
|
557
579
|
if (!result.ok) throw new Error(result.error);
|
|
580
|
+
if (projectId) {
|
|
581
|
+
await this.sessionIndexReady;
|
|
582
|
+
await this.sessionIndex?.getStore().resolveTranscriptPath(sessionKey);
|
|
583
|
+
new ProjectService().attachSession(sessionKey, projectId);
|
|
584
|
+
}
|
|
585
|
+
const hiddenFromSessionList = typeof patch.hiddenFromSessionList === "boolean" ? patch.hiddenFromSessionList : void 0;
|
|
586
|
+
const customData = patch.customData && typeof patch.customData === "object" && !Array.isArray(patch.customData) ? patch.customData : void 0;
|
|
587
|
+
if (hiddenFromSessionList !== void 0 || customData !== void 0) {
|
|
588
|
+
await this.sessionIndexReady;
|
|
589
|
+
const store = this.sessionIndex?.getStore();
|
|
590
|
+
if (store) {
|
|
591
|
+
await store.resolveTranscriptPath(sessionKey);
|
|
592
|
+
const existing = getSessionMetadata(sessionKey);
|
|
593
|
+
if (existing && existing.messageCount === 0) await store.updateMetadata(sessionKey, {
|
|
594
|
+
...hiddenFromSessionList !== void 0 ? { hiddenFromSessionList } : {},
|
|
595
|
+
...customData ? { customData: {
|
|
596
|
+
...existing.customData ?? {},
|
|
597
|
+
...customData
|
|
598
|
+
} } : {}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
}
|
|
558
602
|
}
|
|
559
603
|
async compactSession(sessionKey, options) {
|
|
560
604
|
if (!this.agent) return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { ExportFormat } from '../../session/types.js';
|
|
2
2
|
import type { SessionTimelineItem } from '../../session/transcript-outline.js';
|
|
3
|
-
import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
|
|
3
|
+
import type { ChatSendOptions, HistoryMessage, TuiBackend, TuiCompactionResult, TuiComposerHistoryItem, TuiEvent, TuiModelChoice, TuiShareRequest, TuiShareResult, TuiSessionStats, TuiSessionItem, TuiStartupResources, TuiTranscriptTreeEntry, TuiAgentInfo, TuiWorkspaceFileSearchEntry, TuiWorkflowRunStartRequest, TuiWorkflowRunStartResult, TuiStartupProjectResult } from '../tui-backend.js';
|
|
4
4
|
import type { SessionInfo } from '../tui-types.js';
|
|
5
5
|
import type { ReviewContext } from '../../review/review-git.js';
|
|
6
6
|
import { type GatewayCredential } from '../../gateway/credential.js';
|
|
@@ -33,6 +33,8 @@ export declare class GatewaySseBackend implements TuiBackend {
|
|
|
33
33
|
start(): void;
|
|
34
34
|
stop(): void;
|
|
35
35
|
getActiveSignal(): AbortSignal | undefined;
|
|
36
|
+
getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
|
|
37
|
+
recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
|
|
36
38
|
sendChat(opts: ChatSendOptions): Promise<{
|
|
37
39
|
runId: string;
|
|
38
40
|
}>;
|
|
@@ -80,6 +80,19 @@ var GatewaySseBackend = class {
|
|
|
80
80
|
const signal = this.chatAbort?.signal;
|
|
81
81
|
return signal && !signal.aborted ? signal : void 0;
|
|
82
82
|
}
|
|
83
|
+
async getComposerInputHistory() {
|
|
84
|
+
const res = await gatewayFetch(this.baseUrl, "/api/composer-history", this.credential);
|
|
85
|
+
if (!res.ok) throw new Error(`Failed to load composer history (${res.status})`);
|
|
86
|
+
return (await res.json()).items ?? [];
|
|
87
|
+
}
|
|
88
|
+
async recordComposerInputHistory(text) {
|
|
89
|
+
const res = await gatewayFetch(this.baseUrl, "/api/composer-history", this.credential, {
|
|
90
|
+
method: "POST",
|
|
91
|
+
body: JSON.stringify({ text })
|
|
92
|
+
});
|
|
93
|
+
if (!res.ok) throw new Error(`Failed to save composer history (${res.status})`);
|
|
94
|
+
return (await res.json()).item;
|
|
95
|
+
}
|
|
83
96
|
async sendChat(opts) {
|
|
84
97
|
this.chatAbort?.abort();
|
|
85
98
|
this.chatAbort = new AbortController();
|
|
@@ -793,13 +806,20 @@ var GatewaySseBackend = class {
|
|
|
793
806
|
const json = await res.json().catch(() => ({}));
|
|
794
807
|
if (!res.ok || json.ok === false) throw new Error(json.error ?? `Session config patch failed (${res.status})`);
|
|
795
808
|
const projectId = typeof patch.projectId === "string" ? patch.projectId.trim() : "";
|
|
796
|
-
|
|
809
|
+
const hiddenFromSessionList = typeof patch.hiddenFromSessionList === "boolean" ? patch.hiddenFromSessionList : void 0;
|
|
810
|
+
const customData = patch.customData && typeof patch.customData === "object" && !Array.isArray(patch.customData) ? patch.customData : void 0;
|
|
811
|
+
if (projectId || hiddenFromSessionList !== void 0 || customData !== void 0) {
|
|
812
|
+
const metadataPatch = {
|
|
813
|
+
...projectId ? { projectId } : {},
|
|
814
|
+
...hiddenFromSessionList !== void 0 ? { hiddenFromSessionList } : {},
|
|
815
|
+
...customData ? { customData } : {}
|
|
816
|
+
};
|
|
797
817
|
const metaRes = await gatewayFetch(this.baseUrl, `/api/sessions/${encodeURIComponent(sessionKey)}`, this.credential, {
|
|
798
818
|
method: "PATCH",
|
|
799
|
-
body: JSON.stringify(
|
|
819
|
+
body: JSON.stringify(metadataPatch)
|
|
800
820
|
});
|
|
801
821
|
const metaJson = await metaRes.json().catch(() => ({}));
|
|
802
|
-
if (!metaRes.ok || metaJson.ok === false) throw new Error(metaJson.error ?? `Session
|
|
822
|
+
if (!metaRes.ok || metaJson.ok === false) throw new Error(metaJson.error ?? `Session metadata patch failed (${metaRes.status})`);
|
|
803
823
|
}
|
|
804
824
|
}
|
|
805
825
|
async renameSession(sessionKey, name) {
|
|
@@ -13,5 +13,6 @@ export declare class CustomEditor extends Editor {
|
|
|
13
13
|
onExtensionShortcut?: (data: string) => boolean;
|
|
14
14
|
constructor(tui: TUI, theme: EditorTheme, keybindings: KeybindingsManager, options?: EditorOptions);
|
|
15
15
|
onAction(action: XopcTuiAppKeybinding, handler: () => void): void;
|
|
16
|
+
replaceHistory(itemsNewestFirst: string[]): void;
|
|
16
17
|
handleInput(data: string): void;
|
|
17
18
|
}
|
|
@@ -18,6 +18,12 @@ var CustomEditor = class extends Editor {
|
|
|
18
18
|
onAction(action, handler) {
|
|
19
19
|
this.actionHandlers.set(action, handler);
|
|
20
20
|
}
|
|
21
|
+
replaceHistory(itemsNewestFirst) {
|
|
22
|
+
const internals = this;
|
|
23
|
+
internals.history = itemsNewestFirst.slice(0, 100);
|
|
24
|
+
internals.historyIndex = -1;
|
|
25
|
+
internals.historyDraft = "";
|
|
26
|
+
}
|
|
21
27
|
handleInput(data) {
|
|
22
28
|
if (this.onExtensionShortcut?.(data)) return;
|
|
23
29
|
if (this.keybindings.matches(data, "app.clipboard.pasteImage")) {
|
|
@@ -25,6 +25,11 @@ export interface TuiEvent {
|
|
|
25
25
|
data: unknown;
|
|
26
26
|
source?: TuiEventSource;
|
|
27
27
|
}
|
|
28
|
+
export interface TuiComposerHistoryItem {
|
|
29
|
+
id: number;
|
|
30
|
+
text: string;
|
|
31
|
+
createdAt: number;
|
|
32
|
+
}
|
|
28
33
|
/** Minimal session list item. */
|
|
29
34
|
export interface TuiSessionItem {
|
|
30
35
|
key: string;
|
|
@@ -180,6 +185,10 @@ export interface TuiBackend {
|
|
|
180
185
|
stop(): void;
|
|
181
186
|
/** Current active chat abort signal, if a run is in progress. */
|
|
182
187
|
getActiveSignal?(): AbortSignal | undefined;
|
|
188
|
+
/** Global composer history, shared across sessions and clients. */
|
|
189
|
+
getComposerInputHistory(): Promise<TuiComposerHistoryItem[]>;
|
|
190
|
+
/** Persist one submitted chat input. */
|
|
191
|
+
recordComposerInputHistory(text: string): Promise<TuiComposerHistoryItem>;
|
|
183
192
|
/** Send a chat message, returns the run id. */
|
|
184
193
|
sendChat(opts: ChatSendOptions): Promise<{
|
|
185
194
|
runId: string;
|
|
@@ -255,6 +264,8 @@ export interface TuiBackend {
|
|
|
255
264
|
getSessionInfo(sessionKey: string): Promise<SessionInfo>;
|
|
256
265
|
/** List available models. */
|
|
257
266
|
listModels(): Promise<TuiModelChoice[]>;
|
|
267
|
+
/** Refresh dynamic model catalogs after credentials change. */
|
|
268
|
+
refreshModels?(): Promise<void>;
|
|
258
269
|
/** Reset / create new session. */
|
|
259
270
|
resetSession(sessionKey: string): Promise<void>;
|
|
260
271
|
/** Rename session display name. */
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { TuiBackend } from './tui-backend.js';
|
|
2
|
+
export declare const GENERATED_TUI_SESSION_SHELL_PATCH: {
|
|
3
|
+
readonly hiddenFromSessionList: true;
|
|
4
|
+
readonly customData: {
|
|
5
|
+
readonly genericNewChatShell: true;
|
|
6
|
+
};
|
|
7
|
+
};
|
|
8
|
+
export declare function isGeneratedTuiSessionKey(sessionKey: string): boolean;
|
|
9
|
+
export declare function deleteGeneratedTuiSessionIfEmpty(client: Pick<TuiBackend, 'getSessionStats' | 'deleteSession'>, sessionKey: string): Promise<boolean>;
|
|
10
|
+
export declare function cleanupAbandonedTuiSessions(client: Pick<TuiBackend, 'listSessions' | 'getSessionStats' | 'deleteSession'>, currentSessionKey: string, nowMs?: number): Promise<string[]>;
|
|
11
|
+
export declare function hideLegacyEmptyTuiSessions(client: Pick<TuiBackend, 'listSessions' | 'patchSession'>): Promise<string[]>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { parseAgentSessionKey } from "../routing/session-key-utils.js";
|
|
2
|
+
import { init_agent_session_key } from "../routing/agent-session-key.js";
|
|
3
|
+
//#region src/tui/tui-empty-session-cleanup.ts
|
|
4
|
+
init_agent_session_key();
|
|
5
|
+
const GENERATED_TUI_SUFFIX_RE = /^tui-[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
6
|
+
const ABANDONED_SESSION_AGE_MS = 60 * 6e4;
|
|
7
|
+
const GENERATED_TUI_SESSION_SHELL_PATCH = {
|
|
8
|
+
hiddenFromSessionList: true,
|
|
9
|
+
customData: { genericNewChatShell: true }
|
|
10
|
+
};
|
|
11
|
+
function isGeneratedTuiSessionKey(sessionKey) {
|
|
12
|
+
const parsed = parseAgentSessionKey(sessionKey);
|
|
13
|
+
return parsed ? GENERATED_TUI_SUFFIX_RE.test(parsed.rest) : false;
|
|
14
|
+
}
|
|
15
|
+
async function deleteGeneratedTuiSessionIfEmpty(client, sessionKey) {
|
|
16
|
+
if (!isGeneratedTuiSessionKey(sessionKey)) return false;
|
|
17
|
+
if ((await client.getSessionStats(sessionKey)).totalMessages > 0) return false;
|
|
18
|
+
return (await client.deleteSession(sessionKey)).ok;
|
|
19
|
+
}
|
|
20
|
+
async function cleanupAbandonedTuiSessions(client, currentSessionKey, nowMs = Date.now()) {
|
|
21
|
+
const candidates = (await client.listSessions()).filter((session) => session.key !== currentSessionKey && session.messageCount === 0 && typeof session.updatedAt === "number" && session.updatedAt <= nowMs - ABANDONED_SESSION_AGE_MS && isGeneratedTuiSessionKey(session.key));
|
|
22
|
+
const deleted = [];
|
|
23
|
+
for (const session of candidates) if (await deleteGeneratedTuiSessionIfEmpty(client, session.key)) deleted.push(session.key);
|
|
24
|
+
return deleted;
|
|
25
|
+
}
|
|
26
|
+
async function hideLegacyEmptyTuiSessions(client) {
|
|
27
|
+
const sessions = await client.listSessions();
|
|
28
|
+
const hidden = [];
|
|
29
|
+
for (const session of sessions) {
|
|
30
|
+
if (session.messageCount !== 0 || !isGeneratedTuiSessionKey(session.key)) continue;
|
|
31
|
+
await client.patchSession(session.key, GENERATED_TUI_SESSION_SHELL_PATCH);
|
|
32
|
+
hidden.push(session.key);
|
|
33
|
+
}
|
|
34
|
+
return hidden;
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { GENERATED_TUI_SESSION_SHELL_PATCH, cleanupAbandonedTuiSessions, deleteGeneratedTuiSessionIfEmpty, hideLegacyEmptyTuiSessions, isGeneratedTuiSessionKey };
|
|
@@ -7,6 +7,7 @@ export declare function createEditorSubmitHandler(params: {
|
|
|
7
7
|
setText: (value: string) => void;
|
|
8
8
|
addToHistory: (value: string) => void;
|
|
9
9
|
};
|
|
10
|
+
recordChatHistory?: (value: string) => void;
|
|
10
11
|
handleCommand: (value: string) => void | Promise<void>;
|
|
11
12
|
sendMessage: (value: string) => void | Promise<void>;
|
|
12
13
|
handleBangLine: (value: string) => void | Promise<void>;
|
|
@@ -36,7 +36,7 @@ function createEditorSubmitHandler(params) {
|
|
|
36
36
|
params.handleBangLine(raw);
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
|
-
params.editor.addToHistory(
|
|
39
|
+
if (rawTrimmed) (params.recordChatHistory ?? params.editor.addToHistory)(rawTrimmed);
|
|
40
40
|
if (value.startsWith("/")) {
|
|
41
41
|
params.handleCommand(value);
|
|
42
42
|
return;
|
package/dist/src/tui/tui.js
CHANGED
|
@@ -27,6 +27,7 @@ import { transcriptTreeEntryIdToRowNumber } from "./tui-transcript-tree.js";
|
|
|
27
27
|
import { formatTuiCompactionResult, formatTuiShareResult } from "./tui-command-formatters.js";
|
|
28
28
|
import { formatTuiStartupText } from "./tui-startup-text.js";
|
|
29
29
|
import { createTuiCommandHandler, getSlashCommands } from "./tui-commands.js";
|
|
30
|
+
import { GENERATED_TUI_SESSION_SHELL_PATCH, cleanupAbandonedTuiSessions, deleteGeneratedTuiSessionIfEmpty, hideLegacyEmptyTuiSessions, isGeneratedTuiSessionKey } from "./tui-empty-session-cleanup.js";
|
|
30
31
|
import { extensionCustomMessageContentToText, extensionCustomMessageToTurnText, extensionUserMessageContentToText } from "./tui-extension-user-message.js";
|
|
31
32
|
import { resolveFdPath } from "./tui-fd-path.js";
|
|
32
33
|
import { drainFollowUpQueue, restoreQueuedMessages } from "./tui-follow-up-queue.js";
|
|
@@ -197,6 +198,9 @@ async function runTui(opts) {
|
|
|
197
198
|
let tuiSettings = loadTuiSettings();
|
|
198
199
|
initTuiTheme({ themeId: opts.theme ?? tuiSettings.theme });
|
|
199
200
|
const state = createInitialState(startup.sessionKey);
|
|
201
|
+
const generatedStartupSessionKey = !opts.session?.trim() && isGeneratedTuiSessionKey(startup.sessionKey) ? startup.sessionKey : null;
|
|
202
|
+
const generatedStartupSessionKeys = new Set(generatedStartupSessionKey ? [generatedStartupSessionKey] : []);
|
|
203
|
+
let startupSessionHadUserTurn = false;
|
|
200
204
|
const startupWorkingDirectory = resolveStartupWorkingDirectory(opts, isLocalMode);
|
|
201
205
|
const implicitTrustedWorkspace = startupWorkingDirectory ?? (isLocalMode ? process.cwd() : void 0);
|
|
202
206
|
const projectTrustStore = new ProjectTrustStore();
|
|
@@ -356,6 +360,7 @@ async function runTui(opts) {
|
|
|
356
360
|
paddingX: tuiSettings.editorPaddingX,
|
|
357
361
|
autocompleteMaxVisible: tuiSettings.autocompleteMaxVisible
|
|
358
362
|
});
|
|
363
|
+
let composerHistoryTexts = [];
|
|
359
364
|
let editor = defaultEditor;
|
|
360
365
|
let editorComponentFactory;
|
|
361
366
|
const editorContainer = new Container();
|
|
@@ -417,6 +422,7 @@ async function runTui(opts) {
|
|
|
417
422
|
nextEditor.setAutocompleteProvider?.(extensionRuntime.autocompleteProvider);
|
|
418
423
|
copyDefaultEditorAppHandlers(nextEditor);
|
|
419
424
|
editor = nextEditor;
|
|
425
|
+
for (const text of composerHistoryTexts.slice().reverse()) editor.addToHistory?.(text);
|
|
420
426
|
} else {
|
|
421
427
|
defaultEditor.setText(currentText);
|
|
422
428
|
editor = defaultEditor;
|
|
@@ -947,14 +953,21 @@ async function runTui(opts) {
|
|
|
947
953
|
clearInterval(streamWatchdogId);
|
|
948
954
|
streamWatchdogId = null;
|
|
949
955
|
}
|
|
950
|
-
client.stop();
|
|
951
956
|
tui.terminal.setProgress(false);
|
|
952
|
-
|
|
957
|
+
(async () => {
|
|
958
|
+
const removedEmptyStartupSessions = /* @__PURE__ */ new Set();
|
|
959
|
+
if (!state.activeRunId) for (const sessionKey of generatedStartupSessionKeys) {
|
|
960
|
+
if (sessionKey === state.currentSessionKey && startupSessionHadUserTurn) continue;
|
|
961
|
+
if (await deleteGeneratedTuiSessionIfEmpty(client, sessionKey).catch(() => false)) removedEmptyStartupSessions.add(sessionKey);
|
|
962
|
+
}
|
|
963
|
+
client.stop();
|
|
964
|
+
await drainAndStopTuiSafely(tui);
|
|
953
965
|
restoreStdio();
|
|
954
|
-
|
|
966
|
+
const currentSessionWasRemoved = removedEmptyStartupSessions.has(state.currentSessionKey);
|
|
967
|
+
if (options?.showResumeHint !== false && !currentSessionWasRemoved) process.stdout.write(`\nTo resume this session: ${formatTuiResumeCommand(opts, state.currentSessionKey)}\n`);
|
|
955
968
|
finishTui?.();
|
|
956
969
|
process.exit(0);
|
|
957
|
-
});
|
|
970
|
+
})();
|
|
958
971
|
};
|
|
959
972
|
const { refreshSessionInfo, loadHistory: loadSessionHistory, loadHistoryWindow, setSession, abortActive, resetCurrentSession, clearChatForSessionSwitch } = createSessionActions({
|
|
960
973
|
client,
|
|
@@ -1001,7 +1014,10 @@ async function runTui(opts) {
|
|
|
1001
1014
|
const applyStartupWorkingDirectory = async () => {
|
|
1002
1015
|
if (startupWorkingDirectoryApplied || !startupWorkingDirectory) return;
|
|
1003
1016
|
startupWorkingDirectoryApplied = true;
|
|
1004
|
-
await client.patchSession(state.currentSessionKey, {
|
|
1017
|
+
await client.patchSession(state.currentSessionKey, {
|
|
1018
|
+
workingDirectory: startupWorkingDirectory,
|
|
1019
|
+
...isGeneratedTuiSessionKey(state.currentSessionKey) ? GENERATED_TUI_SESSION_SHELL_PATCH : {}
|
|
1020
|
+
});
|
|
1005
1021
|
state.sessionInfo.effectiveWorkspacePath = startupWorkingDirectory;
|
|
1006
1022
|
state.sessionInfo.workingDirectoryLocked = true;
|
|
1007
1023
|
};
|
|
@@ -1018,15 +1034,22 @@ async function runTui(opts) {
|
|
|
1018
1034
|
const projectAgentId = result.project.defaultAgentId?.trim() ? normalizeAgentId(result.project.defaultAgentId) : void 0;
|
|
1019
1035
|
const currentParsed = parseAgentSessionKey(state.currentSessionKey);
|
|
1020
1036
|
if (!opts.agentId?.trim() && currentParsed?.rest && projectAgentId && projectAgentId !== currentAgentId) {
|
|
1021
|
-
|
|
1037
|
+
const targetSessionKey = `agent:${projectAgentId}:${currentParsed.rest}`;
|
|
1038
|
+
await setSession(targetSessionKey);
|
|
1039
|
+
if (isGeneratedTuiSessionKey(targetSessionKey)) generatedStartupSessionKeys.add(targetSessionKey);
|
|
1022
1040
|
currentAgentId = projectAgentId;
|
|
1041
|
+
if (isGeneratedTuiSessionKey(state.currentSessionKey)) await client.patchSession(state.currentSessionKey, GENERATED_TUI_SESSION_SHELL_PATCH);
|
|
1023
1042
|
await client.patchSession(state.currentSessionKey, {
|
|
1024
1043
|
projectId: result.project.id,
|
|
1025
|
-
workingDirectory: startupWorkingDirectory
|
|
1044
|
+
workingDirectory: startupWorkingDirectory,
|
|
1045
|
+
...isGeneratedTuiSessionKey(state.currentSessionKey) ? GENERATED_TUI_SESSION_SHELL_PATCH : {}
|
|
1026
1046
|
});
|
|
1027
1047
|
state.sessionInfo.effectiveWorkspacePath = startupWorkingDirectory;
|
|
1028
1048
|
state.sessionInfo.workingDirectoryLocked = true;
|
|
1029
|
-
} else await client.patchSession(state.currentSessionKey, {
|
|
1049
|
+
} else await client.patchSession(state.currentSessionKey, {
|
|
1050
|
+
projectId: result.project.id,
|
|
1051
|
+
...isGeneratedTuiSessionKey(state.currentSessionKey) ? GENERATED_TUI_SESSION_SHELL_PATCH : {}
|
|
1052
|
+
});
|
|
1030
1053
|
const verb = result.created ? "Created project" : "Using project";
|
|
1031
1054
|
chatLog.addStatus(theme.dim(`${verb}: ${result.project.name}`));
|
|
1032
1055
|
};
|
|
@@ -1458,6 +1481,7 @@ async function runTui(opts) {
|
|
|
1458
1481
|
return;
|
|
1459
1482
|
}
|
|
1460
1483
|
chatLog.addUser(userDisplayContentForAttachments(text, attachments));
|
|
1484
|
+
startupSessionHadUserTurn = true;
|
|
1461
1485
|
sessionSnapshot.appendMessage("user", messageText);
|
|
1462
1486
|
lastRetryMessageText = messageText;
|
|
1463
1487
|
markRunSending(state);
|
|
@@ -1682,14 +1706,18 @@ async function runTui(opts) {
|
|
|
1682
1706
|
getEntry: () => projectTrustStore.getEntry(process.cwd()),
|
|
1683
1707
|
getSessionDecision: () => projectTrustSessionDecision
|
|
1684
1708
|
},
|
|
1685
|
-
runLogin: (provider) =>
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1709
|
+
runLogin: async (provider) => {
|
|
1710
|
+
await runTuiOAuthLogin(provider, {
|
|
1711
|
+
chatLog,
|
|
1712
|
+
tui,
|
|
1713
|
+
editor,
|
|
1714
|
+
openOverlay: openCommandOverlay,
|
|
1715
|
+
closeOverlay: closeCommandOverlay,
|
|
1716
|
+
keybindings
|
|
1717
|
+
});
|
|
1718
|
+
await client.refreshModels?.();
|
|
1719
|
+
await refreshModelChoices();
|
|
1720
|
+
}
|
|
1693
1721
|
});
|
|
1694
1722
|
const { runLocalShellLine } = createLocalShellRunner({
|
|
1695
1723
|
chatLog,
|
|
@@ -1736,12 +1764,48 @@ async function runTui(opts) {
|
|
|
1736
1764
|
updateFooter();
|
|
1737
1765
|
tui.requestRender();
|
|
1738
1766
|
};
|
|
1767
|
+
let composerHistory = [];
|
|
1768
|
+
let composerHistoryWriteQueue = Promise.resolve();
|
|
1769
|
+
const applyComposerHistory = (next) => {
|
|
1770
|
+
composerHistory = next.slice(0, 100);
|
|
1771
|
+
composerHistoryTexts = composerHistory.map((item) => item.text);
|
|
1772
|
+
if (editor === defaultEditor) {
|
|
1773
|
+
defaultEditor.replaceHistory(composerHistory.map((item) => item.text));
|
|
1774
|
+
return;
|
|
1775
|
+
}
|
|
1776
|
+
for (const item of composerHistory.slice().reverse()) editor.addToHistory?.(item.text);
|
|
1777
|
+
};
|
|
1778
|
+
const refreshComposerHistory = async () => {
|
|
1779
|
+
try {
|
|
1780
|
+
await composerHistoryWriteQueue;
|
|
1781
|
+
applyComposerHistory(await client.getComposerInputHistory());
|
|
1782
|
+
} catch {}
|
|
1783
|
+
};
|
|
1784
|
+
const recordChatHistory = (value) => {
|
|
1785
|
+
const text = value.trim();
|
|
1786
|
+
if (!text) return;
|
|
1787
|
+
editor.addToHistory?.(text);
|
|
1788
|
+
if (composerHistory[0]?.text !== text) {
|
|
1789
|
+
composerHistory = [{
|
|
1790
|
+
id: 0,
|
|
1791
|
+
text,
|
|
1792
|
+
createdAt: Date.now()
|
|
1793
|
+
}, ...composerHistory].slice(0, 100);
|
|
1794
|
+
composerHistoryTexts = composerHistory.map((item) => item.text);
|
|
1795
|
+
}
|
|
1796
|
+
composerHistoryWriteQueue = composerHistoryWriteQueue.then(async () => {
|
|
1797
|
+
const item = await client.recordComposerInputHistory(text);
|
|
1798
|
+
const optimisticIndex = composerHistory.findIndex((entry) => entry.id === 0 && entry.text === item.text);
|
|
1799
|
+
if (optimisticIndex >= 0) composerHistory[optimisticIndex] = item;
|
|
1800
|
+
}).catch(() => {});
|
|
1801
|
+
};
|
|
1739
1802
|
const submitBurst = createSubmitBurstCoalescer({
|
|
1740
1803
|
submit: createEditorSubmitHandler({
|
|
1741
1804
|
editor: {
|
|
1742
1805
|
setText: (value) => editor.setText(value),
|
|
1743
1806
|
addToHistory: (value) => editor.addToHistory?.(value)
|
|
1744
1807
|
},
|
|
1808
|
+
recordChatHistory: (value) => recordChatHistory(value),
|
|
1745
1809
|
handleCommand,
|
|
1746
1810
|
sendMessage,
|
|
1747
1811
|
handleBangLine: runLocalShellLine,
|
|
@@ -1772,7 +1836,7 @@ async function runTui(opts) {
|
|
|
1772
1836
|
tui.requestRender();
|
|
1773
1837
|
return;
|
|
1774
1838
|
}
|
|
1775
|
-
|
|
1839
|
+
recordChatHistory(text);
|
|
1776
1840
|
state.messageFollowUpQueue.push(text);
|
|
1777
1841
|
editor.setText("");
|
|
1778
1842
|
chatLog.addSystem(theme.dim(`Queued follow-up (${state.messageFollowUpQueue.length} in queue). ${tuiSettings.followUpMode === "all" ? "All queued messages send together when this reply finishes." : "Next sends when this reply finishes."}`));
|
|
@@ -2026,6 +2090,23 @@ async function runTui(opts) {
|
|
|
2026
2090
|
};
|
|
2027
2091
|
client.onEvent = (evt) => {
|
|
2028
2092
|
const data = evt.data ?? {};
|
|
2093
|
+
if (evt.event === "composer-history.appended") {
|
|
2094
|
+
const item = data;
|
|
2095
|
+
if (typeof item.text === "string" && typeof item.id === "number") {
|
|
2096
|
+
const optimisticIndex = composerHistory.findIndex((entry) => entry.id === 0 && entry.text === item.text);
|
|
2097
|
+
if (optimisticIndex >= 0) composerHistory[optimisticIndex] = item;
|
|
2098
|
+
else if (composerHistory[0]?.text !== item.text) {
|
|
2099
|
+
composerHistory = [item, ...composerHistory].slice(0, 100);
|
|
2100
|
+
composerHistoryTexts = composerHistory.map((entry) => entry.text);
|
|
2101
|
+
editor.addToHistory?.(item.text);
|
|
2102
|
+
} else composerHistory[0] = item;
|
|
2103
|
+
}
|
|
2104
|
+
return;
|
|
2105
|
+
}
|
|
2106
|
+
if (evt.event === "composer-history.cleared") {
|
|
2107
|
+
applyComposerHistory([]);
|
|
2108
|
+
return;
|
|
2109
|
+
}
|
|
2029
2110
|
if (evt.event === "workflow.run.updated" && handleWorkflowRunUpdated(data)) return;
|
|
2030
2111
|
dispatchAgentEvent(evt.event, data, state, chatLog, tui, setActivityStatus, touchStreamingActivity, onAgentRunEnded, (message) => sessionSnapshot.appendMessage("assistant", assistantMessagePlainText(message)), evt.source);
|
|
2031
2112
|
};
|
|
@@ -2035,6 +2116,7 @@ async function runTui(opts) {
|
|
|
2035
2116
|
setConnectionStatus(isLocalMode ? "local ready" : "gateway connected");
|
|
2036
2117
|
touchStreamingActivity();
|
|
2037
2118
|
(async () => {
|
|
2119
|
+
await refreshComposerHistory();
|
|
2038
2120
|
if (opts.openSessionPickerOnStart && !startupSessionPickerOpened) {
|
|
2039
2121
|
startupSessionPickerOpened = true;
|
|
2040
2122
|
await openSessionPickerOverlay(pickerSvc, {
|
|
@@ -2064,6 +2146,7 @@ async function runTui(opts) {
|
|
|
2064
2146
|
await refreshSessionInfoWithBorder();
|
|
2065
2147
|
await refreshModelChoices();
|
|
2066
2148
|
await loadSessionHistory({ merge: true });
|
|
2149
|
+
cleanupAbandonedTuiSessions(client, state.currentSessionKey).then(() => hideLegacyEmptyTuiSessions(client)).catch(() => {});
|
|
2067
2150
|
showStartupCardOnce();
|
|
2068
2151
|
refreshStartupResources().then(() => {
|
|
2069
2152
|
updateFooter();
|
|
@@ -2098,6 +2181,7 @@ async function runTui(opts) {
|
|
|
2098
2181
|
setConnectionStatus(`event gap: expected ${info.expected}, got ${info.received}`);
|
|
2099
2182
|
if (state.activeRunId) recoverActiveRunFromHistory("broadcast event gap");
|
|
2100
2183
|
else loadSessionHistory({ merge: true });
|
|
2184
|
+
refreshComposerHistory();
|
|
2101
2185
|
tui.requestRender();
|
|
2102
2186
|
};
|
|
2103
2187
|
const sigintHandler = () => handleCtrlC();
|
package/package.json
CHANGED