dsh-hypatia-auto-memory 0.3.0 → 0.5.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/README.md +68 -7
- package/README.zh-CN.md +54 -9
- package/lib/client.js +720 -40
- package/lib/client.js.map +1 -1
- package/package.json +3 -2
- package/src/cascade.js +29 -4
- package/src/client/MemoryView.module.css +312 -0
- package/src/client/MemoryView.tsx +335 -0
- package/src/client/index.tsx +32 -2
- package/src/client/locales.ts +80 -0
- package/src/client/memory-client.ts +246 -0
- package/src/consolidator.js +159 -37
- package/src/index.js +74 -6
- package/src/memory-api.js +557 -0
- package/src/memory-status.js +167 -0
- package/src/model-log.js +246 -0
package/lib/client.js
CHANGED
|
@@ -47,7 +47,7 @@ window.__ModuleLoader__.load({
|
|
|
47
47
|
}
|
|
48
48
|
return candidates;
|
|
49
49
|
}
|
|
50
|
-
function isRecord(value) {
|
|
50
|
+
function isRecord$1(value) {
|
|
51
51
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
@@ -60,11 +60,11 @@ window.__ModuleLoader__.load({
|
|
|
60
60
|
* @returns the listing, or undefined when the Host does not serve one.
|
|
61
61
|
*/
|
|
62
62
|
function readShelfInventory(described) {
|
|
63
|
-
const view = described.find((entry) => isRecord(entry) && entry.ns === "hypatia-auto-memory-shelves");
|
|
64
|
-
if (!isRecord(view) || !isRecord(view.base)) return void 0;
|
|
63
|
+
const view = described.find((entry) => isRecord$1(entry) && entry.ns === "hypatia-auto-memory-shelves");
|
|
64
|
+
if (!isRecord$1(view) || !isRecord$1(view.base)) return void 0;
|
|
65
65
|
const { shelves, error } = view.base;
|
|
66
66
|
return {
|
|
67
|
-
shelves: Array.isArray(shelves) ? shelves.flatMap((shelf) => isRecord(shelf) && typeof shelf.name === "string" ? [{
|
|
67
|
+
shelves: Array.isArray(shelves) ? shelves.flatMap((shelf) => isRecord$1(shelf) && typeof shelf.name === "string" ? [{
|
|
68
68
|
name: shelf.name,
|
|
69
69
|
path: typeof shelf.path === "string" ? shelf.path : "",
|
|
70
70
|
connected: shelf.connected === true
|
|
@@ -98,55 +98,55 @@ window.__ModuleLoader__.load({
|
|
|
98
98
|
}
|
|
99
99
|
//#endregion
|
|
100
100
|
//#region \0dsh-hypatia-css:/home/runner/work/dsh-hypatia-auto-memory/dsh-hypatia-auto-memory/src/client/SettingsCard.module.css.mjs
|
|
101
|
-
const css = ".YVNYya_card{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:16px;list-style:none;transition:border-color .16s,background .16s}.YVNYya_card:hover{border-color:var(--dsw-alias-label-dimmed)}.YVNYya_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.YVNYya_header{appearance:none;width:100%;color:inherit;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.YVNYya_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.YVNYya_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.YVNYya_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.YVNYya_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.YVNYya_pending{corner-shape:round;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.YVNYya_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.YVNYya_chevronOpen{transform:rotate(180deg)}.YVNYya_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint,.YVNYya_error{margin:0;font-size:12px;line-height:1.5}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint{color:var(--dsw-alias-label-tertiary)}.YVNYya_status{padding:12px 16px;list-style:none}.YVNYya_readOnly{padding-top:12px}.YVNYya_field{gap:6px;padding:12px 0;display:grid}.YVNYya_body>.YVNYya_field+.YVNYya_group,.YVNYya_body>.YVNYya_group+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_group{padding:12px 0}.YVNYya_groupTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle{border-top:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);margin:16px 0 0;padding-top:12px;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle+.YVNYya_hint{margin-top:4px}.YVNYya_group>.YVNYya_field:first-of-type{padding-top:12px}.YVNYya_group>.YVNYya_field+.YVNYya_field,.YVNYya_pairedFields{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_fieldHead{align-items:center;gap:8px;display:flex}.YVNYya_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_reset{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:1.5}.YVNYya_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.YVNYya_reset:disabled{cursor:default}.YVNYya_input{box-sizing:border-box;width:100%;min-width:0;display:flex}.YVNYya_select{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);width:100%;min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;background:0 0;border-radius:8px;padding:0 8px;font-size:13px}.YVNYya_select:disabled{opacity:.5}.YVNYya_select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_warning{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.YVNYya_pairedFields{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:4px 0;padding:4px 0;display:grid}.YVNYya_pairedFields .YVNYya_field{min-width:0}.YVNYya_switch{box-sizing:border-box;background:var(--dsw-alias-border-l3);cursor:pointer;border:0;border-radius:10px;width:36px;height:20px;padding:2px;position:relative}.YVNYya_switchOn{background:var(--dsw-alias-brand-primary)}.YVNYya_switch:disabled{cursor:default;opacity:.5}.YVNYya_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_switchThumb{corner-shape:round;background:var(--dsw-alias-label-primary-foreground);border-radius:50%;width:16px;height:16px;transition:transform .12s;display:block}.YVNYya_switchOn .YVNYya_switchThumb{transform:translate(16px)}.YVNYya_modelSelection{gap:10px;padding:12px 0;display:grid}.YVNYya_notice{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.YVNYya_catalogError{color:var(--dsw-alias-label-error);justify-content:space-between;align-items:center;gap:12px;font-size:12px;line-height:1.5;display:flex}.YVNYya_catalogError button{color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0}.YVNYya_models{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.YVNYya_models legend{color:var(--dsw-alias-label-secondary);padding:0 4px;font-size:12px}.YVNYya_modelGroup{gap:6px;display:grid}.YVNYya_modelGroup+.YVNYya_modelGroup{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}.YVNYya_providerName{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.YVNYya_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.YVNYya_model:hover{background:var(--dsw-alias-bg-layer-4)}.YVNYya_modelName,.YVNYya_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.YVNYya_modelName{color:var(--dsw-alias-label-primary);font-size:13px}.YVNYya_route{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px}.YVNYya_unavailable{color:var(--dsw-alias-label-tertiary);font-size:11px}.YVNYya_error{color:var(--dsw-alias-label-error)}.YVNYya_advancedHint{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.YVNYya_footer{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}@media (width<=480px){.YVNYya_pairedFields{grid-template-columns:minmax(0,1fr);gap:0}.YVNYya_pairedFields .YVNYya_field+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}}";
|
|
102
|
-
const tagId = "dsh-hypatia-auto-memory/SettingsCard.module.css";
|
|
103
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
101
|
+
const css$1 = ".YVNYya_card{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:16px;list-style:none;transition:border-color .16s,background .16s}.YVNYya_card:hover{border-color:var(--dsw-alias-label-dimmed)}.YVNYya_cardOpen{border-color:var(--dsw-alias-label-dimmed);background:var(--dsw-alias-bg-layer-2)}.YVNYya_header{appearance:none;width:100%;color:inherit;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.YVNYya_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.YVNYya_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.YVNYya_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.YVNYya_description{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.YVNYya_pending{corner-shape:round;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-secondary);white-space:nowrap;border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.YVNYya_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.YVNYya_chevronOpen{transform:rotate(180deg)}.YVNYya_body{border-top:.5px solid var(--dsw-alias-border-l2);margin:0 16px;padding-bottom:8px}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint,.YVNYya_error{margin:0;font-size:12px;line-height:1.5}.YVNYya_status,.YVNYya_readOnly,.YVNYya_hint,.YVNYya_advancedHint{color:var(--dsw-alias-label-tertiary)}.YVNYya_status{padding:12px 16px;list-style:none}.YVNYya_readOnly{padding-top:12px}.YVNYya_field{gap:6px;padding:12px 0;display:grid}.YVNYya_body>.YVNYya_field+.YVNYya_group,.YVNYya_body>.YVNYya_group+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_group{padding:12px 0}.YVNYya_groupTitle{color:var(--dsw-alias-label-primary);margin:0;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle{border-top:.5px solid var(--dsw-alias-border-l2);color:var(--dsw-alias-label-primary);margin:16px 0 0;padding-top:12px;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_limitsTitle+.YVNYya_hint{margin-top:4px}.YVNYya_group>.YVNYya_field:first-of-type{padding-top:12px}.YVNYya_group>.YVNYya_field+.YVNYya_field,.YVNYya_pairedFields{border-top:.5px solid var(--dsw-alias-border-l2)}.YVNYya_fieldHead{align-items:center;gap:8px;display:flex}.YVNYya_label{min-width:0;color:var(--dsw-alias-label-primary);flex:1;font-size:13px;font-weight:500;line-height:1.5}.YVNYya_reset{color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0;font-size:12px;line-height:1.5}.YVNYya_reset:hover:not(:disabled){color:var(--dsw-alias-label-primary)}.YVNYya_reset:disabled{cursor:default}.YVNYya_input{box-sizing:border-box;width:100%;min-width:0;display:flex}.YVNYya_select{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);width:100%;min-width:0;height:32px;color:var(--dsw-alias-label-primary);font:inherit;background:0 0;border-radius:8px;padding:0 8px;font-size:13px}.YVNYya_select:disabled{opacity:.5}.YVNYya_select:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_warning{color:var(--dsw-alias-label-error);margin:0;font-size:12px;line-height:1.5}.YVNYya_pairedFields{grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:4px 0;padding:4px 0;display:grid}.YVNYya_pairedFields .YVNYya_field{min-width:0}.YVNYya_switch{box-sizing:border-box;background:var(--dsw-alias-border-l3);cursor:pointer;border:0;border-radius:10px;width:36px;height:20px;padding:2px;position:relative}.YVNYya_switchOn{background:var(--dsw-alias-brand-primary)}.YVNYya_switch:disabled{cursor:default;opacity:.5}.YVNYya_switch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:2px}.YVNYya_switchThumb{corner-shape:round;background:var(--dsw-alias-label-primary-foreground);border-radius:50%;width:16px;height:16px;transition:transform .12s;display:block}.YVNYya_switchOn .YVNYya_switchThumb{transform:translate(16px)}.YVNYya_modelSelection{gap:10px;padding:12px 0;display:grid}.YVNYya_notice{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:1.5}.YVNYya_catalogError{color:var(--dsw-alias-label-error);justify-content:space-between;align-items:center;gap:12px;font-size:12px;line-height:1.5;display:flex}.YVNYya_catalogError button{color:var(--dsw-alias-brand-primary);cursor:pointer;font:inherit;background:0 0;border:0;padding:0}.YVNYya_models{border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;gap:6px;min-width:0;max-height:280px;margin:0;padding:10px;display:grid;overflow:auto}.YVNYya_models legend{color:var(--dsw-alias-label-secondary);padding:0 4px;font-size:12px}.YVNYya_modelGroup{gap:6px;display:grid}.YVNYya_modelGroup+.YVNYya_modelGroup{border-top:.5px solid var(--dsw-alias-border-l3);margin-top:4px;padding-top:10px}.YVNYya_providerName{color:var(--dsw-alias-label-tertiary);padding:0 6px;font-size:11px;font-weight:500}.YVNYya_model{cursor:pointer;border-radius:6px;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:8px;min-width:0;padding:6px;display:grid}.YVNYya_model:hover{background:var(--dsw-alias-bg-layer-4)}.YVNYya_modelName,.YVNYya_route{text-overflow:ellipsis;white-space:nowrap;display:block;overflow:hidden}.YVNYya_modelName{color:var(--dsw-alias-label-primary);font-size:13px}.YVNYya_route{color:var(--dsw-alias-label-tertiary);margin-top:2px;font-size:11px}.YVNYya_unavailable{color:var(--dsw-alias-label-tertiary);font-size:11px}.YVNYya_error{color:var(--dsw-alias-label-error)}.YVNYya_advancedHint{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.YVNYya_footer{border-top:.5px solid var(--dsw-alias-border-l2);justify-content:flex-end;align-items:center;gap:8px;padding:12px 0 4px;display:flex}@media (width<=480px){.YVNYya_pairedFields{grid-template-columns:minmax(0,1fr);gap:0}.YVNYya_pairedFields .YVNYya_field+.YVNYya_field{border-top:.5px solid var(--dsw-alias-border-l2)}}";
|
|
102
|
+
const tagId$1 = "dsh-hypatia-auto-memory/SettingsCard.module.css";
|
|
103
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
104
104
|
const tag = document.createElement("style");
|
|
105
105
|
tag.dataset.plugin = "dsh-hypatia-auto-memory";
|
|
106
|
-
tag.dataset.pluginCss = tagId;
|
|
107
|
-
tag.textContent = css;
|
|
106
|
+
tag.dataset.pluginCss = tagId$1;
|
|
107
|
+
tag.textContent = css$1;
|
|
108
108
|
document.head.appendChild(tag);
|
|
109
109
|
}
|
|
110
110
|
var SettingsCard_module_css_default = {
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
"model": "YVNYya_model",
|
|
114
|
-
"headText": "YVNYya_headText",
|
|
111
|
+
"advancedHint": "YVNYya_advancedHint",
|
|
112
|
+
"body": "YVNYya_body",
|
|
115
113
|
"card": "YVNYya_card",
|
|
116
|
-
"readOnly": "YVNYya_readOnly",
|
|
117
114
|
"cardOpen": "YVNYya_cardOpen",
|
|
118
|
-
"hint": "YVNYya_hint",
|
|
119
|
-
"group": "YVNYya_group",
|
|
120
|
-
"label": "YVNYya_label",
|
|
121
|
-
"providerName": "YVNYya_providerName",
|
|
122
115
|
"catalogError": "YVNYya_catalogError",
|
|
116
|
+
"chevron": "YVNYya_chevron",
|
|
123
117
|
"chevronOpen": "YVNYya_chevronOpen",
|
|
124
|
-
"pending": "YVNYya_pending",
|
|
125
|
-
"unavailable": "YVNYya_unavailable",
|
|
126
|
-
"input": "YVNYya_input",
|
|
127
|
-
"reset": "YVNYya_reset",
|
|
128
118
|
"description": "YVNYya_description",
|
|
129
|
-
"
|
|
119
|
+
"error": "YVNYya_error",
|
|
130
120
|
"field": "YVNYya_field",
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
134
|
-
"status": "YVNYya_status",
|
|
135
|
-
"switchThumb": "YVNYya_switchThumb",
|
|
136
|
-
"route": "YVNYya_route",
|
|
137
|
-
"models": "YVNYya_models",
|
|
121
|
+
"fieldHead": "YVNYya_fieldHead",
|
|
122
|
+
"footer": "YVNYya_footer",
|
|
123
|
+
"group": "YVNYya_group",
|
|
138
124
|
"groupTitle": "YVNYya_groupTitle",
|
|
139
|
-
"
|
|
125
|
+
"headText": "YVNYya_headText",
|
|
126
|
+
"header": "YVNYya_header",
|
|
127
|
+
"hint": "YVNYya_hint",
|
|
128
|
+
"input": "YVNYya_input",
|
|
129
|
+
"label": "YVNYya_label",
|
|
130
|
+
"limitsTitle": "YVNYya_limitsTitle",
|
|
131
|
+
"model": "YVNYya_model",
|
|
132
|
+
"modelGroup": "YVNYya_modelGroup",
|
|
133
|
+
"modelName": "YVNYya_modelName",
|
|
140
134
|
"modelSelection": "YVNYya_modelSelection",
|
|
141
|
-
"
|
|
135
|
+
"models": "YVNYya_models",
|
|
136
|
+
"name": "YVNYya_name",
|
|
137
|
+
"notice": "YVNYya_notice",
|
|
142
138
|
"pairedFields": "YVNYya_pairedFields",
|
|
143
|
-
"
|
|
144
|
-
"
|
|
139
|
+
"pending": "YVNYya_pending",
|
|
140
|
+
"providerName": "YVNYya_providerName",
|
|
141
|
+
"readOnly": "YVNYya_readOnly",
|
|
142
|
+
"reset": "YVNYya_reset",
|
|
143
|
+
"route": "YVNYya_route",
|
|
144
|
+
"select": "YVNYya_select",
|
|
145
|
+
"status": "YVNYya_status",
|
|
145
146
|
"switch": "YVNYya_switch",
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"fieldHead": "YVNYya_fieldHead",
|
|
147
|
+
"switchOn": "YVNYya_switchOn",
|
|
148
|
+
"switchThumb": "YVNYya_switchThumb",
|
|
149
|
+
"unavailable": "YVNYya_unavailable",
|
|
150
150
|
"warning": "YVNYya_warning"
|
|
151
151
|
};
|
|
152
152
|
//#endregion
|
|
@@ -201,7 +201,47 @@ window.__ModuleLoader__.load({
|
|
|
201
201
|
saving: "保存中…",
|
|
202
202
|
saveFailed: "保存失败:{message}",
|
|
203
203
|
readOnly: "只读:当前上下文不可写入设置文档。",
|
|
204
|
-
unsaved: "未保存"
|
|
204
|
+
unsaved: "未保存",
|
|
205
|
+
viewMemory: "记忆",
|
|
206
|
+
memoryTitle: "本会话的记忆",
|
|
207
|
+
memoryUpdatedAt: "状态更新于 {time}",
|
|
208
|
+
memoryRefresh: "刷新",
|
|
209
|
+
memoryLoading: "正在读取记忆状态…",
|
|
210
|
+
memoryNoSnapshot: "插件还没有发布记忆状态。启用后完成一轮对话再回来看看。",
|
|
211
|
+
memoryLoadFailed: "无法读取记忆状态:{message}",
|
|
212
|
+
memoryUnknown: "这个会话还没有记忆记录。第一轮对话结束后会开始记录。",
|
|
213
|
+
memoryLogged: "对话记录",
|
|
214
|
+
memorySeqValue: "第 {seq} 条事件",
|
|
215
|
+
memoryConsolidated: "摘要整合",
|
|
216
|
+
memoryCaughtUp: "已结清",
|
|
217
|
+
memoryBehind: "较记录落后 {behind} 条",
|
|
218
|
+
memoryPending: "待整合内容",
|
|
219
|
+
memoryPendingValue: "约 {tokens} token",
|
|
220
|
+
memorySessionNode: "会话节点",
|
|
221
|
+
memorySessionNodeYes: "已建立",
|
|
222
|
+
memorySessionNodeNo: "未建立(宿主未提供会话摘要)",
|
|
223
|
+
memoryBelongTo: "已链接消息",
|
|
224
|
+
memoryBelongToValue: "{count} 条",
|
|
225
|
+
memoryDeferred: "等待会话载入的任务",
|
|
226
|
+
memoryFailedTitle: "失败任务",
|
|
227
|
+
memoryFailedItem: "{kind} 连续失败 {attempts} 次",
|
|
228
|
+
memoryContentTitle: "记忆内容",
|
|
229
|
+
memoryContentFailed: "无法读取 shelf 中的记忆内容:{message}",
|
|
230
|
+
memorySummariesTitle: "跨度摘要",
|
|
231
|
+
memoryWorkUnitsTitle: "工作单元",
|
|
232
|
+
memoryNoSummaries: "这个会话还没有产生摘要。整合运行后会出现在这里。",
|
|
233
|
+
memoryNoWorkUnits: "这个会话还没有提炼出工作单元。",
|
|
234
|
+
memoryCount: "显示 {shown} / 共 {total}",
|
|
235
|
+
memoryTier: "{level} 级",
|
|
236
|
+
memoryWorkUnit: "工作单元",
|
|
237
|
+
memoryEntryExpand: "展开",
|
|
238
|
+
memoryEntryCollapse: "收起",
|
|
239
|
+
memoryEntryEmpty: "这条条目的正文为空,或已超过展示上限。",
|
|
240
|
+
memoryCopyCode: "复制",
|
|
241
|
+
memoryCopiedCode: "已复制",
|
|
242
|
+
memoryFootnotes: "脚注",
|
|
243
|
+
memoryTruncated: "内容超出展示上限,较早的条目或过长的正文已被截断。",
|
|
244
|
+
memoryHint: "诊断视图:原始 msg-* 对话正文不在此显示,需要时让 Agent 通过 hypatia 检索。状态每 5 秒重读一次;「状态更新于」是宿主最近一次看到这些状态发生变化的时间(首次读取也算一次),不变说明这段时间没有新进展。两个条数都按会话日志的事件序号计(含工具调用,不是消息条数),所以它们之差就是还没总结的部分。"
|
|
205
245
|
};
|
|
206
246
|
/** English dictionary checked against the Chinese key set. */
|
|
207
247
|
const en = {
|
|
@@ -250,7 +290,47 @@ window.__ModuleLoader__.load({
|
|
|
250
290
|
saving: "Saving…",
|
|
251
291
|
saveFailed: "Save failed: {message}",
|
|
252
292
|
readOnly: "Read-only: settings document is not writable in this context.",
|
|
253
|
-
unsaved: "Unsaved"
|
|
293
|
+
unsaved: "Unsaved",
|
|
294
|
+
viewMemory: "Memory",
|
|
295
|
+
memoryTitle: "This session's memory",
|
|
296
|
+
memoryUpdatedAt: "State updated {time}",
|
|
297
|
+
memoryRefresh: "Refresh",
|
|
298
|
+
memoryLoading: "Reading memory status…",
|
|
299
|
+
memoryNoSnapshot: "The plugin has not published a status snapshot yet. Enable it, finish a turn, and come back.",
|
|
300
|
+
memoryLoadFailed: "Unable to read memory status: {message}",
|
|
301
|
+
memoryUnknown: "This session has no memory record yet. Logging starts once the first turn ends.",
|
|
302
|
+
memoryLogged: "Conversation log",
|
|
303
|
+
memorySeqValue: "event {seq}",
|
|
304
|
+
memoryConsolidated: "Summarisation",
|
|
305
|
+
memoryCaughtUp: "caught up",
|
|
306
|
+
memoryBehind: "{behind} events behind the log",
|
|
307
|
+
memoryPending: "Waiting to summarise",
|
|
308
|
+
memoryPendingValue: "~{tokens} tokens",
|
|
309
|
+
memorySessionNode: "Session node",
|
|
310
|
+
memorySessionNodeYes: "created",
|
|
311
|
+
memorySessionNodeNo: "not created (the Host supplied no session summary)",
|
|
312
|
+
memoryBelongTo: "Linked messages",
|
|
313
|
+
memoryBelongToValue: "{count}",
|
|
314
|
+
memoryDeferred: "Tasks waiting for the session to load",
|
|
315
|
+
memoryFailedTitle: "Failed tasks",
|
|
316
|
+
memoryFailedItem: "{kind} failed {attempts} times",
|
|
317
|
+
memoryContentTitle: "Memory content",
|
|
318
|
+
memoryContentFailed: "Unable to read memory content from the shelf: {message}",
|
|
319
|
+
memorySummariesTitle: "Span summaries",
|
|
320
|
+
memoryWorkUnitsTitle: "Work units",
|
|
321
|
+
memoryNoSummaries: "This session has produced no summary yet. They appear here once consolidation runs.",
|
|
322
|
+
memoryNoWorkUnits: "This session has yielded no work units yet.",
|
|
323
|
+
memoryCount: "showing {shown} of {total}",
|
|
324
|
+
memoryTier: "tier {level}",
|
|
325
|
+
memoryWorkUnit: "work unit",
|
|
326
|
+
memoryEntryExpand: "Expand",
|
|
327
|
+
memoryEntryCollapse: "Collapse",
|
|
328
|
+
memoryEntryEmpty: "This entry has no body, or it exceeded the display cap.",
|
|
329
|
+
memoryCopyCode: "Copy",
|
|
330
|
+
memoryCopiedCode: "Copied",
|
|
331
|
+
memoryFootnotes: "Footnotes",
|
|
332
|
+
memoryTruncated: "Content exceeded the display cap: earlier entries or over-long bodies were cut.",
|
|
333
|
+
memoryHint: "Diagnostic view: raw msg-* conversation text is not shown here — ask the agent to retrieve it through hypatia. Status is re-read every 5 seconds; the timestamp is when the Host last saw that state change (the first read counts as one), so an unchanged one means nothing new happened. Both counts index the session log's event sequence (tool calls included, not messages), so their difference is what is left to summarise."
|
|
254
334
|
};
|
|
255
335
|
//#endregion
|
|
256
336
|
//#region src/client/SettingsCard.tsx
|
|
@@ -1007,6 +1087,596 @@ window.__ModuleLoader__.load({
|
|
|
1007
1087
|
});
|
|
1008
1088
|
}
|
|
1009
1089
|
//#endregion
|
|
1090
|
+
//#region src/client/memory-client.ts
|
|
1091
|
+
/**
|
|
1092
|
+
* The Memory tab's read side: one same-origin request per refresh.
|
|
1093
|
+
*
|
|
1094
|
+
* The Host half serves it from `/api/dsh-hypatia-auto-memory/session`
|
|
1095
|
+
* (see `src/memory-api.js`), which is parameterized by session and authenticates
|
|
1096
|
+
* itself — unlike a settings namespace, it can answer for the one session the
|
|
1097
|
+
* tab is bound to instead of shipping every session's state to the browser.
|
|
1098
|
+
*
|
|
1099
|
+
* Zero runtime imports beyond `fetch`, so the parsing half is unit-tested under
|
|
1100
|
+
* `node:test` like `shelves.ts`.
|
|
1101
|
+
*/
|
|
1102
|
+
/** Route prefix the Host claims; the tab appends `/session`. */
|
|
1103
|
+
const MEMORY_API_PREFIX = "/api/dsh-hypatia-auto-memory";
|
|
1104
|
+
/**
|
|
1105
|
+
* The URL one refresh reads.
|
|
1106
|
+
* @param sessionId - the session the tab is bound to.
|
|
1107
|
+
* @param content - whether to ask the Host to read the shelf as well.
|
|
1108
|
+
* @returns a same-origin path with its query.
|
|
1109
|
+
*/
|
|
1110
|
+
function memoryUrl(sessionId, content) {
|
|
1111
|
+
const query = new URLSearchParams({ session: sessionId });
|
|
1112
|
+
if (content) query.set("content", "1");
|
|
1113
|
+
return `${MEMORY_API_PREFIX}/session?${query.toString()}`;
|
|
1114
|
+
}
|
|
1115
|
+
/** Fetch one session's memory from the Host. */
|
|
1116
|
+
const fetchMemory = async (sessionId, { content }) => {
|
|
1117
|
+
const response = await fetch(memoryUrl(sessionId, content), {
|
|
1118
|
+
method: "GET",
|
|
1119
|
+
credentials: "same-origin",
|
|
1120
|
+
headers: { accept: "application/json" }
|
|
1121
|
+
});
|
|
1122
|
+
const body = await response.json().catch(() => void 0);
|
|
1123
|
+
if (!response.ok) {
|
|
1124
|
+
const message = isRecord(body) && typeof body.error === "string" ? body.error : `HTTP ${String(response.status)}`;
|
|
1125
|
+
throw new Error(message);
|
|
1126
|
+
}
|
|
1127
|
+
const payload = parseMemoryPayload(body, sessionId);
|
|
1128
|
+
if (payload === void 0) throw new Error("the Host returned an unreadable memory payload");
|
|
1129
|
+
return payload;
|
|
1130
|
+
};
|
|
1131
|
+
/**
|
|
1132
|
+
* Session-log events that are recorded but not yet consolidated.
|
|
1133
|
+
*
|
|
1134
|
+
* Both watermarks index the same log, so their difference is exactly the work
|
|
1135
|
+
* consolidation still owes. Clamped at zero: a consolidation run may cover a
|
|
1136
|
+
* range the logging watermark has not caught up to yet, which is not a backlog.
|
|
1137
|
+
*
|
|
1138
|
+
* @param session - the session half of a payload.
|
|
1139
|
+
* @returns the gap in session-log events.
|
|
1140
|
+
*/
|
|
1141
|
+
function consolidationGap(session) {
|
|
1142
|
+
return Math.max(0, session.loggedSeq - session.consolidatedSeq);
|
|
1143
|
+
}
|
|
1144
|
+
function isRecord(value) {
|
|
1145
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1146
|
+
}
|
|
1147
|
+
function num(value) {
|
|
1148
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1149
|
+
}
|
|
1150
|
+
function str(value) {
|
|
1151
|
+
return typeof value === "string" ? value : "";
|
|
1152
|
+
}
|
|
1153
|
+
function parseFailedTasks(value) {
|
|
1154
|
+
if (!Array.isArray(value)) return [];
|
|
1155
|
+
return value.flatMap((entry) => isRecord(entry) ? [{
|
|
1156
|
+
kind: str(entry.kind),
|
|
1157
|
+
sessionId: str(entry.sessionId),
|
|
1158
|
+
attempts: num(entry.attempts),
|
|
1159
|
+
error: str(entry.error)
|
|
1160
|
+
}] : []);
|
|
1161
|
+
}
|
|
1162
|
+
function parseEntries(value) {
|
|
1163
|
+
if (!Array.isArray(value)) return [];
|
|
1164
|
+
return value.flatMap((entry) => {
|
|
1165
|
+
if (!isRecord(entry)) return [];
|
|
1166
|
+
const name = str(entry.name);
|
|
1167
|
+
if (name === "") return [];
|
|
1168
|
+
return [{
|
|
1169
|
+
name,
|
|
1170
|
+
markdown: str(entry.markdown),
|
|
1171
|
+
level: num(entry.level) || 1,
|
|
1172
|
+
createdAt: str(entry.createdAt)
|
|
1173
|
+
}];
|
|
1174
|
+
});
|
|
1175
|
+
}
|
|
1176
|
+
/**
|
|
1177
|
+
* Read the Host's answer into the tab's shape, defensively.
|
|
1178
|
+
*
|
|
1179
|
+
* A malformed field falls back to its zero value rather than reaching the DOM;
|
|
1180
|
+
* a payload with no usable `session` is rejected outright, because rendering a
|
|
1181
|
+
* panel of zeros for a session the Host never answered about would be a lie.
|
|
1182
|
+
*
|
|
1183
|
+
* A status-only answer parses to `content: undefined` — never to empty lists,
|
|
1184
|
+
* which is what made the five-second poll erase the shelf content. The Host also
|
|
1185
|
+
* states which half it sent (`content`), and that flag is what this prefers; the
|
|
1186
|
+
* key sniffing beside it keeps a bundle built after the flag from misreading a
|
|
1187
|
+
* Host that predates it, so the fix does not need a profile restart to land.
|
|
1188
|
+
*
|
|
1189
|
+
* @param value - the parsed response body.
|
|
1190
|
+
* @param sessionId - the session that was asked for.
|
|
1191
|
+
* @returns the payload, or undefined when the body is not one.
|
|
1192
|
+
*/
|
|
1193
|
+
function parseMemoryPayload(value, sessionId) {
|
|
1194
|
+
if (!isRecord(value) || !isRecord(value.session)) return void 0;
|
|
1195
|
+
const session = value.session;
|
|
1196
|
+
const carried = value.content === true || Object.hasOwn(value, "summaries") || Object.hasOwn(value, "contentError");
|
|
1197
|
+
return {
|
|
1198
|
+
session: {
|
|
1199
|
+
sessionId: str(session.sessionId) || sessionId,
|
|
1200
|
+
known: session.known === true,
|
|
1201
|
+
loggedSeq: num(session.loggedSeq),
|
|
1202
|
+
consolidatedSeq: num(session.consolidatedSeq),
|
|
1203
|
+
caughtUp: session.caughtUp === true,
|
|
1204
|
+
pendingTokens: num(session.pendingTokens),
|
|
1205
|
+
sessionNode: session.sessionNode === true,
|
|
1206
|
+
belongTo: num(session.belongTo),
|
|
1207
|
+
deferred: num(session.deferred),
|
|
1208
|
+
failed: num(session.failed),
|
|
1209
|
+
failedTasks: parseFailedTasks(session.failedTasks),
|
|
1210
|
+
error: str(session.error)
|
|
1211
|
+
},
|
|
1212
|
+
updatedAt: num(value.updatedAt),
|
|
1213
|
+
content: carried ? {
|
|
1214
|
+
summaries: parseEntries(value.summaries),
|
|
1215
|
+
workUnits: parseEntries(value.workUnits),
|
|
1216
|
+
summaryCount: num(value.summaryCount),
|
|
1217
|
+
workUnitCount: num(value.workUnitCount),
|
|
1218
|
+
truncated: value.truncated === true,
|
|
1219
|
+
error: str(value.contentError)
|
|
1220
|
+
} : void 0
|
|
1221
|
+
};
|
|
1222
|
+
}
|
|
1223
|
+
/**
|
|
1224
|
+
* Fold a new answer onto the one on screen.
|
|
1225
|
+
*
|
|
1226
|
+
* Status is always the newest. Content is only replaced by an answer that
|
|
1227
|
+
* carried content, so the poll cannot erase it. An answer whose shelf read
|
|
1228
|
+
* failed keeps the content already shown — entries, counts and the truncation
|
|
1229
|
+
* flag together, so the header still describes the list under it — and records
|
|
1230
|
+
* the error beside it, because a transient hypatia failure should not blank
|
|
1231
|
+
* what the reader was looking at.
|
|
1232
|
+
*
|
|
1233
|
+
* @param previous - the payload on screen, if any.
|
|
1234
|
+
* @param next - the answer just parsed.
|
|
1235
|
+
* @returns the payload to render.
|
|
1236
|
+
*/
|
|
1237
|
+
function mergeMemory(previous, next) {
|
|
1238
|
+
if (next.content === void 0) return {
|
|
1239
|
+
...next,
|
|
1240
|
+
content: previous?.content
|
|
1241
|
+
};
|
|
1242
|
+
if (next.content.error !== "" && previous?.content !== void 0) return {
|
|
1243
|
+
...next,
|
|
1244
|
+
content: {
|
|
1245
|
+
...previous.content,
|
|
1246
|
+
error: next.content.error
|
|
1247
|
+
}
|
|
1248
|
+
};
|
|
1249
|
+
return next;
|
|
1250
|
+
}
|
|
1251
|
+
//#endregion
|
|
1252
|
+
//#region \0dsh-hypatia-css:/home/runner/work/dsh-hypatia-auto-memory/dsh-hypatia-auto-memory/src/client/MemoryView.module.css.mjs
|
|
1253
|
+
const css = ".LBuOzG_panel{box-sizing:border-box;width:100%;height:100%;min-height:0;padding:16px;padding-bottom:calc(var(--dsh-composer-height,152px) + 16px);color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-layer-1);flex-direction:column;align-items:center;display:flex;overflow-y:auto}.LBuOzG_column{flex-direction:column;gap:20px;width:100%;min-width:0;max-width:880px;display:flex}.LBuOzG_head{justify-content:space-between;align-items:baseline;gap:12px;display:flex}.LBuOzG_title{color:var(--dsw-alias-label-primary);margin:0;font-size:15px;font-weight:600;line-height:1.4}.LBuOzG_headMeta{align-items:center;gap:10px;display:flex}.LBuOzG_updated{color:var(--dsw-alias-label-tertiary);font-size:12px}.LBuOzG_refresh{appearance:none;border:.5px solid var(--dsw-alias-border-l4);color:var(--dsw-alias-label-secondary);cursor:pointer;font:inherit;background:0 0;border-radius:8px;padding:2px 8px;font-size:12px}.LBuOzG_refresh:hover{border-color:var(--dsw-alias-label-dimmed);color:var(--dsw-alias-label-primary)}.LBuOzG_refresh:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.LBuOzG_status,.LBuOzG_hint,.LBuOzG_error{margin:0;font-size:12px;line-height:1.6}.LBuOzG_status,.LBuOzG_hint{color:var(--dsw-alias-label-tertiary)}.LBuOzG_error{color:var(--dsw-alias-label-error)}.LBuOzG_group{border-top:.5px solid var(--dsw-alias-border-l2);flex-direction:column;gap:10px;padding-top:16px;display:flex}.LBuOzG_groupTitle{color:var(--dsw-alias-label-primary);align-items:baseline;gap:8px;margin:0;font-size:13px;font-weight:600;display:flex}.LBuOzG_count{color:var(--dsw-alias-label-tertiary);font-variant-numeric:tabular-nums;font-size:11px;font-weight:400}.LBuOzG_rows{grid-template-columns:max-content minmax(0,1fr);align-items:baseline;gap:7px 20px;margin:0;display:grid}.LBuOzG_row{display:contents}.LBuOzG_label{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:12px}.LBuOzG_value{min-width:0;color:var(--dsw-alias-label-primary);font-variant-numeric:tabular-nums;align-items:baseline;gap:8px;margin:0;font-size:12px;display:flex}.LBuOzG_calm,.LBuOzG_busy{white-space:nowrap;border-radius:6px;padding:1px 6px;font-size:11px}.LBuOzG_calm{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-2)}.LBuOzG_busy{color:var(--dsw-alias-label-primary);border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3)}.LBuOzG_failures{gap:6px;margin:0;padding:0;list-style:none;display:grid}.LBuOzG_failure{background:var(--dsw-alias-bg-layer-2);border-radius:8px;gap:2px;padding:8px 10px;display:grid}.LBuOzG_failureKind{color:var(--dsw-alias-label-primary);font-size:12px}.LBuOzG_failureError{color:var(--dsw-alias-label-tertiary);overflow-wrap:anywhere;font-size:11px;line-height:1.5}.LBuOzG_entries{flex-direction:column;gap:8px;margin:0;padding:0;list-style:none;display:flex}.LBuOzG_entry{border:.5px solid var(--dsw-alias-border-l2);background:var(--dsw-alias-bg-layer-2);border-radius:10px;overflow:hidden}.LBuOzG_entryHead{appearance:none;width:100%;color:inherit;cursor:pointer;font:inherit;text-align:left;background:0 0;border:0;justify-content:space-between;align-items:baseline;gap:12px;padding:8px 12px;display:flex}.LBuOzG_entryHead:hover{background:var(--dsw-alias-bg-layer-3)}.LBuOzG_entryHead:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.LBuOzG_entryName{min-width:0;color:var(--dsw-alias-label-secondary);font-family:var(--dsw-font-family-mono,ui-monospace, SFMono-Regular, Menlo, monospace);text-overflow:ellipsis;white-space:nowrap;font-size:11px;overflow:hidden}.LBuOzG_entryMeta{flex:none;align-items:baseline;gap:8px;display:flex}.LBuOzG_badge{background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-tertiary);white-space:nowrap;border-radius:6px;padding:1px 6px;font-size:11px}.LBuOzG_entryTime{color:var(--dsw-alias-label-quaternary);font-variant-numeric:tabular-nums;white-space:nowrap;font-size:11px}.LBuOzG_entryToggle{color:var(--dsw-alias-label-tertiary);white-space:nowrap;font-size:11px}.LBuOzG_entryBody{border-top:.5px solid var(--dsw-alias-border-l2);overflow-wrap:anywhere;padding:10px 12px;font-size:13px;line-height:1.65}.LBuOzG_entryPreview{color:var(--dsw-alias-label-tertiary);text-overflow:ellipsis;white-space:nowrap;margin:0;padding:0 12px 10px;font-size:12px;line-height:1.5;overflow:hidden}.LBuOzG_hint{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}";
|
|
1254
|
+
const tagId = "dsh-hypatia-auto-memory/MemoryView.module.css";
|
|
1255
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
1256
|
+
const tag = document.createElement("style");
|
|
1257
|
+
tag.dataset.plugin = "dsh-hypatia-auto-memory";
|
|
1258
|
+
tag.dataset.pluginCss = tagId;
|
|
1259
|
+
tag.textContent = css;
|
|
1260
|
+
document.head.appendChild(tag);
|
|
1261
|
+
}
|
|
1262
|
+
var MemoryView_module_css_default = {
|
|
1263
|
+
"badge": "LBuOzG_badge",
|
|
1264
|
+
"busy": "LBuOzG_busy",
|
|
1265
|
+
"calm": "LBuOzG_calm",
|
|
1266
|
+
"column": "LBuOzG_column",
|
|
1267
|
+
"count": "LBuOzG_count",
|
|
1268
|
+
"entries": "LBuOzG_entries",
|
|
1269
|
+
"entry": "LBuOzG_entry",
|
|
1270
|
+
"entryBody": "LBuOzG_entryBody",
|
|
1271
|
+
"entryHead": "LBuOzG_entryHead",
|
|
1272
|
+
"entryMeta": "LBuOzG_entryMeta",
|
|
1273
|
+
"entryName": "LBuOzG_entryName",
|
|
1274
|
+
"entryPreview": "LBuOzG_entryPreview",
|
|
1275
|
+
"entryTime": "LBuOzG_entryTime",
|
|
1276
|
+
"entryToggle": "LBuOzG_entryToggle",
|
|
1277
|
+
"error": "LBuOzG_error",
|
|
1278
|
+
"failure": "LBuOzG_failure",
|
|
1279
|
+
"failureError": "LBuOzG_failureError",
|
|
1280
|
+
"failureKind": "LBuOzG_failureKind",
|
|
1281
|
+
"failures": "LBuOzG_failures",
|
|
1282
|
+
"group": "LBuOzG_group",
|
|
1283
|
+
"groupTitle": "LBuOzG_groupTitle",
|
|
1284
|
+
"head": "LBuOzG_head",
|
|
1285
|
+
"headMeta": "LBuOzG_headMeta",
|
|
1286
|
+
"hint": "LBuOzG_hint",
|
|
1287
|
+
"label": "LBuOzG_label",
|
|
1288
|
+
"panel": "LBuOzG_panel",
|
|
1289
|
+
"refresh": "LBuOzG_refresh",
|
|
1290
|
+
"row": "LBuOzG_row",
|
|
1291
|
+
"rows": "LBuOzG_rows",
|
|
1292
|
+
"status": "LBuOzG_status",
|
|
1293
|
+
"title": "LBuOzG_title",
|
|
1294
|
+
"updated": "LBuOzG_updated",
|
|
1295
|
+
"value": "LBuOzG_value"
|
|
1296
|
+
};
|
|
1297
|
+
//#endregion
|
|
1298
|
+
//#region src/client/MemoryView.tsx
|
|
1299
|
+
/**
|
|
1300
|
+
* The conversation's Memory tab: what this session has been remembered as, what
|
|
1301
|
+
* it was remembered into, and what is stuck.
|
|
1302
|
+
*
|
|
1303
|
+
* Three sections, in the order a reader wants them: the pipeline's status
|
|
1304
|
+
* (watermarks, backlog, failures), then the span summaries consolidation
|
|
1305
|
+
* produced, then the work units derived from them. Bodies render through the
|
|
1306
|
+
* shell's own `MarkdownText`, so a summary reads exactly like assistant Markdown
|
|
1307
|
+
* elsewhere in the GUI and costs no bundle weight.
|
|
1308
|
+
*
|
|
1309
|
+
* Raw `msg-*` entries are deliberately absent: they hold the conversation
|
|
1310
|
+
* verbatim, the reader just wrote them, and the agent is the right reader for
|
|
1311
|
+
* them (see `src/memory-api.js` for the same rule on the Host side).
|
|
1312
|
+
*
|
|
1313
|
+
* Status is polled; content is fetched only when it can have changed — on mount,
|
|
1314
|
+
* on a session switch, on a manual refresh, and whenever consolidation advances
|
|
1315
|
+
* the session's watermark. Reading the shelf costs hypatia round trips, and
|
|
1316
|
+
* consolidation is the only thing that changes it.
|
|
1317
|
+
*/
|
|
1318
|
+
/** How often the tab re-reads the status half while it is on screen. */
|
|
1319
|
+
const POLL_MS = 5e3;
|
|
1320
|
+
/** Local wall-clock stamp for the freshness line. */
|
|
1321
|
+
function formatTime(epochMs) {
|
|
1322
|
+
if (!Number.isFinite(epochMs) || epochMs <= 0) return "—";
|
|
1323
|
+
return new Date(epochMs).toLocaleTimeString();
|
|
1324
|
+
}
|
|
1325
|
+
/**
|
|
1326
|
+
* hypatia stamps `created_at` as `YYYY-MM-DD HH:MM:SS.ffffff`; the microseconds
|
|
1327
|
+
* are noise in a row that is 11px tall, so the tab shows down to the minute.
|
|
1328
|
+
* Slice rather than `new Date`: the space-separated form is not the ISO shape
|
|
1329
|
+
* every engine is required to parse.
|
|
1330
|
+
*/
|
|
1331
|
+
function formatEntryTime(stamp) {
|
|
1332
|
+
return stamp.length >= 16 ? stamp.slice(0, 16).replace("T", " ") : stamp;
|
|
1333
|
+
}
|
|
1334
|
+
/** The first non-empty line of a body, for a collapsed row's preview. */
|
|
1335
|
+
function firstLine(markdown) {
|
|
1336
|
+
for (const line of markdown.split("\n")) {
|
|
1337
|
+
const trimmed = line.replace(/^[#>\-*\s]+/, "").trim();
|
|
1338
|
+
if (trimmed !== "") return trimmed;
|
|
1339
|
+
}
|
|
1340
|
+
return "";
|
|
1341
|
+
}
|
|
1342
|
+
/** One collapsible distilled entry. */
|
|
1343
|
+
function Entry({ entry, badge, open, onToggle, labels, t }) {
|
|
1344
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
1345
|
+
className: MemoryView_module_css_default.entry,
|
|
1346
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1347
|
+
type: "button",
|
|
1348
|
+
className: MemoryView_module_css_default.entryHead,
|
|
1349
|
+
"aria-expanded": open,
|
|
1350
|
+
onClick: onToggle,
|
|
1351
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1352
|
+
className: MemoryView_module_css_default.entryName,
|
|
1353
|
+
children: entry.name
|
|
1354
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
1355
|
+
className: MemoryView_module_css_default.entryMeta,
|
|
1356
|
+
children: [
|
|
1357
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1358
|
+
className: MemoryView_module_css_default.badge,
|
|
1359
|
+
children: badge
|
|
1360
|
+
}),
|
|
1361
|
+
entry.createdAt !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1362
|
+
className: MemoryView_module_css_default.entryTime,
|
|
1363
|
+
children: formatEntryTime(entry.createdAt)
|
|
1364
|
+
}) : null,
|
|
1365
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1366
|
+
className: MemoryView_module_css_default.entryToggle,
|
|
1367
|
+
children: open ? t("memoryEntryCollapse") : t("memoryEntryExpand")
|
|
1368
|
+
})
|
|
1369
|
+
]
|
|
1370
|
+
})]
|
|
1371
|
+
}), open ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1372
|
+
className: MemoryView_module_css_default.entryBody,
|
|
1373
|
+
children: entry.markdown === "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1374
|
+
className: MemoryView_module_css_default.status,
|
|
1375
|
+
children: t("memoryEntryEmpty")
|
|
1376
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.MarkdownText, {
|
|
1377
|
+
text: entry.markdown,
|
|
1378
|
+
labels
|
|
1379
|
+
})
|
|
1380
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1381
|
+
className: MemoryView_module_css_default.entryPreview,
|
|
1382
|
+
children: firstLine(entry.markdown)
|
|
1383
|
+
})]
|
|
1384
|
+
});
|
|
1385
|
+
}
|
|
1386
|
+
function MemoryView({ sessionId, fetch, t }) {
|
|
1387
|
+
const [payload, setPayload] = (0, react.useState)(void 0);
|
|
1388
|
+
const [loading, setLoading] = (0, react.useState)(true);
|
|
1389
|
+
const [error, setError] = (0, react.useState)("");
|
|
1390
|
+
/**
|
|
1391
|
+
* The entries the reader opened, by name. Absent means closed, which is the
|
|
1392
|
+
* default: a toggle survives the poll that replaces the payload, and an entry
|
|
1393
|
+
* a later poll adds starts closed rather than inheriting a neighbour's state.
|
|
1394
|
+
*/
|
|
1395
|
+
const [overrides, setOverrides] = (0, react.useState)({});
|
|
1396
|
+
/** The watermark whose content is already in hand, so a poll never re-reads it. */
|
|
1397
|
+
const [contentAt, setContentAt] = (0, react.useState)(void 0);
|
|
1398
|
+
const copyLabel = t("memoryCopyCode");
|
|
1399
|
+
const copiedLabel = t("memoryCopiedCode");
|
|
1400
|
+
const footnotes = t("memoryFootnotes");
|
|
1401
|
+
const labels = (0, react.useMemo)(() => ({
|
|
1402
|
+
code: {
|
|
1403
|
+
copyLabel,
|
|
1404
|
+
copiedLabel
|
|
1405
|
+
},
|
|
1406
|
+
footnotes
|
|
1407
|
+
}), [
|
|
1408
|
+
copyLabel,
|
|
1409
|
+
copiedLabel,
|
|
1410
|
+
footnotes
|
|
1411
|
+
]);
|
|
1412
|
+
/**
|
|
1413
|
+
* The session the tab is showing now. A request outlives the session it was
|
|
1414
|
+
* made for — a slow shelf read, or a poll already in flight at a switch — and
|
|
1415
|
+
* its answer must be dropped rather than folded into the next session's view.
|
|
1416
|
+
*/
|
|
1417
|
+
const activeSession = (0, react.useRef)(sessionId);
|
|
1418
|
+
const load = (0, react.useCallback)(async (content) => {
|
|
1419
|
+
const current = () => activeSession.current === sessionId;
|
|
1420
|
+
try {
|
|
1421
|
+
const next = await fetch(sessionId, { content });
|
|
1422
|
+
if (!current()) return;
|
|
1423
|
+
setPayload((previous) => mergeMemory(previous, next));
|
|
1424
|
+
setError("");
|
|
1425
|
+
if (content) setContentAt(next.session.consolidatedSeq);
|
|
1426
|
+
} catch (failure) {
|
|
1427
|
+
if (!current()) return;
|
|
1428
|
+
setError(failure instanceof Error ? failure.message : String(failure));
|
|
1429
|
+
} finally {
|
|
1430
|
+
if (current()) setLoading(false);
|
|
1431
|
+
}
|
|
1432
|
+
}, [fetch, sessionId]);
|
|
1433
|
+
(0, react.useEffect)(() => {
|
|
1434
|
+
activeSession.current = sessionId;
|
|
1435
|
+
setPayload(void 0);
|
|
1436
|
+
setOverrides({});
|
|
1437
|
+
setContentAt(void 0);
|
|
1438
|
+
setLoading(true);
|
|
1439
|
+
load(true);
|
|
1440
|
+
}, [load, sessionId]);
|
|
1441
|
+
(0, react.useEffect)(() => {
|
|
1442
|
+
const timer = setInterval(() => {
|
|
1443
|
+
if (typeof document !== "undefined" && document.visibilityState === "hidden") return;
|
|
1444
|
+
load(false);
|
|
1445
|
+
}, POLL_MS);
|
|
1446
|
+
return () => clearInterval(timer);
|
|
1447
|
+
}, [load]);
|
|
1448
|
+
(0, react.useEffect)(() => {
|
|
1449
|
+
const at = payload?.session.consolidatedSeq;
|
|
1450
|
+
if (at === void 0 || contentAt === void 0) return;
|
|
1451
|
+
if (at !== contentAt) load(true);
|
|
1452
|
+
}, [
|
|
1453
|
+
payload?.session.consolidatedSeq,
|
|
1454
|
+
contentAt,
|
|
1455
|
+
load
|
|
1456
|
+
]);
|
|
1457
|
+
const toggle = (0, react.useCallback)((name, open) => {
|
|
1458
|
+
setOverrides((current) => ({
|
|
1459
|
+
...current,
|
|
1460
|
+
[name]: !open
|
|
1461
|
+
}));
|
|
1462
|
+
}, []);
|
|
1463
|
+
const session = payload?.session;
|
|
1464
|
+
const content = payload?.content;
|
|
1465
|
+
const summaries = content?.summaries ?? [];
|
|
1466
|
+
const workUnits = content?.workUnits ?? [];
|
|
1467
|
+
const renderEntries = (entries, kind) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
|
|
1468
|
+
className: MemoryView_module_css_default.entries,
|
|
1469
|
+
children: entries.map((entry) => {
|
|
1470
|
+
const open = overrides[entry.name] === true;
|
|
1471
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Entry, {
|
|
1472
|
+
entry,
|
|
1473
|
+
badge: kind === "summary" ? t("memoryTier", { level: String(entry.level) }) : t("memoryWorkUnit"),
|
|
1474
|
+
open,
|
|
1475
|
+
onToggle: () => toggle(entry.name, open),
|
|
1476
|
+
labels,
|
|
1477
|
+
t
|
|
1478
|
+
}, entry.name);
|
|
1479
|
+
})
|
|
1480
|
+
});
|
|
1481
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1482
|
+
className: MemoryView_module_css_default.panel,
|
|
1483
|
+
"data-conversation-composer-overlay": "",
|
|
1484
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1485
|
+
className: MemoryView_module_css_default.column,
|
|
1486
|
+
children: [
|
|
1487
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", {
|
|
1488
|
+
className: MemoryView_module_css_default.head,
|
|
1489
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
1490
|
+
className: MemoryView_module_css_default.title,
|
|
1491
|
+
children: t("memoryTitle")
|
|
1492
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1493
|
+
className: MemoryView_module_css_default.headMeta,
|
|
1494
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1495
|
+
className: MemoryView_module_css_default.updated,
|
|
1496
|
+
children: t("memoryUpdatedAt", { time: formatTime(payload?.updatedAt ?? 0) })
|
|
1497
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1498
|
+
type: "button",
|
|
1499
|
+
className: MemoryView_module_css_default.refresh,
|
|
1500
|
+
onClick: () => {
|
|
1501
|
+
load(true);
|
|
1502
|
+
},
|
|
1503
|
+
children: t("memoryRefresh")
|
|
1504
|
+
})]
|
|
1505
|
+
})]
|
|
1506
|
+
}),
|
|
1507
|
+
error !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1508
|
+
className: MemoryView_module_css_default.error,
|
|
1509
|
+
role: "status",
|
|
1510
|
+
children: t("memoryLoadFailed", { message: error })
|
|
1511
|
+
}) : null,
|
|
1512
|
+
loading && payload === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1513
|
+
className: MemoryView_module_css_default.status,
|
|
1514
|
+
children: t("memoryLoading")
|
|
1515
|
+
}) : session === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1516
|
+
className: MemoryView_module_css_default.status,
|
|
1517
|
+
children: t("memoryNoSnapshot")
|
|
1518
|
+
}) : !session.known ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1519
|
+
className: MemoryView_module_css_default.status,
|
|
1520
|
+
children: t("memoryUnknown")
|
|
1521
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("section", {
|
|
1522
|
+
className: MemoryView_module_css_default.group,
|
|
1523
|
+
"aria-label": t("memoryTitle"),
|
|
1524
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dl", {
|
|
1525
|
+
className: MemoryView_module_css_default.rows,
|
|
1526
|
+
children: [
|
|
1527
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1528
|
+
className: MemoryView_module_css_default.row,
|
|
1529
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
1530
|
+
className: MemoryView_module_css_default.label,
|
|
1531
|
+
children: t("memoryLogged")
|
|
1532
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
1533
|
+
className: MemoryView_module_css_default.value,
|
|
1534
|
+
children: t("memorySeqValue", { seq: String(session.loggedSeq) })
|
|
1535
|
+
})]
|
|
1536
|
+
}),
|
|
1537
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1538
|
+
className: MemoryView_module_css_default.row,
|
|
1539
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
1540
|
+
className: MemoryView_module_css_default.label,
|
|
1541
|
+
children: t("memoryConsolidated")
|
|
1542
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("dd", {
|
|
1543
|
+
className: MemoryView_module_css_default.value,
|
|
1544
|
+
children: [t("memorySeqValue", { seq: String(session.consolidatedSeq) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1545
|
+
className: session.caughtUp ? MemoryView_module_css_default.calm : MemoryView_module_css_default.busy,
|
|
1546
|
+
children: session.caughtUp ? t("memoryCaughtUp") : t("memoryBehind", { behind: String(consolidationGap(session)) })
|
|
1547
|
+
})]
|
|
1548
|
+
})]
|
|
1549
|
+
}),
|
|
1550
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1551
|
+
className: MemoryView_module_css_default.row,
|
|
1552
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
1553
|
+
className: MemoryView_module_css_default.label,
|
|
1554
|
+
children: t("memoryPending")
|
|
1555
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
1556
|
+
className: MemoryView_module_css_default.value,
|
|
1557
|
+
children: t("memoryPendingValue", { tokens: String(session.pendingTokens) })
|
|
1558
|
+
})]
|
|
1559
|
+
}),
|
|
1560
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1561
|
+
className: MemoryView_module_css_default.row,
|
|
1562
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
1563
|
+
className: MemoryView_module_css_default.label,
|
|
1564
|
+
children: t("memorySessionNode")
|
|
1565
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
1566
|
+
className: MemoryView_module_css_default.value,
|
|
1567
|
+
children: session.sessionNode ? t("memorySessionNodeYes") : t("memorySessionNodeNo")
|
|
1568
|
+
})]
|
|
1569
|
+
}),
|
|
1570
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1571
|
+
className: MemoryView_module_css_default.row,
|
|
1572
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
1573
|
+
className: MemoryView_module_css_default.label,
|
|
1574
|
+
children: t("memoryBelongTo")
|
|
1575
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
1576
|
+
className: MemoryView_module_css_default.value,
|
|
1577
|
+
children: t("memoryBelongToValue", { count: String(session.belongTo) })
|
|
1578
|
+
})]
|
|
1579
|
+
}),
|
|
1580
|
+
session.deferred > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1581
|
+
className: MemoryView_module_css_default.row,
|
|
1582
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("dt", {
|
|
1583
|
+
className: MemoryView_module_css_default.label,
|
|
1584
|
+
children: t("memoryDeferred")
|
|
1585
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("dd", {
|
|
1586
|
+
className: MemoryView_module_css_default.value,
|
|
1587
|
+
children: String(session.deferred)
|
|
1588
|
+
})]
|
|
1589
|
+
}) : null
|
|
1590
|
+
]
|
|
1591
|
+
})
|
|
1592
|
+
}),
|
|
1593
|
+
session !== void 0 && (session.failed > 0 || session.failedTasks.length > 0) ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1594
|
+
className: MemoryView_module_css_default.group,
|
|
1595
|
+
"aria-label": t("memoryFailedTitle"),
|
|
1596
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1597
|
+
className: MemoryView_module_css_default.groupTitle,
|
|
1598
|
+
children: t("memoryFailedTitle")
|
|
1599
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
1600
|
+
className: MemoryView_module_css_default.failures,
|
|
1601
|
+
children: [session.failedTasks.map((task, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
|
|
1602
|
+
className: MemoryView_module_css_default.failure,
|
|
1603
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1604
|
+
className: MemoryView_module_css_default.failureKind,
|
|
1605
|
+
children: t("memoryFailedItem", {
|
|
1606
|
+
kind: task.kind,
|
|
1607
|
+
attempts: String(task.attempts)
|
|
1608
|
+
})
|
|
1609
|
+
}), task.error !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1610
|
+
className: MemoryView_module_css_default.failureError,
|
|
1611
|
+
children: task.error
|
|
1612
|
+
}) : null]
|
|
1613
|
+
}, `${task.kind}-${String(index)}`)), session.failedTasks.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
1614
|
+
className: MemoryView_module_css_default.failure,
|
|
1615
|
+
children: session.error
|
|
1616
|
+
}) : null]
|
|
1617
|
+
})]
|
|
1618
|
+
}) : null,
|
|
1619
|
+
content !== void 0 && content.error !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1620
|
+
className: MemoryView_module_css_default.group,
|
|
1621
|
+
"aria-label": t("memoryContentTitle"),
|
|
1622
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
|
|
1623
|
+
className: MemoryView_module_css_default.groupTitle,
|
|
1624
|
+
children: t("memoryContentTitle")
|
|
1625
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1626
|
+
className: MemoryView_module_css_default.error,
|
|
1627
|
+
role: "status",
|
|
1628
|
+
children: t("memoryContentFailed", { message: content.error })
|
|
1629
|
+
})]
|
|
1630
|
+
}) : null,
|
|
1631
|
+
content !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
|
|
1632
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1633
|
+
className: MemoryView_module_css_default.group,
|
|
1634
|
+
"aria-label": t("memorySummariesTitle"),
|
|
1635
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
|
|
1636
|
+
className: MemoryView_module_css_default.groupTitle,
|
|
1637
|
+
children: [t("memorySummariesTitle"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1638
|
+
className: MemoryView_module_css_default.count,
|
|
1639
|
+
children: t("memoryCount", {
|
|
1640
|
+
shown: String(summaries.length),
|
|
1641
|
+
total: String(content.summaryCount)
|
|
1642
|
+
})
|
|
1643
|
+
})]
|
|
1644
|
+
}), summaries.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1645
|
+
className: MemoryView_module_css_default.status,
|
|
1646
|
+
children: t("memoryNoSummaries")
|
|
1647
|
+
}) : renderEntries(summaries, "summary")]
|
|
1648
|
+
}),
|
|
1649
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1650
|
+
className: MemoryView_module_css_default.group,
|
|
1651
|
+
"aria-label": t("memoryWorkUnitsTitle"),
|
|
1652
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h3", {
|
|
1653
|
+
className: MemoryView_module_css_default.groupTitle,
|
|
1654
|
+
children: [t("memoryWorkUnitsTitle"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1655
|
+
className: MemoryView_module_css_default.count,
|
|
1656
|
+
children: t("memoryCount", {
|
|
1657
|
+
shown: String(workUnits.length),
|
|
1658
|
+
total: String(content.workUnitCount)
|
|
1659
|
+
})
|
|
1660
|
+
})]
|
|
1661
|
+
}), workUnits.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1662
|
+
className: MemoryView_module_css_default.status,
|
|
1663
|
+
children: t("memoryNoWorkUnits")
|
|
1664
|
+
}) : renderEntries(workUnits, "workUnit")]
|
|
1665
|
+
}),
|
|
1666
|
+
content.truncated ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1667
|
+
className: MemoryView_module_css_default.hint,
|
|
1668
|
+
children: t("memoryTruncated")
|
|
1669
|
+
}) : null,
|
|
1670
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
1671
|
+
className: MemoryView_module_css_default.hint,
|
|
1672
|
+
children: t("memoryHint")
|
|
1673
|
+
})
|
|
1674
|
+
] }) : null
|
|
1675
|
+
]
|
|
1676
|
+
})
|
|
1677
|
+
});
|
|
1678
|
+
}
|
|
1679
|
+
//#endregion
|
|
1010
1680
|
//#region src/client/index.tsx
|
|
1011
1681
|
const APPLY_CLAIM = "__dshHypatiaAutoMemoryApplied";
|
|
1012
1682
|
function claimApply() {
|
|
@@ -1066,8 +1736,18 @@ window.__ModuleLoader__.load({
|
|
|
1066
1736
|
key: NS,
|
|
1067
1737
|
locale: NS
|
|
1068
1738
|
}, renderCard));
|
|
1739
|
+
const t = locale.bind(NS);
|
|
1740
|
+
const unregisterMemoryView = ctx.slots.inject("conversation.view", () => ctx.slots.register({
|
|
1741
|
+
name: "conversation.view",
|
|
1742
|
+
id: "memory",
|
|
1743
|
+
order: 20,
|
|
1744
|
+
locale: NS,
|
|
1745
|
+
label: () => t("viewMemory"),
|
|
1746
|
+
inject: () => ({ fetch: fetchMemory })
|
|
1747
|
+
}, MemoryView));
|
|
1069
1748
|
ctx.effect(() => () => {
|
|
1070
1749
|
unregister();
|
|
1750
|
+
unregisterMemoryView();
|
|
1071
1751
|
releaseApply();
|
|
1072
1752
|
});
|
|
1073
1753
|
}
|