@design.estate/dees-catalog 3.92.0 → 3.93.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/dist_bundle/bundle.js +212 -39
- package/dist_ts_web/00_commitinfo_data.js +1 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +10 -1
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +127 -16
- package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +82 -9
- package/dist_watch/bundle.js +211 -38
- package/dist_watch/bundle.js.map +3 -3
- package/package.json +1 -1
- package/readme.md +3 -1
- package/ts_web/00_commitinfo_data.ts +1 -1
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +132 -19
- package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +69 -7
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@design.estate/dees-catalog",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.93.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.",
|
|
6
6
|
"main": "dist_ts_web/index.js",
|
package/readme.md
CHANGED
|
@@ -1721,7 +1721,9 @@ chat.applyDelta({ type: 'text', messageId: 'm1', delta: 'chunk' });
|
|
|
1721
1721
|
chat.applyDelta({ type: 'message-end', messageId: 'm1', usage: { totalTokens: 1200 } });
|
|
1722
1722
|
```
|
|
1723
1723
|
|
|
1724
|
-
Key props: `messages`, `permissions`, `status`, `usage`, `heading`, `subheading`, `showToolbar`, `busy`, `queuedCount`, `disabled`, `model`/`modelOptions`, `reasoningEffort`/`effortOptions`, `toolRegistry`.
|
|
1724
|
+
Key props: `messages`, `permissions`, `status`, `usage`, `todos`/`showTodosPanel`, `heading`, `subheading`, `showToolbar`, `busy`, `queuedCount`, `disabled`, `model`/`modelOptions`, `reasoningEffort`/`effortOptions`, `toolRegistry`.
|
|
1725
|
+
|
|
1726
|
+
A **Tasks side panel** (OpenCode-style) shows the current todo list next to the transcript: set `.todos` explicitly, or leave it empty and the chat derives it from the newest todo tool call in `messages`. The panel hides itself in narrow containers (< 520px) where the transcript's todo cards carry the same information; `showTodosPanel={false}` disables it entirely. Methods: `applyDelta()`, `focusComposer()`, `clearComposer()`, `scrollToBottom()`. Events (also from children, all composed): `harness-send`, `harness-steer`, `harness-abort`, `harness-input`, `harness-attachments-change`, `harness-attachment-error`, `harness-model-change`, `harness-permission-response`, `harness-new-session`, `harness-open-sessions`.
|
|
1725
1727
|
|
|
1726
1728
|
#### `DeesHarnessMessageList`
|
|
1727
1729
|
|
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export const commitinfo = {
|
|
5
5
|
name: '@design.estate/dees-catalog',
|
|
6
|
-
version: '3.
|
|
6
|
+
version: '3.93.0',
|
|
7
7
|
description: 'A comprehensive library that provides dynamic web components for building sophisticated and modern web applications using JavaScript and TypeScript.'
|
|
8
8
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { html } from '@design.estate/dees-element';
|
|
2
2
|
import type { DeesHarnessChat } from './dees-harness-chat.js';
|
|
3
3
|
import type { IHarnessMessage, IHarnessPermissionRequest } from '../interfaces.js';
|
|
4
|
-
import { harnessDemoConversation
|
|
4
|
+
import { harnessDemoConversation } from '../harness.demodata.js';
|
|
5
5
|
|
|
6
6
|
const toolShowcase = (): IHarnessMessage[] => {
|
|
7
7
|
const now = Date.now();
|
|
@@ -84,30 +84,143 @@ let stopStream: (() => void) | undefined;
|
|
|
84
84
|
const chatOf = (event: MouseEvent): DeesHarnessChat | null =>
|
|
85
85
|
(event.target as HTMLElement).closest('.chatDemo')?.querySelector('dees-harness-chat') ?? null;
|
|
86
86
|
|
|
87
|
+
/**
|
|
88
|
+
* Streams a realistic turn: reasoning, a todo write, a test run, a file
|
|
89
|
+
* edit rendered as a diff, then the streamed summary text.
|
|
90
|
+
*/
|
|
87
91
|
const simulate = (event: MouseEvent) => {
|
|
88
92
|
const chat = chatOf(event);
|
|
89
93
|
if (!chat) return;
|
|
90
94
|
stopStream?.();
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
streaming: true,
|
|
95
|
+
const runId = Date.now();
|
|
96
|
+
const cancels: Array<() => void> = [];
|
|
97
|
+
const at = (ms: number, action: () => void) => {
|
|
98
|
+
const timeout = setTimeout(action, ms);
|
|
99
|
+
cancels.push(() => clearTimeout(timeout));
|
|
97
100
|
};
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
101
|
+
stopStream = () => {
|
|
102
|
+
for (const cancel of cancels) cancel();
|
|
103
|
+
chat.status = { type: 'idle' };
|
|
104
|
+
};
|
|
105
|
+
const pushMessage = (message: IHarnessMessage) => {
|
|
106
|
+
chat.messages = [...chat.messages, message];
|
|
107
|
+
};
|
|
108
|
+
const updateTool = (messageId: string, tool: Partial<IHarnessMessage['toolCall']> & { id: string }) => {
|
|
109
|
+
chat.applyDelta({ type: 'tool-update', messageId, tool: tool as never });
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
chat.status = { type: 'busy', message: 'Planning…' };
|
|
113
|
+
|
|
114
|
+
// 1) reasoning streams first
|
|
115
|
+
const reasoningMessage: IHarnessMessage = {
|
|
116
|
+
id: `sim-${runId}-reasoning`, role: 'assistant', text: '', createdAt: Date.now(), streaming: true,
|
|
117
|
+
};
|
|
118
|
+
pushMessage(reasoningMessage);
|
|
119
|
+
chat.applyDelta({ type: 'reasoning-start', messageId: reasoningMessage.id, partId: 'r1', startedAt: Date.now() });
|
|
120
|
+
const reasoningText = 'The cache key includes the locale list, so every rollout re-crawls. Plan: track the fix as todos, run the tests, then pin the key to the route manifest.';
|
|
121
|
+
reasoningText.split(' ').forEach((word, index) => {
|
|
122
|
+
at(80 + index * 45, () => chat.applyDelta({ type: 'reasoning', messageId: reasoningMessage.id, partId: 'r1', delta: word + ' ' }));
|
|
123
|
+
});
|
|
124
|
+
const reasoningDoneAt = 80 + reasoningText.split(' ').length * 45 + 150;
|
|
125
|
+
at(reasoningDoneAt, () => {
|
|
126
|
+
chat.applyDelta({ type: 'reasoning-end', messageId: reasoningMessage.id, partId: 'r1', endedAt: Date.now() });
|
|
127
|
+
chat.applyDelta({ type: 'message-end', messageId: reasoningMessage.id });
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
// 2) todo write
|
|
131
|
+
const todoId = `sim-${runId}-todos`;
|
|
132
|
+
at(reasoningDoneAt + 300, () => {
|
|
133
|
+
chat.status = { type: 'busy', message: 'Updating task list…' };
|
|
134
|
+
pushMessage({
|
|
135
|
+
id: todoId, role: 'tool', text: '', createdAt: Date.now(),
|
|
136
|
+
toolCall: {
|
|
137
|
+
id: `${todoId}-call`, name: 'todowrite', status: 'running',
|
|
138
|
+
input: { todos: [
|
|
139
|
+
{ content: 'Pin sitemap cache key to route manifest hash', status: 'in_progress' },
|
|
140
|
+
{ content: 'Run the sitemap test suite', status: 'pending' },
|
|
141
|
+
{ content: 'Apply the cache-key patch', status: 'pending' },
|
|
142
|
+
{ content: 'Verify staging timings', status: 'pending' },
|
|
143
|
+
] },
|
|
144
|
+
startedAt: Date.now(),
|
|
107
145
|
},
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
at(reasoningDoneAt + 1000, () => updateTool(todoId, { id: `${todoId}-call`, status: 'completed', finishedAt: Date.now() }));
|
|
149
|
+
|
|
150
|
+
// 3) test run
|
|
151
|
+
const testId = `sim-${runId}-test`;
|
|
152
|
+
at(reasoningDoneAt + 1400, () => {
|
|
153
|
+
chat.status = { type: 'busy', message: 'Running tests…' };
|
|
154
|
+
pushMessage({
|
|
155
|
+
id: testId, role: 'tool', text: '', createdAt: Date.now(),
|
|
156
|
+
toolCall: {
|
|
157
|
+
id: `${testId}-call`, name: 'run_command', status: 'running',
|
|
158
|
+
input: { command: 'pnpm test --filter sitemap', cwd: '/srv/app' },
|
|
159
|
+
startedAt: Date.now(),
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
at(reasoningDoneAt + 3200, () => updateTool(testId, {
|
|
164
|
+
id: `${testId}-call`, status: 'completed',
|
|
165
|
+
output: { exitCode: 0, stdout: '14 tests passed\n0 failed' },
|
|
166
|
+
finishedAt: Date.now(),
|
|
167
|
+
}));
|
|
168
|
+
|
|
169
|
+
// 4) file edit rendered as a diff
|
|
170
|
+
const editId = `sim-${runId}-edit`;
|
|
171
|
+
at(reasoningDoneAt + 3600, () => {
|
|
172
|
+
chat.status = { type: 'busy', message: 'Applying the patch…' };
|
|
173
|
+
pushMessage({
|
|
174
|
+
id: editId, role: 'tool', text: '', createdAt: Date.now(),
|
|
175
|
+
toolCall: {
|
|
176
|
+
id: `${editId}-call`, name: 'write_file', status: 'running',
|
|
177
|
+
input: {
|
|
178
|
+
path: '/srv/app/src/jobs/sitemap.job.ts',
|
|
179
|
+
oldContent: 'const cacheKey = hash(locales);\nconst ttl = 3600;',
|
|
180
|
+
content: 'const cacheKey = hash(routeManifest);\nconst ttl = 3600;',
|
|
181
|
+
},
|
|
182
|
+
startedAt: Date.now(),
|
|
183
|
+
},
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
at(reasoningDoneAt + 4600, () => updateTool(editId, { id: `${editId}-call`, status: 'completed', finishedAt: Date.now() }));
|
|
187
|
+
|
|
188
|
+
// 5) updated todos, then the streamed summary
|
|
189
|
+
const todoDoneId = `sim-${runId}-todos-2`;
|
|
190
|
+
at(reasoningDoneAt + 5000, () => {
|
|
191
|
+
pushMessage({
|
|
192
|
+
id: todoDoneId, role: 'tool', text: '', createdAt: Date.now(),
|
|
193
|
+
toolCall: {
|
|
194
|
+
id: `${todoDoneId}-call`, name: 'todowrite', status: 'completed',
|
|
195
|
+
input: { todos: [
|
|
196
|
+
{ content: 'Pin sitemap cache key to route manifest hash', status: 'completed' },
|
|
197
|
+
{ content: 'Run the sitemap test suite', status: 'completed' },
|
|
198
|
+
{ content: 'Apply the cache-key patch', status: 'completed' },
|
|
199
|
+
{ content: 'Verify staging timings', status: 'in_progress' },
|
|
200
|
+
] },
|
|
201
|
+
startedAt: Date.now(), finishedAt: Date.now(),
|
|
202
|
+
},
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
const summaryId = `sim-${runId}-summary`;
|
|
206
|
+
at(reasoningDoneAt + 5400, () => {
|
|
207
|
+
chat.status = { type: 'busy', message: 'Responding…' };
|
|
208
|
+
pushMessage({ id: summaryId, role: 'assistant', text: '', createdAt: Date.now(), streaming: true });
|
|
209
|
+
const summary = 'Patched `sitemap.job.ts` to key the cache on the **route manifest hash** — tests pass (14/14). Staging verification is the last open task.';
|
|
210
|
+
let offset = 0;
|
|
211
|
+
const interval = setInterval(() => {
|
|
212
|
+
const chunk = summary.slice(offset, offset + 6);
|
|
213
|
+
offset += 6;
|
|
214
|
+
if (!chunk) {
|
|
215
|
+
clearInterval(interval);
|
|
216
|
+
chat.applyDelta({ type: 'message-end', messageId: summaryId, usage: { inputTokens: 2100, outputTokens: 260, totalTokens: 2360 } });
|
|
217
|
+
chat.status = { type: 'idle' };
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
chat.applyDelta({ type: 'text', messageId: summaryId, delta: chunk });
|
|
221
|
+
}, 40);
|
|
222
|
+
cancels.push(() => clearInterval(interval));
|
|
223
|
+
});
|
|
111
224
|
};
|
|
112
225
|
|
|
113
226
|
const askPermission = (event: MouseEvent) => {
|
|
@@ -14,14 +14,17 @@ import type {
|
|
|
14
14
|
IHarnessMessage,
|
|
15
15
|
IHarnessPermissionRequest,
|
|
16
16
|
IHarnessStatus,
|
|
17
|
+
IHarnessTodoItem,
|
|
17
18
|
IHarnessUsage,
|
|
18
19
|
THarnessStreamDelta,
|
|
19
20
|
} from '../interfaces.js';
|
|
21
|
+
import { harnessParseTodos } from '../harness.helpers.js';
|
|
20
22
|
import { DeesHarnessToolRegistry } from '../toolregistry.js';
|
|
21
23
|
import { DeesHarnessMessageList } from '../dees-harness-message-list/dees-harness-message-list.js';
|
|
22
24
|
import { DeesHarnessComposer } from '../dees-harness-composer/dees-harness-composer.js';
|
|
23
25
|
import '../dees-harness-permission-card/dees-harness-permission-card.js';
|
|
24
26
|
import '../dees-harness-status/dees-harness-status.js';
|
|
27
|
+
import '../dees-harness-todos/dees-harness-todos.js';
|
|
25
28
|
import '../dees-harness-usage/dees-harness-usage.js';
|
|
26
29
|
import '../../00group-button/dees-button/dees-button.js';
|
|
27
30
|
import '../../00group-utility/dees-icon/dees-icon.js';
|
|
@@ -61,6 +64,17 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
61
64
|
@property({ attribute: false })
|
|
62
65
|
accessor usage: IHarnessUsage = {};
|
|
63
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Current task list for the side panel. When empty, the panel derives it
|
|
69
|
+
* from the newest todo tool call in `messages` (registry kind 'todo'), so
|
|
70
|
+
* hosts that stream todowrite calls get the sidebar for free.
|
|
71
|
+
*/
|
|
72
|
+
@property({ attribute: false })
|
|
73
|
+
accessor todos: IHarnessTodoItem[] = [];
|
|
74
|
+
|
|
75
|
+
@property({ type: Boolean })
|
|
76
|
+
accessor showTodosPanel: boolean = true;
|
|
77
|
+
|
|
64
78
|
@property()
|
|
65
79
|
accessor heading: string = '';
|
|
66
80
|
|
|
@@ -116,6 +130,32 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
116
130
|
font-family: var(--dees-font-family);
|
|
117
131
|
color: var(--dees-color-text-primary);
|
|
118
132
|
background: var(--dees-color-bg-primary);
|
|
133
|
+
container-type: inline-size;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.chatBody {
|
|
137
|
+
flex: 1;
|
|
138
|
+
min-height: 0;
|
|
139
|
+
display: flex;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.todosPanel {
|
|
143
|
+
flex: 0 0 232px;
|
|
144
|
+
min-width: 0;
|
|
145
|
+
overflow-y: auto;
|
|
146
|
+
scrollbar-width: thin;
|
|
147
|
+
scrollbar-color: var(--dees-color-scrollbar-thumb) transparent;
|
|
148
|
+
padding: var(--dees-spacing-sm) var(--dees-spacing-md);
|
|
149
|
+
border-left: 1px solid var(--dees-color-border-subtle);
|
|
150
|
+
background: var(--dees-color-bg-secondary);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/* narrow hosts (e.g. a sidebar chat) drop the panel; todo tool cards
|
|
154
|
+
in the transcript still carry the same information */
|
|
155
|
+
@container (max-width: 520px) {
|
|
156
|
+
.todosPanel {
|
|
157
|
+
display: none;
|
|
158
|
+
}
|
|
119
159
|
}
|
|
120
160
|
|
|
121
161
|
.toolbar {
|
|
@@ -158,7 +198,7 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
158
198
|
flex: 0 0 auto;
|
|
159
199
|
}
|
|
160
200
|
|
|
161
|
-
dees-harness-message-list {
|
|
201
|
+
.chatBody dees-harness-message-list {
|
|
162
202
|
flex: 1;
|
|
163
203
|
min-height: 0;
|
|
164
204
|
}
|
|
@@ -214,6 +254,19 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
214
254
|
this.listElement?.scrollToBottom(force);
|
|
215
255
|
}
|
|
216
256
|
|
|
257
|
+
public get effectiveTodos(): IHarnessTodoItem[] {
|
|
258
|
+
if (this.todos.length) return this.todos;
|
|
259
|
+
// the newest todo call is the current state — an empty write clears
|
|
260
|
+
// the panel instead of falling back to an older list
|
|
261
|
+
for (let index = this.messages.length - 1; index >= 0; index--) {
|
|
262
|
+
const call = this.messages[index]?.toolCall;
|
|
263
|
+
if (!call) continue;
|
|
264
|
+
if (this.toolRegistry.resolve(call).kind !== 'todo') continue;
|
|
265
|
+
return harnessParseTodos(call.input);
|
|
266
|
+
}
|
|
267
|
+
return [];
|
|
268
|
+
}
|
|
269
|
+
|
|
217
270
|
private get listElement(): DeesHarnessMessageList | undefined {
|
|
218
271
|
const element = this.shadowRoot?.querySelector('dees-harness-message-list');
|
|
219
272
|
return element instanceof DeesHarnessMessageList ? element : undefined;
|
|
@@ -229,12 +282,21 @@ export class DeesHarnessChat extends DeesElement {
|
|
|
229
282
|
public render(): TemplateResult {
|
|
230
283
|
return html`
|
|
231
284
|
${this.showToolbar ? this.renderToolbar() : ''}
|
|
232
|
-
<
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
285
|
+
<div class="chatBody">
|
|
286
|
+
<dees-harness-message-list
|
|
287
|
+
.messages=${this.messages}
|
|
288
|
+
.status=${idleStatus}
|
|
289
|
+
.showRoles=${this.showRoles}
|
|
290
|
+
.toolRegistry=${this.toolRegistry}
|
|
291
|
+
></dees-harness-message-list>
|
|
292
|
+
${this.showTodosPanel && this.effectiveTodos.length
|
|
293
|
+
? html`
|
|
294
|
+
<aside class="todosPanel">
|
|
295
|
+
<dees-harness-todos heading="Tasks" .todos=${this.effectiveTodos}></dees-harness-todos>
|
|
296
|
+
</aside>
|
|
297
|
+
`
|
|
298
|
+
: ''}
|
|
299
|
+
</div>
|
|
238
300
|
${this.permissions.length
|
|
239
301
|
? html`
|
|
240
302
|
<div class="permissionQueue">
|