@design.estate/dees-catalog 6.7.1 → 6.8.1
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_bundle/bundle.js +1034 -101
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.d.ts +2 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.js +32 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.d.ts +92 -6
- package/dist_ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.js +921 -49
- package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.d.ts +5 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.js +42 -7
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.d.ts +6 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.js +53 -14
- package/dist_ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.d.ts +2 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.js +13 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.d.ts +1 -0
- package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.js +10 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.js +9 -3
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +6 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +124 -6
- package/dist_ts_web/elements/00group-harness/interfaces.d.ts +30 -0
- package/dist_ts_web/elements/00group-harness/toolregistry.d.ts +2 -0
- package/dist_ts_web/elements/00group-harness/toolregistry.js +7 -1
- package/package.json +1 -1
- package/readme.md +4 -2
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.ts +28 -1
- package/ts_web/elements/00group-harness/dees-harness-message-list/dees-harness-message-list.ts +943 -51
- package/ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.ts +37 -8
- package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.ts +40 -12
- package/ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.ts +6 -2
- package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts +18 -2
- package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts +8 -2
- package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +108 -4
- package/ts_web/elements/00group-harness/interfaces.ts +34 -0
- package/ts_web/elements/00group-harness/toolregistry.ts +7 -0
package/ts_web/elements/00group-harness/dees-harness-permission-card/dees-harness-permission-card.ts
CHANGED
|
@@ -10,7 +10,11 @@ import {
|
|
|
10
10
|
cssManager,
|
|
11
11
|
} from '@design.estate/dees-element';
|
|
12
12
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
13
|
-
import type {
|
|
13
|
+
import type {
|
|
14
|
+
IHarnessPermissionRequest,
|
|
15
|
+
IHarnessPermissionViewState,
|
|
16
|
+
THarnessPermissionResponse,
|
|
17
|
+
} from '../interfaces.js';
|
|
14
18
|
import { harnessStringifyValue } from '../harness.helpers.js';
|
|
15
19
|
import '../../00group-button/dees-button/dees-button.js';
|
|
16
20
|
import '../../00group-feedback/dees-badge/dees-badge.js';
|
|
@@ -45,6 +49,12 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
45
49
|
@property({ type: Boolean })
|
|
46
50
|
accessor busy: boolean = false;
|
|
47
51
|
|
|
52
|
+
@property({ attribute: false })
|
|
53
|
+
accessor viewState: IHarnessPermissionViewState | undefined = undefined;
|
|
54
|
+
|
|
55
|
+
@property({ type: Boolean })
|
|
56
|
+
accessor suppressEntry: boolean = false;
|
|
57
|
+
|
|
48
58
|
@state()
|
|
49
59
|
accessor remember: boolean = false;
|
|
50
60
|
|
|
@@ -53,7 +63,11 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
53
63
|
accessor answered: THarnessPermissionResponse | undefined = undefined;
|
|
54
64
|
|
|
55
65
|
public get effectiveResponse(): THarnessPermissionResponse | undefined {
|
|
56
|
-
return this.request.response ?? this.answered;
|
|
66
|
+
return this.request.response ?? this.answered ?? this.viewState?.answered;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private get effectiveRemember(): boolean {
|
|
70
|
+
return this.remember || this.viewState?.remember === true;
|
|
57
71
|
}
|
|
58
72
|
|
|
59
73
|
public static styles = [
|
|
@@ -82,6 +96,10 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
82
96
|
}
|
|
83
97
|
}
|
|
84
98
|
|
|
99
|
+
:host(.no-entry) {
|
|
100
|
+
animation: none;
|
|
101
|
+
}
|
|
102
|
+
|
|
85
103
|
@media (prefers-reduced-motion: reduce) {
|
|
86
104
|
:host {
|
|
87
105
|
animation: none;
|
|
@@ -183,7 +201,7 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
183
201
|
: ''}
|
|
184
202
|
<div class="actions">
|
|
185
203
|
${this.effectiveResponse
|
|
186
|
-
? html`<span class="answeredNote">Answered: ${this.effectiveResponse}${this.
|
|
204
|
+
? html`<span class="answeredNote">Answered: ${this.effectiveResponse}${this.effectiveRemember ? ' (remembered)' : ''}</span>`
|
|
187
205
|
: html`
|
|
188
206
|
<dees-button type="accent" size="sm" ?disabled=${disabled} @clicked=${() => this.respond('once')}>
|
|
189
207
|
Allow Once
|
|
@@ -197,11 +215,12 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
197
215
|
<label class="rememberLabel">
|
|
198
216
|
<input
|
|
199
217
|
type="checkbox"
|
|
200
|
-
.checked=${this.
|
|
218
|
+
.checked=${this.effectiveRemember}
|
|
201
219
|
?disabled=${disabled}
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
220
|
+
@change=${(event: Event) => {
|
|
221
|
+
this.remember = (event.currentTarget as HTMLInputElement).checked;
|
|
222
|
+
if (this.viewState) this.viewState.remember = this.remember;
|
|
223
|
+
}}
|
|
205
224
|
/>
|
|
206
225
|
remember for this session
|
|
207
226
|
</label>
|
|
@@ -213,13 +232,18 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
213
232
|
|
|
214
233
|
private respond(response: THarnessPermissionResponse): void {
|
|
215
234
|
if (this.busy || this.effectiveResponse !== undefined) return;
|
|
235
|
+
const remember = this.effectiveRemember || response === 'always';
|
|
216
236
|
this.answered = response;
|
|
237
|
+
if (this.viewState) {
|
|
238
|
+
this.viewState.answered = response;
|
|
239
|
+
this.viewState.remember = remember;
|
|
240
|
+
}
|
|
217
241
|
this.dispatchEvent(
|
|
218
242
|
new CustomEvent('harness-permission-response', {
|
|
219
243
|
detail: {
|
|
220
244
|
requestId: this.request.id,
|
|
221
245
|
response,
|
|
222
|
-
remember
|
|
246
|
+
remember,
|
|
223
247
|
request: this.request,
|
|
224
248
|
},
|
|
225
249
|
bubbles: true,
|
|
@@ -227,4 +251,9 @@ export class DeesHarnessPermissionCard extends DeesElement {
|
|
|
227
251
|
}),
|
|
228
252
|
);
|
|
229
253
|
}
|
|
254
|
+
|
|
255
|
+
public firstUpdated(changedPropertiesArg: Map<string, unknown>): void {
|
|
256
|
+
super.firstUpdated(changedPropertiesArg);
|
|
257
|
+
if (this.suppressEntry) this.classList.add('no-entry');
|
|
258
|
+
}
|
|
230
259
|
}
|
package/ts_web/elements/00group-harness/dees-harness-question-card/dees-harness-question-card.ts
CHANGED
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
cssManager,
|
|
11
11
|
} from '@design.estate/dees-element';
|
|
12
12
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
13
|
-
import type { IHarnessQuestionRequest } from '../interfaces.js';
|
|
13
|
+
import type { IHarnessQuestionRequest, IHarnessQuestionViewState } from '../interfaces.js';
|
|
14
14
|
import '../../00group-button/dees-button/dees-button.js';
|
|
15
15
|
import '../../00group-utility/dees-icon/dees-icon.js';
|
|
16
16
|
|
|
@@ -38,6 +38,12 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
38
38
|
@property({ type: Boolean })
|
|
39
39
|
accessor busy: boolean = false;
|
|
40
40
|
|
|
41
|
+
@property({ attribute: false })
|
|
42
|
+
accessor viewState: IHarnessQuestionViewState | undefined = undefined;
|
|
43
|
+
|
|
44
|
+
@property({ type: Boolean })
|
|
45
|
+
accessor suppressEntry: boolean = false;
|
|
46
|
+
|
|
41
47
|
/** local optimistic answer; request.response (host echo) takes precedence */
|
|
42
48
|
@state()
|
|
43
49
|
accessor answered: string[] | undefined = undefined;
|
|
@@ -49,7 +55,17 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
49
55
|
accessor customText: string = '';
|
|
50
56
|
|
|
51
57
|
public get effectiveResponse(): string[] | undefined {
|
|
52
|
-
return this.request.response ?? this.answered;
|
|
58
|
+
return this.request.response ?? this.answered ?? this.viewState?.answered;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private get effectiveSelected(): ReadonlySet<string> {
|
|
62
|
+
return this.selected.size > 0
|
|
63
|
+
? this.selected
|
|
64
|
+
: new Set(this.viewState?.selected ?? []);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
private get effectiveCustomText(): string {
|
|
68
|
+
return this.customText || this.viewState?.customText || '';
|
|
53
69
|
}
|
|
54
70
|
|
|
55
71
|
public static styles = [
|
|
@@ -72,6 +88,10 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
72
88
|
}
|
|
73
89
|
}
|
|
74
90
|
|
|
91
|
+
:host(.no-entry) {
|
|
92
|
+
animation: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
75
95
|
@media (prefers-reduced-motion: reduce) {
|
|
76
96
|
:host {
|
|
77
97
|
animation: none;
|
|
@@ -230,7 +250,7 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
230
250
|
<div class="options" role=${request.multiSelect ? 'group' : 'radiogroup'}>
|
|
231
251
|
${request.options.map((option) => html`
|
|
232
252
|
<button
|
|
233
|
-
class="option ${this.
|
|
253
|
+
class="option ${this.effectiveSelected.has(option.label) ? 'selected' : ''}"
|
|
234
254
|
type="button"
|
|
235
255
|
?disabled=${disabled}
|
|
236
256
|
@click=${() => this.handleOptionClick(option.label)}
|
|
@@ -249,23 +269,24 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
249
269
|
<div class="customRow">
|
|
250
270
|
<input
|
|
251
271
|
placeholder="Answer in your own words…"
|
|
252
|
-
.value=${this.
|
|
272
|
+
.value=${this.effectiveCustomText}
|
|
253
273
|
?disabled=${disabled}
|
|
254
274
|
@input=${(event: Event) => {
|
|
255
275
|
this.customText = (event.currentTarget as HTMLInputElement).value;
|
|
276
|
+
if (this.viewState) this.viewState.customText = this.customText;
|
|
256
277
|
}}
|
|
257
278
|
@keydown=${(event: KeyboardEvent) => {
|
|
258
|
-
if (event.key === 'Enter' && this.
|
|
259
|
-
this.respond([...this.
|
|
279
|
+
if (event.key === 'Enter' && this.effectiveCustomText.trim()) {
|
|
280
|
+
this.respond([...this.effectiveSelected, this.effectiveCustomText.trim()]);
|
|
260
281
|
}
|
|
261
282
|
}}
|
|
262
283
|
/>
|
|
263
284
|
<dees-button
|
|
264
285
|
size="sm"
|
|
265
|
-
?disabled=${disabled || (!this.
|
|
286
|
+
?disabled=${disabled || (!this.effectiveCustomText.trim() && !this.effectiveSelected.size)}
|
|
266
287
|
@clicked=${() => {
|
|
267
|
-
const answers = [...this.
|
|
268
|
-
if (this.
|
|
288
|
+
const answers = [...this.effectiveSelected];
|
|
289
|
+
if (this.effectiveCustomText.trim()) answers.push(this.effectiveCustomText.trim());
|
|
269
290
|
this.respond(answers);
|
|
270
291
|
}}
|
|
271
292
|
>Send Answer</dees-button>
|
|
@@ -278,8 +299,8 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
278
299
|
<dees-button
|
|
279
300
|
type="accent"
|
|
280
301
|
size="sm"
|
|
281
|
-
?disabled=${disabled || !this.
|
|
282
|
-
@clicked=${() => this.respond([...this.
|
|
302
|
+
?disabled=${disabled || !this.effectiveSelected.size}
|
|
303
|
+
@clicked=${() => this.respond([...this.effectiveSelected])}
|
|
283
304
|
>Confirm</dees-button>
|
|
284
305
|
</div>
|
|
285
306
|
`
|
|
@@ -292,10 +313,11 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
292
313
|
private handleOptionClick(label: string): void {
|
|
293
314
|
if (this.busy || this.effectiveResponse !== undefined) return;
|
|
294
315
|
if (this.request.multiSelect) {
|
|
295
|
-
const next = new Set(this.
|
|
316
|
+
const next = new Set(this.effectiveSelected);
|
|
296
317
|
if (next.has(label)) next.delete(label);
|
|
297
318
|
else next.add(label);
|
|
298
319
|
this.selected = next;
|
|
320
|
+
if (this.viewState) this.viewState.selected = [...next];
|
|
299
321
|
return;
|
|
300
322
|
}
|
|
301
323
|
this.respond([label]);
|
|
@@ -304,6 +326,7 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
304
326
|
private respond(answers: string[]): void {
|
|
305
327
|
if (this.busy || this.effectiveResponse !== undefined || !answers.length) return;
|
|
306
328
|
this.answered = answers;
|
|
329
|
+
if (this.viewState) this.viewState.answered = answers;
|
|
307
330
|
this.dispatchEvent(
|
|
308
331
|
new CustomEvent('harness-question-response', {
|
|
309
332
|
detail: {
|
|
@@ -316,4 +339,9 @@ export class DeesHarnessQuestionCard extends DeesElement {
|
|
|
316
339
|
}),
|
|
317
340
|
);
|
|
318
341
|
}
|
|
342
|
+
|
|
343
|
+
public firstUpdated(changedPropertiesArg: Map<string, unknown>): void {
|
|
344
|
+
super.firstUpdated(changedPropertiesArg);
|
|
345
|
+
if (this.suppressEntry) this.classList.add('no-entry');
|
|
346
|
+
}
|
|
319
347
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
cssManager,
|
|
11
11
|
} from '@design.estate/dees-element';
|
|
12
12
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
13
|
-
import type { IHarnessReasoningPart } from '../interfaces.js';
|
|
13
|
+
import type { IHarnessMessageViewState, IHarnessReasoningPart } from '../interfaces.js';
|
|
14
14
|
import { harnessFormatDuration } from '../harness.helpers.js';
|
|
15
15
|
import '../../00group-utility/dees-icon/dees-icon.js';
|
|
16
16
|
|
|
@@ -37,6 +37,9 @@ export class DeesHarnessReasoning extends DeesElement {
|
|
|
37
37
|
@property({ attribute: false })
|
|
38
38
|
accessor reasoningParts: IHarnessReasoningPart[] = [];
|
|
39
39
|
|
|
40
|
+
@property({ attribute: false })
|
|
41
|
+
accessor viewState: IHarnessMessageViewState | undefined = undefined;
|
|
42
|
+
|
|
40
43
|
@state()
|
|
41
44
|
accessor expanded: boolean | undefined = undefined;
|
|
42
45
|
|
|
@@ -178,7 +181,7 @@ export class DeesHarnessReasoning extends DeesElement {
|
|
|
178
181
|
}
|
|
179
182
|
|
|
180
183
|
public get isOpen(): boolean {
|
|
181
|
-
return this.expanded ?? this.isStreaming;
|
|
184
|
+
return this.expanded ?? this.viewState?.reasoningExpanded ?? this.isStreaming;
|
|
182
185
|
}
|
|
183
186
|
|
|
184
187
|
/** All parts joined into the one full trace the expanded body shows. */
|
|
@@ -224,6 +227,7 @@ export class DeesHarnessReasoning extends DeesElement {
|
|
|
224
227
|
aria-expanded=${this.isOpen ? 'true' : 'false'}
|
|
225
228
|
@click=${() => {
|
|
226
229
|
this.expanded = !this.isOpen;
|
|
230
|
+
if (this.viewState) this.viewState.reasoningExpanded = this.expanded;
|
|
227
231
|
}}
|
|
228
232
|
>
|
|
229
233
|
<span class="chevron ${this.isOpen ? 'open' : ''}">
|
package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts
CHANGED
|
@@ -65,6 +65,7 @@ interface IResourcePointerDragGesture {
|
|
|
65
65
|
source: HTMLElement;
|
|
66
66
|
resourceId: string;
|
|
67
67
|
fromSessionId: string | null;
|
|
68
|
+
eligibleSessionIds: ReadonlySet<string>;
|
|
68
69
|
startClientX: number;
|
|
69
70
|
startClientY: number;
|
|
70
71
|
grabOffsetX: number;
|
|
@@ -1196,9 +1197,18 @@ export class DeesHarnessSessionList extends DeesElement {
|
|
|
1196
1197
|
) this.closeResourceContext(this.resourceContextGeneration);
|
|
1197
1198
|
this.reconcilePendingResourceAssociation();
|
|
1198
1199
|
}
|
|
1199
|
-
if (
|
|
1200
|
+
if (
|
|
1201
|
+
changedProperties.has('sessions')
|
|
1202
|
+
|| changedProperties.has('eligibleSessionIdsByResourceId')
|
|
1203
|
+
) {
|
|
1200
1204
|
const gesture = this.pointerDragGesture;
|
|
1201
|
-
if (
|
|
1205
|
+
if (
|
|
1206
|
+
gesture?.type === 'resource'
|
|
1207
|
+
&& !this.sameSessionIds(
|
|
1208
|
+
gesture.eligibleSessionIds,
|
|
1209
|
+
new Set(this.eligibleSessionIds(gesture.resourceId)),
|
|
1210
|
+
)
|
|
1211
|
+
) this.finishPointerDrag(false);
|
|
1202
1212
|
}
|
|
1203
1213
|
}
|
|
1204
1214
|
|
|
@@ -1832,6 +1842,7 @@ export class DeesHarnessSessionList extends DeesElement {
|
|
|
1832
1842
|
source,
|
|
1833
1843
|
resourceId: resourceArg.id,
|
|
1834
1844
|
fromSessionId: fromSessionIdArg,
|
|
1845
|
+
eligibleSessionIds: new Set(this.eligibleSessionIds(resourceArg.id)),
|
|
1835
1846
|
startClientX: eventArg.clientX,
|
|
1836
1847
|
startClientY: eventArg.clientY,
|
|
1837
1848
|
grabOffsetX: eventArg.clientX - sourceRect.left,
|
|
@@ -2316,6 +2327,11 @@ export class DeesHarnessSessionList extends DeesElement {
|
|
|
2316
2327
|
return result;
|
|
2317
2328
|
}
|
|
2318
2329
|
|
|
2330
|
+
private sameSessionIds(firstArg: ReadonlySet<string>, secondArg: ReadonlySet<string>): boolean {
|
|
2331
|
+
return firstArg.size === secondArg.size
|
|
2332
|
+
&& [...firstArg].every((sessionId) => secondArg.has(sessionId));
|
|
2333
|
+
}
|
|
2334
|
+
|
|
2319
2335
|
private isResourceTargetEligible(resourceIdArg: string, sessionIdArg: string): boolean {
|
|
2320
2336
|
return this.eligibleSessionIds(resourceIdArg).includes(sessionIdArg);
|
|
2321
2337
|
}
|
package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts
CHANGED
|
@@ -694,8 +694,14 @@ export class DeesHarnessSessionSidebar extends DeesElement {
|
|
|
694
694
|
<span class="sectionHeadingText">${labelArg}</span>
|
|
695
695
|
${summaryArg ? html`<span class="sectionSummary">${summaryArg}</span>` : ''}
|
|
696
696
|
</button>
|
|
697
|
-
<div
|
|
698
|
-
|
|
697
|
+
<div
|
|
698
|
+
id=${contentId}
|
|
699
|
+
class="sectionContent"
|
|
700
|
+
role="region"
|
|
701
|
+
aria-hidden=${String(!expanded)}
|
|
702
|
+
?hidden=${!expanded}
|
|
703
|
+
>
|
|
704
|
+
${expanded ? contentArg : ''}
|
|
699
705
|
</div>
|
|
700
706
|
</section>
|
|
701
707
|
`;
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
} from '@design.estate/dees-element';
|
|
12
12
|
import { themeDefaultStyles } from '../../00theme.js';
|
|
13
13
|
import type {
|
|
14
|
+
IHarnessMessageViewState,
|
|
14
15
|
IHarnessToolCall,
|
|
15
16
|
THarnessContentBlock,
|
|
16
17
|
THarnessMessageStreamDelta,
|
|
@@ -69,6 +70,9 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
69
70
|
@property({ type: Boolean })
|
|
70
71
|
accessor allowSubtaskStreams: boolean = true;
|
|
71
72
|
|
|
73
|
+
@property({ attribute: false })
|
|
74
|
+
accessor viewState: IHarnessMessageViewState | undefined = undefined;
|
|
75
|
+
|
|
72
76
|
@state()
|
|
73
77
|
accessor expanded: boolean | undefined = undefined;
|
|
74
78
|
|
|
@@ -102,9 +106,12 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
102
106
|
private observedBodyInner: Element | null = null;
|
|
103
107
|
private fullscreenPortal: HTMLElementTagNameMap['dees-harness-tool-fullscreen'] | null = null;
|
|
104
108
|
private disclosureFrame: number | null = null;
|
|
109
|
+
private returnScrollFrame: number | null = null;
|
|
105
110
|
private subtaskResultElement: HTMLElement | null = null;
|
|
106
111
|
private subtaskResultResizeObserver: ResizeObserver | null = null;
|
|
107
112
|
private terminalTailFollowing = true;
|
|
113
|
+
private terminalScrollHydrated = false;
|
|
114
|
+
private terminalScrollHydrationFrame: number | null = null;
|
|
108
115
|
private terminalTailReturnTimeout: ReturnType<typeof setTimeout> | null = null;
|
|
109
116
|
private terminalTailReturnDelayMs = 5000;
|
|
110
117
|
|
|
@@ -669,6 +676,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
669
676
|
|
|
670
677
|
public get isOpen(): boolean {
|
|
671
678
|
if (this.expanded !== undefined) return this.expanded;
|
|
679
|
+
if (this.viewState?.toolExpanded !== undefined) return this.viewState.toolExpanded;
|
|
672
680
|
const descriptor = this.descriptor;
|
|
673
681
|
if (descriptor.kind === 'subtask' && this.call.subtask) {
|
|
674
682
|
return this.allowSubtaskStreams
|
|
@@ -778,12 +786,14 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
778
786
|
if (this.disclosureFrame !== null) cancelAnimationFrame(this.disclosureFrame);
|
|
779
787
|
this.disclosureFrame = null;
|
|
780
788
|
this.expanded = false;
|
|
789
|
+
if (this.viewState) this.viewState.toolExpanded = false;
|
|
781
790
|
return;
|
|
782
791
|
}
|
|
783
792
|
if (this.bodyMounted) {
|
|
784
793
|
if (this.disclosureFrame !== null) cancelAnimationFrame(this.disclosureFrame);
|
|
785
794
|
this.disclosureFrame = null;
|
|
786
795
|
this.expanded = true;
|
|
796
|
+
if (this.viewState) this.viewState.toolExpanded = true;
|
|
787
797
|
return;
|
|
788
798
|
}
|
|
789
799
|
this.bodyMounted = true;
|
|
@@ -795,12 +805,18 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
795
805
|
if (!this.isConnected || this.expanded !== false) return;
|
|
796
806
|
this.shadowRoot?.querySelector<HTMLElement>('.bodyDisclosure')?.getBoundingClientRect();
|
|
797
807
|
this.expanded = true;
|
|
808
|
+
if (this.viewState) this.viewState.toolExpanded = true;
|
|
798
809
|
});
|
|
799
810
|
});
|
|
800
811
|
};
|
|
801
812
|
|
|
802
813
|
private readonly openFullscreen = (): void => {
|
|
803
814
|
if (this.fullscreenPortal || this.hasSubtaskPreview) return;
|
|
815
|
+
this.dispatchEvent(new CustomEvent('harness-card-retention', {
|
|
816
|
+
detail: { active: true },
|
|
817
|
+
bubbles: true,
|
|
818
|
+
composed: true,
|
|
819
|
+
}));
|
|
804
820
|
// Appended to document.body: content-visibility containment in the
|
|
805
821
|
// transcript would trap a position: fixed layer inside this card.
|
|
806
822
|
const portal = document.createElement('dees-harness-tool-fullscreen');
|
|
@@ -830,7 +846,10 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
830
846
|
// reduced-motion skips the animation, so animationend never fires there
|
|
831
847
|
if (this.flashFallbackTimeout) clearTimeout(this.flashFallbackTimeout);
|
|
832
848
|
this.flashFallbackTimeout = setTimeout(() => this.endReturnFlash(), 900);
|
|
833
|
-
|
|
849
|
+
if (this.returnScrollFrame !== null) cancelAnimationFrame(this.returnScrollFrame);
|
|
850
|
+
this.returnScrollFrame = requestAnimationFrame(() => {
|
|
851
|
+
this.returnScrollFrame = null;
|
|
852
|
+
if (!this.isConnected) return;
|
|
834
853
|
this.scrollIntoView({ block: 'center', behavior: 'smooth' });
|
|
835
854
|
});
|
|
836
855
|
};
|
|
@@ -842,6 +861,11 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
842
861
|
}
|
|
843
862
|
if (!this.returnFlash) return;
|
|
844
863
|
this.returnFlash = false;
|
|
864
|
+
this.dispatchEvent(new CustomEvent('harness-card-retention', {
|
|
865
|
+
detail: { active: false },
|
|
866
|
+
bubbles: true,
|
|
867
|
+
composed: true,
|
|
868
|
+
}));
|
|
845
869
|
this.dispatchEvent(new CustomEvent('harness-card-flash', {
|
|
846
870
|
detail: { active: false },
|
|
847
871
|
bubbles: true,
|
|
@@ -865,11 +889,44 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
865
889
|
|
|
866
890
|
public willUpdate(changedProperties: Map<PropertyKey, unknown>): void {
|
|
867
891
|
super.willUpdate(changedProperties);
|
|
892
|
+
if (changedProperties.has('viewState') || changedProperties.has('call')) {
|
|
893
|
+
this.terminalScrollHydrated = false;
|
|
894
|
+
if (this.terminalScrollHydrationFrame !== null) {
|
|
895
|
+
cancelAnimationFrame(this.terminalScrollHydrationFrame);
|
|
896
|
+
this.terminalScrollHydrationFrame = null;
|
|
897
|
+
}
|
|
898
|
+
if (this.expanded === undefined && this.viewState?.toolExpanded !== undefined) {
|
|
899
|
+
this.expanded = this.viewState.toolExpanded;
|
|
900
|
+
}
|
|
901
|
+
if (!this.outputExpanded && this.viewState?.toolOutputExpanded === true) this.outputExpanded = true;
|
|
902
|
+
if (this.diffViewOverride === null && this.viewState?.toolDiffView !== undefined) {
|
|
903
|
+
this.diffViewOverride = this.viewState.toolDiffView;
|
|
904
|
+
}
|
|
905
|
+
if (this.viewState?.toolTerminalTailFollowing !== undefined) {
|
|
906
|
+
this.terminalTailFollowing = this.viewState.toolTerminalTailFollowing;
|
|
907
|
+
}
|
|
908
|
+
if (this.viewState) {
|
|
909
|
+
const subtask = this.call.subtask;
|
|
910
|
+
const ownsLiveTranscript = Boolean(
|
|
911
|
+
this.hasLiveSubtaskPreview && subtask?.previewState === 'ready',
|
|
912
|
+
);
|
|
913
|
+
if (!subtask || !ownsLiveTranscript) {
|
|
914
|
+
delete this.viewState.subtaskTranscript;
|
|
915
|
+
delete this.viewState.subtaskTranscriptSessionId;
|
|
916
|
+
} else if (
|
|
917
|
+
this.viewState.subtaskTranscriptSessionId !== subtask.sessionId
|
|
918
|
+
|| !this.viewState.subtaskTranscript
|
|
919
|
+
) {
|
|
920
|
+
this.viewState.subtaskTranscriptSessionId = subtask.sessionId;
|
|
921
|
+
this.viewState.subtaskTranscript = { messages: {}, permissions: {}, questions: {} };
|
|
922
|
+
}
|
|
923
|
+
}
|
|
924
|
+
}
|
|
868
925
|
const previousCall = changedProperties.get('call') as IHarnessToolCall | undefined;
|
|
869
926
|
if (!previousCall) return;
|
|
870
927
|
if (previousCall.id !== this.call.id) {
|
|
871
|
-
this.diffViewOverride = null;
|
|
872
|
-
this.terminalTailFollowing = true;
|
|
928
|
+
this.diffViewOverride = this.viewState?.toolDiffView ?? null;
|
|
929
|
+
this.terminalTailFollowing = this.viewState?.toolTerminalTailFollowing ?? true;
|
|
873
930
|
this.cancelTerminalTailReturn();
|
|
874
931
|
return;
|
|
875
932
|
}
|
|
@@ -891,6 +948,10 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
891
948
|
public updated(changedProperties: Map<PropertyKey, unknown>): void {
|
|
892
949
|
super.updated(changedProperties);
|
|
893
950
|
if (!this.isConnected) return;
|
|
951
|
+
this.terminalScrollHydrationFrame ??= requestAnimationFrame(() => {
|
|
952
|
+
this.terminalScrollHydrationFrame = null;
|
|
953
|
+
if (this.isConnected) this.terminalScrollHydrated = true;
|
|
954
|
+
});
|
|
894
955
|
if (this.isOpen && !this.bodyMounted) this.bodyMounted = true;
|
|
895
956
|
if (changedProperties.has('call') && this.fullscreenPortal) {
|
|
896
957
|
this.fullscreenPortal.call = this.enrichedCall;
|
|
@@ -927,12 +988,21 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
927
988
|
});
|
|
928
989
|
this.bodyResizeObserver.observe(bodyInner);
|
|
929
990
|
if (this.terminalTailFollowing) this.scrollTerminalToTail();
|
|
991
|
+
else if (this.viewState?.toolTerminalScrollTop !== undefined) {
|
|
992
|
+
const frame = this.shadowRoot?.querySelector<HTMLElement>('.bodyClipFrame');
|
|
993
|
+
if (frame) this.setTerminalScrollTop(frame, this.viewState.toolTerminalScrollTop);
|
|
994
|
+
}
|
|
930
995
|
}
|
|
931
996
|
|
|
932
997
|
private readonly handleBodyScroll = (eventArg: Event): void => {
|
|
933
998
|
if (this.descriptor.kind !== 'terminal' || this.uncapped) return;
|
|
999
|
+
if (!this.terminalScrollHydrated) return;
|
|
934
1000
|
const frame = eventArg.currentTarget as HTMLElement;
|
|
935
1001
|
this.terminalTailFollowing = frame.scrollHeight - frame.scrollTop - frame.clientHeight <= 2;
|
|
1002
|
+
if (this.viewState) {
|
|
1003
|
+
this.viewState.toolTerminalTailFollowing = this.terminalTailFollowing;
|
|
1004
|
+
this.viewState.toolTerminalScrollTop = frame.scrollTop;
|
|
1005
|
+
}
|
|
936
1006
|
if (this.terminalTailFollowing) this.cancelTerminalTailReturn();
|
|
937
1007
|
};
|
|
938
1008
|
|
|
@@ -940,7 +1010,16 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
940
1010
|
if (this.descriptor.kind !== 'terminal' || this.uncapped || !this.isOpen) return;
|
|
941
1011
|
const frame = this.shadowRoot?.querySelector<HTMLElement>('.bodyClipFrame');
|
|
942
1012
|
if (!frame) return;
|
|
943
|
-
|
|
1013
|
+
if (this.viewState?.toolTerminalTailFollowing === false) {
|
|
1014
|
+
this.terminalTailFollowing = false;
|
|
1015
|
+
this.setTerminalScrollTop(frame, this.viewState.toolTerminalScrollTop ?? frame.scrollTop);
|
|
1016
|
+
return;
|
|
1017
|
+
}
|
|
1018
|
+
this.setTerminalScrollTop(frame, frame.scrollHeight);
|
|
1019
|
+
}
|
|
1020
|
+
|
|
1021
|
+
private setTerminalScrollTop(frameArg: HTMLElement, scrollTopArg: number): void {
|
|
1022
|
+
frameArg.scrollTop = scrollTopArg;
|
|
944
1023
|
}
|
|
945
1024
|
|
|
946
1025
|
private readonly scheduleTerminalTailReturn = (): void => {
|
|
@@ -949,7 +1028,12 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
949
1028
|
this.terminalTailReturnTimeout = setTimeout(() => {
|
|
950
1029
|
this.terminalTailReturnTimeout = null;
|
|
951
1030
|
this.terminalTailFollowing = true;
|
|
1031
|
+
if (this.viewState) this.viewState.toolTerminalTailFollowing = true;
|
|
952
1032
|
this.scrollTerminalToTail();
|
|
1033
|
+
if (this.viewState) {
|
|
1034
|
+
const frame = this.shadowRoot?.querySelector<HTMLElement>('.bodyClipFrame');
|
|
1035
|
+
if (frame) this.viewState.toolTerminalScrollTop = frame.scrollTop;
|
|
1036
|
+
}
|
|
953
1037
|
}, this.terminalTailReturnDelayMs);
|
|
954
1038
|
};
|
|
955
1039
|
|
|
@@ -961,6 +1045,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
961
1045
|
|
|
962
1046
|
private readonly handleDiffViewChange = (eventArg: CustomEvent<IDiffViewChangeDetail>): void => {
|
|
963
1047
|
this.diffViewOverride = eventArg.detail.diffView;
|
|
1048
|
+
if (this.viewState) this.viewState.toolDiffView = this.diffViewOverride;
|
|
964
1049
|
};
|
|
965
1050
|
|
|
966
1051
|
private readonly syncSubtaskResultScroll = (): void => {
|
|
@@ -1002,6 +1087,15 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
1002
1087
|
cancelAnimationFrame(this.disclosureFrame);
|
|
1003
1088
|
this.disclosureFrame = null;
|
|
1004
1089
|
}
|
|
1090
|
+
if (this.returnScrollFrame !== null) {
|
|
1091
|
+
cancelAnimationFrame(this.returnScrollFrame);
|
|
1092
|
+
this.returnScrollFrame = null;
|
|
1093
|
+
}
|
|
1094
|
+
if (this.terminalScrollHydrationFrame !== null) {
|
|
1095
|
+
cancelAnimationFrame(this.terminalScrollHydrationFrame);
|
|
1096
|
+
this.terminalScrollHydrationFrame = null;
|
|
1097
|
+
}
|
|
1098
|
+
this.terminalScrollHydrated = false;
|
|
1005
1099
|
if (this.flashFallbackTimeout) {
|
|
1006
1100
|
clearTimeout(this.flashFallbackTimeout);
|
|
1007
1101
|
this.flashFallbackTimeout = null;
|
|
@@ -1011,8 +1105,16 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
1011
1105
|
this.outcomeScanFallbackTimeout = null;
|
|
1012
1106
|
}
|
|
1013
1107
|
this.cancelTerminalTailReturn();
|
|
1108
|
+
if (this.fullscreenPortal || this.returnFlash) {
|
|
1109
|
+
this.dispatchEvent(new CustomEvent('harness-card-retention', {
|
|
1110
|
+
detail: { active: false },
|
|
1111
|
+
bubbles: true,
|
|
1112
|
+
composed: true,
|
|
1113
|
+
}));
|
|
1114
|
+
}
|
|
1014
1115
|
this.fullscreenPortal?.remove();
|
|
1015
1116
|
this.fullscreenPortal = null;
|
|
1117
|
+
this.returnFlash = false;
|
|
1016
1118
|
this.bodyResizeObserver?.disconnect();
|
|
1017
1119
|
this.bodyResizeObserver = null;
|
|
1018
1120
|
this.observedBodyInner = null;
|
|
@@ -1068,6 +1170,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
1068
1170
|
.questions=${subtask.questions ?? []}
|
|
1069
1171
|
.status=${subtask.status}
|
|
1070
1172
|
.toolRegistry=${this.toolRegistry}
|
|
1173
|
+
.viewState=${this.viewState?.subtaskTranscript}
|
|
1071
1174
|
.allowSubtaskStreams=${false}
|
|
1072
1175
|
.autoFollow=${this.isOpen}
|
|
1073
1176
|
.hideScrollbar=${true}
|
|
@@ -1164,6 +1267,7 @@ export class DeesHarnessToolCard extends DeesElement {
|
|
|
1164
1267
|
type="button"
|
|
1165
1268
|
@click=${() => {
|
|
1166
1269
|
this.outputExpanded = true;
|
|
1270
|
+
if (this.viewState) this.viewState.toolOutputExpanded = true;
|
|
1167
1271
|
}}
|
|
1168
1272
|
>
|
|
1169
1273
|
Show all
|
|
@@ -49,6 +49,40 @@ export interface IHarnessTranscriptOrder {
|
|
|
49
49
|
partIndex: number;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/** View state retained by a virtualized transcript while a message is unmounted. */
|
|
53
|
+
export interface IHarnessMessageViewState {
|
|
54
|
+
reasoningExpanded?: boolean;
|
|
55
|
+
markdownText?: string;
|
|
56
|
+
markdownHtml?: string;
|
|
57
|
+
toolExpanded?: boolean;
|
|
58
|
+
toolOutputExpanded?: boolean;
|
|
59
|
+
toolDiffView?: 'inline' | 'split' | null;
|
|
60
|
+
toolTerminalTailFollowing?: boolean;
|
|
61
|
+
toolTerminalScrollTop?: number;
|
|
62
|
+
subtaskTranscriptSessionId?: string;
|
|
63
|
+
subtaskTranscript?: IHarnessTranscriptViewState;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/** Optimistic permission state retained while a virtualized card is unmounted. */
|
|
67
|
+
export interface IHarnessPermissionViewState {
|
|
68
|
+
remember?: boolean;
|
|
69
|
+
answered?: THarnessPermissionResponse;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** In-progress question state retained while a virtualized card is unmounted. */
|
|
73
|
+
export interface IHarnessQuestionViewState {
|
|
74
|
+
answered?: string[];
|
|
75
|
+
selected?: string[];
|
|
76
|
+
customText?: string;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Complete interaction state for rows that a virtual transcript may evict. */
|
|
80
|
+
export interface IHarnessTranscriptViewState {
|
|
81
|
+
messages: Record<string, IHarnessMessageViewState>;
|
|
82
|
+
permissions: Record<string, IHarnessPermissionViewState>;
|
|
83
|
+
questions: Record<string, IHarnessQuestionViewState>;
|
|
84
|
+
}
|
|
85
|
+
|
|
52
86
|
/** Session-level token facts. Unknown metrics stay undefined. */
|
|
53
87
|
export interface IHarnessSessionMetrics {
|
|
54
88
|
/** Cumulative token usage across the complete session. */
|
|
@@ -239,6 +239,11 @@ export class DeesHarnessToolRegistry {
|
|
|
239
239
|
private descriptors: IHarnessToolDescriptor[] = [];
|
|
240
240
|
private byName = new Map<string, IHarnessToolDescriptor>();
|
|
241
241
|
private byKind = new Map<string, IHarnessToolDescriptor>();
|
|
242
|
+
private registryRevision = 0;
|
|
243
|
+
|
|
244
|
+
public get revision(): number {
|
|
245
|
+
return this.registryRevision;
|
|
246
|
+
}
|
|
242
247
|
|
|
243
248
|
constructor(seedDescriptors: IHarnessToolDescriptor[] = []) {
|
|
244
249
|
for (const descriptor of seedDescriptors) {
|
|
@@ -260,6 +265,7 @@ export class DeesHarnessToolRegistry {
|
|
|
260
265
|
for (const name of descriptor.names ?? []) {
|
|
261
266
|
this.byName.set(name.toLowerCase(), descriptor);
|
|
262
267
|
}
|
|
268
|
+
this.registryRevision += 1;
|
|
263
269
|
return this;
|
|
264
270
|
}
|
|
265
271
|
|
|
@@ -271,6 +277,7 @@ export class DeesHarnessToolRegistry {
|
|
|
271
277
|
for (const [name, mapped] of this.byName) {
|
|
272
278
|
if (mapped === existing) this.byName.delete(name);
|
|
273
279
|
}
|
|
280
|
+
this.registryRevision += 1;
|
|
274
281
|
return this;
|
|
275
282
|
}
|
|
276
283
|
|