@design.estate/dees-catalog 4.12.0 → 6.0.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.
Files changed (37) hide show
  1. package/dist_bundle/bundle.js +2719 -1261
  2. package/dist_ts_web/00_commitinfo_data.js +2 -2
  3. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.d.ts +23 -4
  4. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.js +290 -78
  5. package/dist_ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.js +419 -42
  6. package/dist_ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.js +44 -3
  7. package/dist_ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.js +5 -7
  8. package/dist_ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.js +5 -2
  9. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.d.ts +54 -0
  10. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.demo.d.ts +1 -0
  11. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.demo.js +56 -0
  12. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.js +870 -0
  13. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/index.d.ts +1 -0
  14. package/dist_ts_web/elements/00group-harness/dees-harness-session-sidebar/index.js +2 -0
  15. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.d.ts +5 -0
  16. package/dist_ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.js +87 -3
  17. package/dist_ts_web/elements/00group-harness/harness.markdown.js +3 -1
  18. package/dist_ts_web/elements/00group-harness/harness.styles.js +48 -1
  19. package/dist_ts_web/elements/00group-harness/index.d.ts +1 -0
  20. package/dist_ts_web/elements/00group-harness/index.js +2 -1
  21. package/dist_ts_web/elements/00group-harness/interfaces.d.ts +41 -0
  22. package/package.json +1 -1
  23. package/readme.md +13 -5
  24. package/ts_web/00_commitinfo_data.ts +1 -1
  25. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.demo.ts +277 -79
  26. package/ts_web/elements/00group-harness/dees-harness-chat/dees-harness-chat.ts +367 -36
  27. package/ts_web/elements/00group-harness/dees-harness-message/dees-harness-message.ts +43 -2
  28. package/ts_web/elements/00group-harness/dees-harness-reasoning/dees-harness-reasoning.ts +4 -6
  29. package/ts_web/elements/00group-harness/dees-harness-session-list/dees-harness-session-list.ts +4 -1
  30. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.demo.ts +67 -0
  31. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/dees-harness-session-sidebar.ts +802 -0
  32. package/ts_web/elements/00group-harness/dees-harness-session-sidebar/index.ts +1 -0
  33. package/ts_web/elements/00group-harness/dees-harness-tool-card/dees-harness-tool-card.ts +79 -1
  34. package/ts_web/elements/00group-harness/harness.markdown.ts +2 -0
  35. package/ts_web/elements/00group-harness/harness.styles.ts +47 -0
  36. package/ts_web/elements/00group-harness/index.ts +1 -0
  37. package/ts_web/elements/00group-harness/interfaces.ts +48 -0
@@ -1,6 +1,6 @@
1
1
  import { html } from '@design.estate/dees-element';
2
2
  import type { DeesHarnessChat } from './dees-harness-chat.js';
3
- import type { IHarnessMessage, IHarnessPermissionRequest } from '../interfaces.js';
3
+ import type { IHarnessMessage, IHarnessPermissionRequest, IHarnessToolCall } from '../interfaces.js';
4
4
  import { harnessDemoConversation } from '../harness.demodata.js';
5
5
 
6
6
  const toolShowcase = (): IHarnessMessage[] => {
@@ -85,53 +85,167 @@ const chatOf = (event: MouseEvent): DeesHarnessChat | null =>
85
85
  (event.target as HTMLElement).closest('.chatDemo')?.querySelector('dees-harness-chat') ?? null;
86
86
 
87
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.
88
+ * Streams a realistic turn through planning, inspection, a failing test,
89
+ * the file edit, verification, and the final assistant summary.
90
90
  */
91
91
  const simulate = (event: MouseEvent) => {
92
92
  const chat = chatOf(event);
93
93
  if (!chat) return;
94
94
  stopStream?.();
95
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));
100
- };
101
- stopStream = () => {
102
- for (const cancel of cancels) cancel();
103
- chat.status = { type: 'idle' };
96
+ let stopped = false;
97
+ const pendingDelays = new Map<ReturnType<typeof setTimeout>, (continueRun: boolean) => void>();
98
+ const activeMessages = new Set<string>();
99
+ const activeTools = new Set<string>();
100
+ const activeReasoning = new Map<string, Set<string>>();
101
+
102
+ const wait = async (milliseconds: number): Promise<boolean> => new Promise((resolve) => {
103
+ if (stopped) {
104
+ resolve(false);
105
+ return;
106
+ }
107
+ const timeout = setTimeout(() => {
108
+ pendingDelays.delete(timeout);
109
+ resolve(!stopped);
110
+ }, milliseconds);
111
+ pendingDelays.set(timeout, resolve);
112
+ });
113
+ const waitForMessageList = async (): Promise<void> => {
114
+ await chat.updateComplete;
115
+ const list = chat.shadowRoot?.querySelector('dees-harness-message-list') as (
116
+ HTMLElement & { updateComplete: Promise<unknown> }
117
+ ) | null;
118
+ if (list) await list.updateComplete;
104
119
  };
105
- const pushMessage = (message: IHarnessMessage) => {
120
+ const pushMessage = async (message: IHarnessMessage): Promise<boolean> => {
106
121
  chat.messages = [...chat.messages, message];
122
+ if (message.streaming) activeMessages.add(message.id);
123
+ if (message.toolCall?.status === 'pending' || message.toolCall?.status === 'running') {
124
+ activeTools.add(message.id);
125
+ }
126
+ await waitForMessageList();
127
+ if (!stopped) return true;
128
+ if (message.streaming) {
129
+ message.streaming = false;
130
+ message.error ??= 'Simulation stopped.';
131
+ }
132
+ if (message.toolCall?.status === 'pending' || message.toolCall?.status === 'running') {
133
+ message.toolCall.status = 'error';
134
+ message.toolCall.errorText = 'Simulation stopped.';
135
+ message.toolCall.finishedAt = Date.now();
136
+ }
137
+ chat.messages = [...chat.messages];
138
+ return false;
107
139
  };
108
- const updateTool = (messageId: string, tool: Partial<IHarnessMessage['toolCall']> & { id: string }) => {
109
- chat.applyDelta({ type: 'tool-update', messageId, tool: tool as never });
140
+ const updateTool = (messageId: string, tool: Partial<IHarnessToolCall> & { id: string }) => {
141
+ chat.applyDelta({ type: 'tool-update', messageId, tool });
142
+ if (tool.status === 'completed' || tool.status === 'error') activeTools.delete(messageId);
143
+ };
144
+ const startReasoning = (messageId: string, partId: string): void => {
145
+ chat.applyDelta({ type: 'reasoning-start', messageId, partId, startedAt: Date.now() });
146
+ const parts = activeReasoning.get(messageId) ?? new Set<string>();
147
+ parts.add(partId);
148
+ activeReasoning.set(messageId, parts);
149
+ };
150
+ const endReasoning = (messageId: string, partId: string): void => {
151
+ chat.applyDelta({ type: 'reasoning-end', messageId, partId, endedAt: Date.now() });
152
+ const parts = activeReasoning.get(messageId);
153
+ parts?.delete(partId);
154
+ if (!parts?.size) activeReasoning.delete(messageId);
155
+ };
156
+ const finishMessage = (
157
+ messageId: string,
158
+ options: { usage?: IHarnessMessage['usage']; error?: string } = {},
159
+ ): void => {
160
+ chat.applyDelta({
161
+ type: 'message-end',
162
+ messageId,
163
+ usage: options.usage,
164
+ error: options.error,
165
+ });
166
+ activeMessages.delete(messageId);
167
+ };
168
+ const streamWords = async (
169
+ messageId: string,
170
+ partId: string,
171
+ text: string,
172
+ ): Promise<boolean> => {
173
+ for (const word of text.split(' ')) {
174
+ if (!await wait(38)) return false;
175
+ chat.applyDelta({ type: 'reasoning', messageId, partId, delta: `${word} ` });
176
+ }
177
+ return true;
178
+ };
179
+ const streamText = async (messageId: string, text: string): Promise<boolean> => {
180
+ for (let offset = 0; offset < text.length; offset += 8) {
181
+ if (!await wait(32)) return false;
182
+ chat.applyDelta({ type: 'text', messageId, delta: text.slice(offset, offset + 8) });
183
+ }
184
+ return true;
110
185
  };
111
186
 
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,
187
+ const stop = (): void => {
188
+ if (stopped) return;
189
+ stopped = true;
190
+ for (const [timeout, resolve] of pendingDelays) {
191
+ clearTimeout(timeout);
192
+ resolve(false);
193
+ }
194
+ pendingDelays.clear();
195
+ for (const [messageId, parts] of [...activeReasoning]) {
196
+ for (const partId of [...parts]) endReasoning(messageId, partId);
197
+ }
198
+ for (const messageId of [...activeMessages]) {
199
+ finishMessage(messageId, { error: 'Simulation stopped.' });
200
+ }
201
+ for (const messageId of [...activeTools]) {
202
+ const message = chat.messages.find((candidate) => candidate.id === messageId);
203
+ if (!message?.toolCall) continue;
204
+ updateTool(messageId, {
205
+ id: message.toolCall.id,
206
+ status: 'error',
207
+ errorText: 'Simulation stopped.',
208
+ finishedAt: Date.now(),
209
+ });
210
+ }
211
+ chat.status = { type: 'idle' };
212
+ if (stopStream === stop) stopStream = undefined;
117
213
  };
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
- });
214
+ stopStream = stop;
215
+
216
+ const run = async (): Promise<void> => {
217
+ chat.status = { type: 'busy', message: 'Planning…' };
218
+ const reasoningId = `sim-${runId}-reasoning`;
219
+ if (!await pushMessage({
220
+ id: reasoningId,
221
+ role: 'assistant',
222
+ text: '',
223
+ createdAt: Date.now(),
224
+ streaming: true,
225
+ model: 'gpt-5.5',
226
+ effort: 'high',
227
+ })) return;
228
+ startReasoning(reasoningId, 'analysis');
229
+ if (!await streamWords(
230
+ reasoningId,
231
+ 'analysis',
232
+ 'The locale list participates in the cache key, so a rollout invalidates every route even when the manifest is unchanged.',
233
+ )) return;
234
+ endReasoning(reasoningId, 'analysis');
235
+ if (!await wait(160)) return;
236
+ startReasoning(reasoningId, 'plan');
237
+ if (!await streamWords(
238
+ reasoningId,
239
+ 'plan',
240
+ 'I will inspect the job, pin the key to the route manifest, run the focused regression test, and update the task list.',
241
+ )) return;
242
+ endReasoning(reasoningId, 'plan');
243
+ finishMessage(reasoningId);
129
244
 
130
- // 2) todo write
131
- const todoId = `sim-${runId}-todos`;
132
- at(reasoningDoneAt + 300, () => {
245
+ if (!await wait(260)) return;
133
246
  chat.status = { type: 'busy', message: 'Updating task list…' };
134
- pushMessage({
247
+ const todoId = `sim-${runId}-todos`;
248
+ if (!await pushMessage({
135
249
  id: todoId, role: 'tool', text: '', createdAt: Date.now(),
136
250
  toolCall: {
137
251
  id: `${todoId}-call`, name: 'todowrite', status: 'running',
@@ -143,34 +257,58 @@ const simulate = (event: MouseEvent) => {
143
257
  ] },
144
258
  startedAt: Date.now(),
145
259
  },
260
+ })) return;
261
+ if (!await wait(520)) return;
262
+ updateTool(todoId, { id: `${todoId}-call`, status: 'completed', finishedAt: Date.now() });
263
+
264
+ if (!await wait(240)) return;
265
+ chat.status = { type: 'busy', message: 'Inspecting the sitemap job…' };
266
+ const readId = `sim-${runId}-read`;
267
+ if (!await pushMessage({
268
+ id: readId, role: 'tool', text: '', createdAt: Date.now(),
269
+ toolCall: {
270
+ id: `${readId}-call`, name: 'read_file', status: 'running',
271
+ input: { path: '/srv/app/src/jobs/sitemap.job.ts', startLine: 1, endLine: 80 },
272
+ startedAt: Date.now(),
273
+ },
274
+ })) return;
275
+ if (!await wait(620)) return;
276
+ updateTool(readId, {
277
+ id: `${readId}-call`,
278
+ status: 'completed',
279
+ output: 'const cacheKey = hash(locales);\nconst ttl = 3600;\nawait cache.set(cacheKey, sitemap, ttl);',
280
+ finishedAt: Date.now(),
146
281
  });
147
- });
148
- at(reasoningDoneAt + 1000, () => updateTool(todoId, { id: `${todoId}-call`, status: 'completed', finishedAt: Date.now() }));
149
282
 
150
- // 3) test run
151
- const testId = `sim-${runId}-test`;
152
- at(reasoningDoneAt + 1400, () => {
153
- chat.status = { type: 'busy', message: 'Running tests…' };
154
- pushMessage({
283
+ if (!await wait(240)) return;
284
+ chat.status = { type: 'busy', message: 'Running the regression test…' };
285
+ const testId = `sim-${runId}-test`;
286
+ if (!await pushMessage({
155
287
  id: testId, role: 'tool', text: '', createdAt: Date.now(),
156
288
  toolCall: {
157
289
  id: `${testId}-call`, name: 'run_command', status: 'running',
158
290
  input: { command: 'pnpm test --filter sitemap', cwd: '/srv/app' },
159
291
  startedAt: Date.now(),
160
292
  },
293
+ })) return;
294
+ if (!await wait(520)) return;
295
+ updateTool(testId, {
296
+ id: `${testId}-call`,
297
+ status: 'running',
298
+ output: { stdout: '13 tests passed\n1 test still running…' },
299
+ });
300
+ if (!await wait(620)) return;
301
+ updateTool(testId, {
302
+ id: `${testId}-call`, status: 'error', isError: true,
303
+ output: { exitCode: 1, stdout: '13 tests passed', stderr: 'cache key changed after locale reorder' },
304
+ errorText: 'Regression confirmed before applying the patch.',
305
+ finishedAt: Date.now(),
161
306
  });
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
307
 
169
- // 4) file edit rendered as a diff
170
- const editId = `sim-${runId}-edit`;
171
- at(reasoningDoneAt + 3600, () => {
308
+ if (!await wait(260)) return;
172
309
  chat.status = { type: 'busy', message: 'Applying the patch…' };
173
- pushMessage({
310
+ const editId = `sim-${runId}-edit`;
311
+ if (!await pushMessage({
174
312
  id: editId, role: 'tool', text: '', createdAt: Date.now(),
175
313
  toolCall: {
176
314
  id: `${editId}-call`, name: 'write_file', status: 'running',
@@ -181,14 +319,31 @@ const simulate = (event: MouseEvent) => {
181
319
  },
182
320
  startedAt: Date.now(),
183
321
  },
322
+ })) return;
323
+ if (!await wait(720)) return;
324
+ updateTool(editId, { id: `${editId}-call`, status: 'completed', finishedAt: Date.now() });
325
+
326
+ if (!await wait(240)) return;
327
+ chat.status = { type: 'busy', message: 'Verifying the patch…' };
328
+ const verifyId = `sim-${runId}-verify`;
329
+ if (!await pushMessage({
330
+ id: verifyId, role: 'tool', text: '', createdAt: Date.now(),
331
+ toolCall: {
332
+ id: `${verifyId}-call`, name: 'run_command', status: 'running',
333
+ input: { command: 'pnpm test --filter sitemap', cwd: '/srv/app' },
334
+ startedAt: Date.now(),
335
+ },
336
+ })) return;
337
+ if (!await wait(760)) return;
338
+ updateTool(verifyId, {
339
+ id: `${verifyId}-call`, status: 'completed',
340
+ output: { exitCode: 0, stdout: '14 tests passed\n0 failed' },
341
+ finishedAt: Date.now(),
184
342
  });
185
- });
186
- at(reasoningDoneAt + 4600, () => updateTool(editId, { id: `${editId}-call`, status: 'completed', finishedAt: Date.now() }));
187
343
 
188
- // 5) updated todos, then the streamed summary
189
- const todoDoneId = `sim-${runId}-todos-2`;
190
- at(reasoningDoneAt + 5000, () => {
191
- pushMessage({
344
+ if (!await wait(220)) return;
345
+ const todoDoneId = `sim-${runId}-todos-2`;
346
+ if (!await pushMessage({
192
347
  id: todoDoneId, role: 'tool', text: '', createdAt: Date.now(),
193
348
  toolCall: {
194
349
  id: `${todoDoneId}-call`, name: 'todowrite', status: 'completed',
@@ -196,30 +351,47 @@ const simulate = (event: MouseEvent) => {
196
351
  { content: 'Pin sitemap cache key to route manifest hash', status: 'completed' },
197
352
  { content: 'Run the sitemap test suite', status: 'completed' },
198
353
  { content: 'Apply the cache-key patch', status: 'completed' },
199
- { content: 'Verify staging timings', status: 'in_progress' },
354
+ { content: 'Verify staging timings', status: 'completed' },
200
355
  ] },
201
356
  startedAt: Date.now(), finishedAt: Date.now(),
202
357
  },
203
- });
204
- });
205
- const summaryId = `sim-${runId}-summary`;
206
- at(reasoningDoneAt + 5400, () => {
358
+ })) return;
359
+
360
+ if (!await wait(260)) return;
207
361
  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));
362
+ const summaryId = `sim-${runId}-summary`;
363
+ if (!await pushMessage({
364
+ id: summaryId,
365
+ role: 'assistant',
366
+ text: '',
367
+ createdAt: Date.now(),
368
+ streaming: true,
369
+ model: 'gpt-5.5',
370
+ effort: 'high',
371
+ })) return;
372
+ const summary = [
373
+ 'Patched `sitemap.job.ts` so the cache is keyed by the **route manifest hash** instead of locale ordering.',
374
+ '',
375
+ '### Verification',
376
+ '',
377
+ '- Confirmed the regression before the edit',
378
+ '- Applied the one-line cache-key change',
379
+ '- Re-ran the focused suite: **14/14 tests passed**',
380
+ '- Completed the staging timing check',
381
+ '',
382
+ 'Locale-only rollouts now reuse the existing sitemap cache.',
383
+ ].join('\n');
384
+ if (!await streamText(summaryId, summary)) return;
385
+ finishMessage(summaryId, {
386
+ usage: { inputTokens: 2480, outputTokens: 340, totalTokens: 2820 },
387
+ });
388
+ chat.status = { type: 'idle' };
389
+ if (stopStream === stop) stopStream = undefined;
390
+ };
391
+
392
+ void run().catch((error) => {
393
+ console.error('Harness chat demo simulation failed.', error);
394
+ stop();
223
395
  });
224
396
  };
225
397
 
@@ -310,8 +482,10 @@ export const demoFunc = () => html`
310
482
  );
311
483
  }
312
484
  }}
313
- @harness-new-session=${() => console.log('harness-new-session')}
314
- @harness-open-sessions=${() => console.log('harness-open-sessions')}
485
+ @harness-scratchpad-save=${(event: CustomEvent) => console.log('harness-scratchpad-save', event.detail)}
486
+ @harness-session-intelligence-ask=${(event: CustomEvent) => {
487
+ console.log('harness-session-intelligence-ask', event.detail);
488
+ }}
315
489
  @harness-abort=${() => {
316
490
  stopStream?.();
317
491
  console.log('harness-abort');
@@ -334,6 +508,30 @@ export const demoFunc = () => html`
334
508
  .modelOptions=${['gpt-5.5', 'gpt-5', 'o4-mini']}
335
509
  .effortOptions=${['xhigh', 'high', 'medium', 'low']}
336
510
  .usage=${{ inputTokens: 18_400, outputTokens: 3_100, totalTokens: 21_500 }}
511
+ .sessionMetrics=${{
512
+ lifetimeUsedTokens: 184_320,
513
+ compactionCount: 2,
514
+ tokensBeforeLatestCompaction: 112_840,
515
+ currentContextTokens: 47_200,
516
+ maxContextTokens: 128_000,
517
+ }}
518
+ .scratchpad=${{
519
+ id: 'deploy-assistant-demo',
520
+ text: '- Cache keys use the route manifest hash.\n- Release after staging verification.',
521
+ revision: 4,
522
+ updatedAt: Date.now() - 45_000,
523
+ updatedBy: 'intelligence',
524
+ }}
525
+ .sessionIntelligenceEnabled=${true}
526
+ .intelligenceExchanges=${[{
527
+ id: 'intelligence-demo',
528
+ question: 'What remains before release?',
529
+ answer: 'Staging verification is the only remaining task.',
530
+ status: 'completed',
531
+ model: 'gpt-5.6-luna',
532
+ createdAt: Date.now() - 30_000,
533
+ completedAt: Date.now() - 28_000,
534
+ }]}
337
535
  .messages=${[...harnessDemoConversation(), ...toolShowcase()]}
338
536
  ></dees-harness-chat>
339
537
  </div>